[tor-bugs] #17776 [Tor]: Buffer over-reads in directory and rendcache tests

Tor Bug Tracker & Wiki blackhole at torproject.org
Wed Dec 9 09:26:14 UTC 2015


#17776: Buffer over-reads in directory and rendcache tests
-------------------------------+------------------------------------
 Reporter:  cypherpunks        |          Owner:
     Type:  defect             |         Status:  needs_revision
 Priority:  Medium             |      Milestone:  Tor: 0.2.8.x-final
Component:  Tor                |        Version:  Tor: 0.2.7.3-rc
 Severity:  Normal             |     Resolution:
 Keywords:  TorCoreTeam201512  |  Actual Points:
Parent ID:                     |         Points:
  Sponsor:                     |
-------------------------------+------------------------------------

Comment (by cypherpunks):

 Replying to [comment:5 teor]:
 > Replying to [comment:4 cypherpunks]:
 > > Replying to [comment:2 teor]:
 > > > Replying to [comment:1 cypherpunks]:
 > > > > The attached patches fixes the issues mentioned in the ticket
 description. I hope the commit messages speak for themselves. Rewriting
 them into the ticket seemed redundant.
 > > >
 > > > Code Review: Patches 1 & 2
 > > >
 > > > I agree that these buffer overruns need to be fixed.
 > > >
 > > > But what I'd like to do is change the functions that overrun the
 buffers so they don't overrun buffers if a short string is passed to them.
 That way, we fix the problem at the source.
 > > >
 > > > I want to check that the fingerprint strings are:
 > > > * not NULL, and
 > > > * don't contain a NULL character in the first DIGEST_LEN bytes?
 > > > before the functions read the strings?
 > > >
 > > > You can use code like:
 > > > {{{
 > > > tor_assert(fingerprint);
 > > > tor_assert(memchr(fingerprint, 0, DIGEST_LEN) == NULL);
 > > > }}}
 > > >
 > > > That would also require updating all the test data so it's really
 DIGEST_LEN characters long (and increasing the buffer lengths by 1 to
 accommodate the terminating nul byte).
 > >
 > > The bugs were found using AddressSanitizer and i think the `memchr`
 solution will trigger similar warnings because the behavior is undefined
 if access occurs beyond the end of the array searched.
 >
 > memchr(fingerprint, 0, DIGEST_LEN) will never access any byte in
 fingerprint beyond a nul byte or DIGEST_LEN bytes. (Whichever comes
 first.)
 Unless the fingerprint isn't null-terminated and adjacent memory happens
 to contain random data with a null-byte exactly at DIGEST_LEN+1. This
 would both be undefined behavior because it over-reads and it would see
 the fingerprint as being of valid length which it isn't.
 >
 > > The assertion implies that the digests are required to be null-
 terminated strings. This moves away from the requirement that they need to
 be `DIGEST_LEN` long and is something which could be ignored in a similar
 fashion.
 >
 > The assertion is intended to catch code which passes strings shorter
 than DIGEST_LEN to the function. (We will need to comment it to make this
 clear.)
 I agree the comments on the related functions need to be clearer regarding
 the expected buffer length.
 >
 > Buffers passed to the function should never contain a nul byte in the
 first DIGEST_LEN bytes. If they do, it's because someone passed a short
 string to the function. (As you've noticed, this is easy to do.)
 >
 > Since there's no way to find the length of the memory pointed to by a
 pointer in C, our best option is to look for evidence that someone passed
 in a short buffer.
 I agree with this, but i would like to do it in a way that doesn't leave
 the door open for other issues.
 >
 > > The solution IMO would be to require string length parameters (like
 the modern C string functions).
 >
 > The buffer is a set-length non-nul terminated block of memory.
 > Any string length parameter would always be DIGEST_LEN, so it's
 redundant. (And it would imply that the buffers need to be nul-terminated,
 which they don't.)
 I agree that it is redundant so maybe it is not a good solution, but it
 does not imply the buffers are null-terminated. On the contrary, it
 implies the buffer are not null-terminated hence why we need the length as
 a separate parameter.
 >
 > > Replying to [comment:3 teor]:
 > > > Patches 1 & 2 are on unit tests introduced in 0.2.7.3-rc.
 > > > (The functions being tested are a lot older than that.)
 > >
 > > The commit messages of patches 1 and 2 include the commits which
 introduced the issues. According to `git describe --contains` both commits
 are not within in a tag. Is this correct?
 >
 > I don't know how this feature of git works.
 > I think we tag the commit that finalises a release. We don't tag all
 commits in a release.
 >
 > When I look for the release that contains a commit, I look for the first
 release commit after that commit in git log.
 After as in below it? Because that would mean the commit is not included
 in that release as `git log` usually goes back in time starting from the
 top. To quote the git manual on `git describe --contains`
 {{{
 --contains
            Instead of finding the tag that predates the commit, find the
 tag
            that comes after the commit, and thus contains it.
 }}}

 Finally, maybe i am overthinking the solution but i feel the proposed
 `memchr` assertion does not prevent all corner cases from occurring (as
 the first part of this reply explains). It introduces issues of its own.
 In search of other solutions i have looked at other parts of the Tor code
 base such as the `crypto_digest*` functions. These functions assume the
 digest buffer is large enough because they have no way of verifying it and
 all they do is assert the digest pointer isn't `NULL`. I know these are
 write operations on a buffer instead of read operations on a buffer, but
 the core question is the same; what if the buffer is too short? These
 functions do not care.

 With this knowledge i like to update the proposed changes to be
 * assert the pointer to the buffer isn't NULL (same as proposed by teor)
 * do not assert that the buffer is too short (there is no proper way to do
 this)
 * update the comments on the related functions that the buffer should be
 DIGEST_LEN long (as there is no proper way to enforce it otherwise)

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


More information about the tor-bugs mailing list