help-libtasn1
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

libtasn1 with a fine-toothed comb


From: Pascal Cuoq
Subject: libtasn1 with a fine-toothed comb
Date: Sat, 2 Apr 2016 15:45:08 +0000

Hello,

I am currently giving libtasn1 the same treatment that John Regehr describes 
applying to SQLite here:
http://blog.regehr.org/archives/1292

This message is about the first two findings:


- One of the things that tis-interpreter has found so far is fprintf("%02x… 
being applied to what is, after integer promotions, an int. This pattern is 
fixed by the following commit:

https://github.com/pascal-cuoq/libtasn1-fork/commit/0803a38108e76ede7d4cd03dae0fcc713fdc7da9


- Another pattern has to do with memcpy() and length arguments of zero. Anyone 
who has looked into this recent commit knowns that C compilers have taken to 
optimize on the basis of a sentence in the C standard that says that the 
arguments of standard functions must not be “invalid values”:

“If an argument to a function has an invalid value (such as a value outside the 
domain of the function, or a pointer outside the address space of the program, 
or a null pointer, or a pointer to non-modifiable storage when the 
corresponding parameter is not const-qualified) or a type (after promotion) not 
expected by a function with variable number of arguments, the behavior is 
undefined.”

The above is in C11 (http://port70.net/~nsz/c/c11/n1570.html#7.1.4p1 ) but a 
similar sentence was present in C99. BIND started to be compiled to binaries 
that behaved incorrectly when GCC 4.9 introduced an optimization based on this 
sentence: http://blog.mycre.ws/articles/bind-and-gcc-49/

This clearly means that memcpy(NULL, p, 0) and memcpy(p, NULL, 0) are undefined 
behavior, or at least C compilers have decided that they are. It is debatable 
whether the same rule also means that pointers “one past the end” (t + n when t 
is an array of n elements) are invalid arguments for memcpy even together with 
a size of 0 
(http://stackoverflow.com/questions/25390577/is-memcpya-1-b-1-0-defined-in-c11 
) but in doubt I would recommend to future-proof the source code by avoiding 
such memcpy invocations.

tis-interpreter has found memcpy invoked with “one past the end” pointers in 
_asn1_append_value():
http://git.savannah.gnu.org/gitweb/?p=libtasn1.git;a=blob;f=lib/parser_aux.c;h=da9a388fe3204d22f56a138af319ee8a9b77d7f0;hb=bd6f37713d139b5d102df70248ee9af3422f0339#l304

When the function _asn1_append_value() is invoked with len containing 0, a 
memcpy call with a “one past the end” pointer can happen as a result either at 
line 330 or at line 346. Inputs to the commandline utility asn1Decoding that 
cause it to be called with 0 for the len argument causing this to happen.
If it is a logic error for _asn1_append_value() to be used this way, the 
invalid input can be diagnosed at any point before the function is called. Some 
call stacks ending in _asn1_append_value() being passed a length of zero are at 
the bottom of this message. The line numbers are those of version 4.7, possibly 
with small offsets when I needed to adapt files for tis-interpreter. The inputs 
are available on request.
If it is not a logic error for _asn1_append_value() to be used this way, then 
ideally the function should handle the case where len is 0 without calling 
memcpy on “one past the end” pointers to prevent future compiler optimizations 
to mess with that code.

Pascal

PS: I have used afl to generate inputs that exert (so far) 1206 different 
execution paths inside asn1Decode. I will make all the inputs available in 
batch at the end of the fuzzing session, but I would appreciate additional 
testcases, especially if they came in the form of inputs to asn1Decode.

--
                 assert((void *)(node->value + prev_len) is a valid pointer for 
writing)
                 stack: memcpy :: lib/parser_aux.c:330 <-
                        _asn1_append_value :: lib/decoding.c:788 <-
                        _asn1_extract_der_octet :: lib/decoding.c:885 <-
                        get_octet_string :: lib/decoding.c:1307 <-
                        asn1_der_decoding2 :: lib/decoding.c:1647 <-
                        asn1_der_decoding :: src/asn1Decoding.c:276 <-
                        simple_decode :: src/asn1Decoding.c:304 <-
                        decode :: src/asn1Decoding.c:225 <-
                        main

--
                 assert((void *)(node->value + prev_len_0) is a valid pointer 
for writing)
                 stack: memcpy :: lib/parser_aux.c:346 <-
                        _asn1_append_value :: lib/decoding.c:788 <-
                        _asn1_extract_der_octet :: lib/decoding.c:885 <-
                        get_octet_string :: lib/decoding.c:1307 <-
                        asn1_der_decoding2 :: lib/decoding.c:1647 <-
                        asn1_der_decoding :: src/asn1Decoding.c:276 <-
                        simple_decode :: src/asn1Decoding.c:304 <-
                        decode :: src/asn1Decoding.c:225 <-
                        main










reply via email to

[Prev in Thread] Current Thread [Next in Thread]