Closed Bug 1287219 Opened 9 years ago Closed 9 years ago

swap with raw pointer local in nsFtpProtocolHandler::RemoveConnection()

Categories

(Core Graveyard :: Networking: FTP, defect)

defect
Not set
normal

Tracking

(firefox50 affected, firefox51 fixed)

RESOLVED FIXED
mozilla51
Tracking Status
firefox50 --- affected
firefox51 --- fixed

People

(Reporter: mccr8, Assigned: mayhemer)

Details

(Whiteboard: [necko-active])

Attachments

(1 file)

The end of the method does this: // swap connection ownership *_retval = ts->conn; ts->conn = nullptr; The type of ts->conn is RefPtr<>, while _retval is nsFtpControlConnection**. This copies out the pointer, but without addrefing the connection. Then the RefPtr<> is nulled out, which will destroy the connection if this is the last reference, but we still have a pointer to it. (Maybe there's always something else holding the connection alive?) I believe this is the result of a botched fix to a leak in bug 194402: https://github.com/mozilla/gecko-dev/commit/bfd31e83de3c4f88305a43f5006980b90601e6f9#diff-7954d49dd5596a143a51909f88f19127R287 In fact, I believe the real cause of that leak is in nsFtpState::EstablishControlConnection(): http://hg.mozilla.org/mozilla-central/file/tip/netwerk/protocol/ftp/nsFtpConnectionThread.cpp#l265 The code basically does this: nsFtpControlConnection *connection = nullptr; ... gFtpHandler->RemoveConnection(mChannel->URI(), &connection); ... mControlConnection.swap(connection); Because connection is not a RefPtr, the "swap" puts the new value from connection into mControlConnection, without addrefing it, which will eventually cause an extra Release() when it cleared. The old value of mControlConnection gets put into connection, and nothing happens to it, so we leak it. Found by code inspection.
Group: core-security → network-core-security
Doug, do you have any thoughts here? It would be nice to fix this, but I'm also wary of touching code that isn't well-tested.
Flags: needinfo?(dougt)
my policy is that we only take security fixes here. this looks tractable enough that we can do it safely. I would trust honza to work it out if he's willing..
Flags: needinfo?(dougt) → needinfo?(honzab.moz)
(In reply to Andrew McCreight [:mccr8] from comment #0) > The end of the method does this: > // swap connection ownership > *_retval = ts->conn; > ts->conn = nullptr; > > The type of ts->conn is RefPtr<>, It's not (up to date m-c): // Stuff for the timer callback function struct timerStruct { nsCOMPtr<nsITimer> timer; > nsFtpControlConnection *conn; char *key; timerStruct() : conn(nullptr), key(nullptr) {} ~timerStruct() { if (timer) timer->Cancel(); if (key) free(key); if (conn) { conn->Disconnect(NS_ERROR_ABORT); NS_RELEASE(conn); } } }; > while _retval is nsFtpControlConnection**. > This copies out the pointer, but without addrefing the connection. Then the > RefPtr<> is nulled out, which will destroy the connection if this is the > last reference, but we still have a pointer to it. (Maybe there's always > something else holding the connection alive?) > > I believe this is the result of a botched fix to a leak in bug 194402: > https://github.com/mozilla/gecko-dev/commit/ > bfd31e83de3c4f88305a43f5006980b90601e6f9#diff- > 7954d49dd5596a143a51909f88f19127R287 > > In fact, I believe the real cause of that leak is in > nsFtpState::EstablishControlConnection(): > http://hg.mozilla.org/mozilla-central/file/tip/netwerk/protocol/ftp/ > nsFtpConnectionThread.cpp#l265 > > The code basically does this: > nsFtpControlConnection *connection = nullptr; > ... > gFtpHandler->RemoveConnection(mChannel->URI(), &connection); > ... > mControlConnection.swap(connection); > > Because connection is not a RefPtr, the "swap" puts the new value from > connection into mControlConnection, without addrefing it, which will > eventually cause an extra Release() when it cleared. The old value of > mControlConnection gets put into connection, and nothing happens to it, so > we leak it. > > Found by code inspection. Has this all been reproduced or is this bug based only on your code inspection? This all sounds like we want to make sure everything is on RefPtrs. That's not a small task. But I can do it.
Assignee: nobody → honzab.moz
Flags: needinfo?(honzab.moz) → needinfo?(continuation)
I haven't really assessed this myself, but if this can be fixed up with a mutex that would probably be preferable to any kind of investment in the ftp code. Its definitely a low value thing. (unfortunately not low enough value to just toss it to an addon - though if we had a reasonable js addon to ship as a default system addon that would be attractive.. its just also a fairly sizable project that shouldn't be considered if this can be patched up)
> It's not (up to date m-c): Oh, that's good. I'm not sure why I thought it was a RefPtr. Therefore this isn't a security issue. Sorry for my mistake. > Has this all been reproduced or is this bug based only on your code inspection? Code inspection. The only remaining problem would be a leak from |connection|, but it looks like the invariant of this function is that mControlConnection is null, so if that holds, it would be okay. It would still be nice if |connection| could be changed to a RefPtr<>. That would be a small local change. I'm trying to get rid of all uses of |RefPtr::swap(T*& aRhs)| because things can go very badly with it if you aren't careful.
Group: network-core-security
Flags: needinfo?(continuation)
Summary: Use-after-free in nsFtpProtocolHandler::RemoveConnection() → swap with raw pointer local in nsFtpProtocolHandler::RemoveConnection()
this could be it.
Attachment #8773849 - Flags: review?(mcmanus)
Status: NEW → ASSIGNED
Whiteboard: [necko-active]
Comment on attachment 8773849 [details] [diff] [review] v1 (timerStruct::conn made a refptr, connection local made refptr) Review of attachment 8773849 [details] [diff] [review]: ----------------------------------------------------------------- I'm really tempted to WONTFIX any FTP changes at this point that aren't demonstrable problems simply on a risk/reward basis. But the total system benefit is probably worth it here..
Attachment #8773849 - Flags: review?(mcmanus) → review+
Keywords: checkin-needed
Pushed by cbook@mozilla.com: https://hg.mozilla.org/integration/mozilla-inbound/rev/ec891a342ef7 Fix leak of nsFtpControlConnection in nsFtpProtocolHandler::RemoveConnection, r=mcmanus
Keywords: checkin-needed
Status: ASSIGNED → RESOLVED
Closed: 9 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla51
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: