[tor-bugs] #18570 [Tor]: Fix memory handling in incoming cell queues

Tor Bug Tracker & Wiki blackhole at torproject.org
Thu Mar 17 16:47:59 UTC 2016


#18570: Fix memory handling in incoming cell queues
------------------------+--------------------------------
     Reporter:  andrea  |      Owner:
         Type:  defect  |     Status:  new
     Priority:  Medium  |  Milestone:  Tor: 0.2.8.x-final
    Component:  Tor     |    Version:  Tor: 0.2.8.1-alpha
     Severity:  Normal  |   Keywords:
Actual Points:          |  Parent ID:
       Points:          |   Reviewer:
      Sponsor:  None    |
------------------------+--------------------------------
 Per e-mail by David Goulet:

 {{{
 Hi little-t tor team!

 (Please add anyone in CC if I forgot anyone, my brain is kind of fried to
 I'm
 sure I'm forgetting someone...)

 (Also, this is closed CC list because could be security related if my
 analysis
 is wrong thus not good idea for tor-dev@ right now)

 (An idea, a little-t at torproject.org that could email every dev doing work
 on
 little-t tor code actively would be nice instead of having an epic CC
 chain :)

 I stumble upon this yesterday while working with Rob on the tor code. At
 first,
 it seems like a _bad_ security issue but turns out we are OK however there
 seems to be some collateral dammage.

 We start our code spelunking in connection_or.c (please correct me if I'm
 wrong
 as I go because this ain't a trivial subsystem so I might interpret things
 wrong).

 Function connection_or_process_cells_from_inbuf() basically takes the cell
 from
 the inbuf of the given OR connection and either handle them or queue them.
 Two
 types of cells here either a var_cell_t or cell_t. Please follow the
 cell_t in
 that function which is in the else statement of this if:

     if (connection_fetch_var_cell_from_buf(conn, &var_cell)) {
         ...
     } else {
         HERE
     }

 The issue we noticed is that "cell_t cell" is on the stack and a reference
 to
 it is passed to channel_tls_handle_cell(). This function can end up in
 channel_queue_cell(). Remember, at that point the cell pointer passed to
 that
 function is on the stack.

   /* Do we need to queue it, or can we just call the handler right away?
 */
   if (!(chan->cell_handler)) need_to_queue = 1;
   if (! TOR_SIMPLEQ_EMPTY(&chan->incoming_queue))
     need_to_queue = 1

 In other words:

     * if we do NOT have a cell_handler function for this channel, queue
 it.
     * if the incoming_queue of the channel is NOT empty, queue it.

 It all makes sense so far. The issue _could_ have arised if we queued the
 cell
 because we would ended up in cell_queue_entry_new_fixed() which stores the
 cell
 pointer which is BAD!!! because stack pointer thus potentially leaking
 stack
 bytes to the network and breaking lots of things in tor functionnalities
 :).

 However, after testing, I realized that we _never_ end up in that code
 path so
 why? Turns out that we never actually queue cell in the incoming_queue of
 the
 channel. Because 1) cell_handler of the channel seems always set and 2) we
 only
 insert a cell in the queue if the queue is not empty so how can we insert
 a
 cell in there if we only add it if it's not empty? (bootstrap issue :)

 Since I can't find any information on the reason for this code or "high
 level"
 view of it either in the commit message or mailing list (maybe my search
 is
 bad), here are some questions that I'm sure someone in CC can answer me
 :).

 1) What's the intended behavior here of "incoming_queue"? I'm pretty sure
 (not
 100%) that we are _NOT_ using it so what are we losing in theory?

 2) If that feature makes sense to keep, fixing it here would require a bit
 more
 of testing and check, at the very least _NOT_ using the stack pointer when
 queueing :)

 3) Should we rip it off from the code if we think we don't need it?

 4) In any of those above cases, having a document/proposal/<whatever> to
 explain how cell handling works (10k feet view is enough) would be very
 needed
 here fearing too little of us know about it.

 (FYI, same goes for var_cell_t I think, channel_queue_var_cell())

 Thanks!
 David
 }}}

 There's no security hazard here because, as channel_t is currently used by
 the upper layer, the incoming cell queue never fills, but this is
 definitely a bug and the correct solution is for the channel layer itself
 to copy cells when queueing them, and be responsible for freeing them
 after the cell handler returns in that case.

--
Ticket URL: <https://trac.torproject.org/projects/tor/ticket/18570>
Tor Bug Tracker & Wiki <https://trac.torproject.org/>
The Tor Project: anonymity online


More information about the tor-bugs mailing list