Page MenuHome GnuPG

Reading uninitialized memory in libksba
Closed, ResolvedPublic

Description

The two attached files show that libksba can read form uninitalized memory for invalid ASN.1 inputs. One danger is that
uninitialized memory might contain valuable information (keys, nonces, or simply addresses of functions, defeating ASLR) that will
be incorporated in the dataflow of the program using libksba and eventually sent back to the attacker.

In order to make the use of uninitialized memory obvious, please apply the following patch:

~/instrumented/libksba-1.3.4$ diff -u src/util.c{~,}

  • src/util.c~ 2013-03-15 20:26:38.000000000 +0100

+++ src/util.c 2016-05-11 02:18:39.685533973 +0200
@@ -121,13 +121,13 @@
/* Wrapper for the common memory allocation functions. These are here

so that we can add hooks.  The corresponding macros should be used.
These macros are not named xfoo() because this name is commonly
  • used for function which die on errror. We use macronames like

+ used for function which die on error. We use macronames like

   xtryfoo() instead. */

void *
ksba_malloc (size_t n )
{

  • return alloc_func (n);

+ void *p = alloc_func (n); if (p && n) memset(p,0x3e,n); return p;
}

void *

This fills memory that would otherwise have been uninitialized (coming from malloc()) with the character 3E. This is not supposed
to influence the behavior of a well-behaved program, as the contents of a block allocated by malloc() are indeterminate and
shouldn't be used, in C standard parlance.

~/instrumented/libksba-1.3.4$ ./tests/cert-basic uninitialized1.crt
Certificate in `uninitialized1.crt':

serial....: (#00#)
issuer....:

`0.23.13.48.51.48.51.51.48.49=#39343E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3
E,0.0.0.0=#43412043657274205369676E696E6720417574686F00800000,OU=http://www.cacert.org,O=Root CA'
...
Uninitialized memory is read here and is shown by the 3E3E3E... sequence.

~/instrumented/libksba-1.3.4$ ./tests/cert-basic uninitialized2.crt
Certificate in `uninitialized2.crt':

serial....: (#00EE04D9636253D675#)
issuer....: `CN=a'
subject...: `CN=a'
notBefore.: none
notAfter..: 2042-08-30 23:09:33
hash algo.: (null)

cert-basic.c:464: public key not found
Extn: 2.5.29.14 at 206 with length 22
SubjectKeyIdentifier: (#3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E3E#)
...
Uninitialized memory is read here and is shown by the 3E3E3E... sequence.

tis-interpreter, applied to the non-instrumented version of libksba 1.3.4, provides the following information:

For uninitialized1.crt:

Certificate in `t.crt':

  serial....:

00
src/dn.c:628:[kernel] warning: accessing uninitialized left-value:

assert \initialized(image+((node->off+node->nhdr)+i));
stack: append_atv :: src/dn.c:667 <-
       dn_to_str :: src/dn.c:692 <-
       _ksba_dn_to_str :: src/cert.c:609 <-
       get_name :: src/cert.c:744 <-
       _ksba_cert_get_issuer :: src/visibility.c:190 <-
       ksba_cert_get_issuer :: tests/cert-basic.c:424 <-
       one_file :: tests/cert-basic.c:593 <-
       main

src/dn.c:628:[kernel] warning: completely indeterminate value in mallocksba_malloc_l130_935 with offset 1104 bits.

For uninitialized2.crt:

Certificate in `t.crt':

  serial....:

00

EE

04

D9

63

62

53

D6

75

  issuer....:

`CN=a'

  subject...:

`CN=a'

  notBefore.:

none

  notAfter..:

2042-08-30 23:09:33

  hash algo.: (null)

fprintf(__fc_stderr,...)
tests/cert-basic.c:464: public key not found

Extn: 2.5.29.14 at 206 with length 22

SubjectKeyIdentifier:
tests/t-common.h:137:[kernel] warning: accessing uninitialized left-value: assert \initialized(s);

stack: print_sexp :: tests/cert-basic.c:182 <-
       list_extensions :: tests/cert-basic.c:546 <-
       one_file :: tests/cert-basic.c:593 <-
       main

tests/t-common.h:137:[kernel] warning: completely indeterminate value in mallocksba_malloc_l130_944 with offset 32 bits.

Details

Version
1.3.4

Event Timeline

Here is a third instance, much like the second one. As the read from uninitialized memory happens in append_ucs2_value(),
the uninitialized memory is harder to recognize in the output.

tis-interpreter information:

Certificate in `t.crt':

  serial....:

02

3A

83
src/dn.c:522:[kernel] warning: accessing uninitialized left-value:

assert \initialized(tmp_1);
(tmp_1 from s++)
stack: append_ucs2_value :: src/dn.c:619 <-
       append_atv :: src/dn.c:667 <-
       dn_to_str :: src/dn.c:692 <-
       _ksba_dn_to_str :: src/cert.c:609 <-
       get_name :: src/cert.c:744 <-
       _ksba_cert_get_issuer :: src/visibility.c:190 <-
       ksba_cert_get_issuer :: tests/cert-basic.c:424 <-
       one_file :: tests/cert-basic.c:593 <-
       main

src/dn.c:522:[kernel] warning: completely indeterminate value in mallocksba_malloc_l130_935 with offset 1384 bits.

Here is a fourth instance of use of uninitialized memory (uninitialized4.crt).

The tis-interpreter diagnostic is:

Certificate in `t.crt':

  serial....:

02

3A

83

  issuer....:

`CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US'

  subject...:

`CN=Google Internet Authority G2,O=Google Inc,C=US'

  notBefore.:

2013-04-05 15:15:56

  notAfter..:

2016-12-31 23:59:59

  hash algo.: (null)

Extn: 2.5.29.35 at 517 with length 24

SubjectKeyIdentifier:

none
src/ber-help.c:213:[kernel] warning: accessing uninitialized left-value:

assert \initialized(buf);                  
stack: _ksba_ber_parse_tl :: src/cert.c:1836 <-
       _ksba_cert_get_auth_key_id :: src/visibility.c:280 <-
       ksba_cert_get_auth_key_id :: tests/cert-basic.c:190 <-
       list_extensions :: tests/cert-basic.c:546 <-
       one_file :: tests/cert-basic.c:593 <-
       main

src/ber-help.c:213:[kernel] warning: completely indeterminate value in mallocksba_malloc_l130_935 with offsets 4152 bits.

In order to make the use of uninitialized memory visible, apply the following patch:

~/instrumented/libksba-1.3.4$ diff -u src/ber-
ber-decoder.c ber-decoder.lo ber-dump ber-help.c ber-help.h ber-help.o
ber-decoder.h ber-decoder.o ber-dump.c ber-help.c~ ber-help.lo
pascal@TrustInSoft-Box-VII:~/instrumented/libksba-1.3.4$ diff -u src/ber-help.c{~,}

  • src/ber-help.c~ 2016-05-03 18:12:09.000000000 +0200

+++ src/ber-help.c 2016-05-11 03:04:34.361037076 +0200
@@ -210,7 +210,7 @@

/* Get the tag */
if (!length)
  return premature_eof (ti);
  • c = *buf++; length--;

+ c = *buf++; printf("|%02hhX|\n", c); length--;

   ti->buf[ti->nhdr++] = c;
   ti->class = (c & 0xc0) >> 6;

With the above instrumentation in place, the command "./tests/cert-basic uninitialized4.crt" shows:

Certificate in `uninitialized4.crt':

serial....: (#023A83#)
issuer....: `CN=GeoTrust Global CA,O=GeoTrust Inc.,C=US'
subject...: `CN=Google Internet Authority G2,O=Google Inc,C=US'
notBefore.: 2013-04-05 15:15:56
notAfter..: 2016-12-31 23:59:59
hash algo.: (null)

Extn: 2.5.29.35 at 517 with length 24
SubjectKeyIdentifier: none

30
3E

cert-basic.c:219: ksba_cert_get_auth_key_id: Invalid certificate object
KeyUsage: Not specified
ExtKeyUsages: none
CertificatePolicies: none
cert-basic.c:557: expected EOF but got: BER error

The line |3E| indicates access to uninitialized memory.

Now I regret reporting so many different problems as a single ticket. Note that if possible
information leaks are the only thing we are concerned with, all the issues in this ticket can be
solved by systematically initializing dynamically allocated memory, so they have that in common.

This won't solve the problems that several inconsistent .crt files are in fact accepted as valid,
showing contents of the freshly initialized allocated memory in place of information that should have
come from the .crt file. I would much prefer fixing these logic errors individually so that use of
uninitialized memory can remain a useful symptom of other logic errors, but ultimately, this is your
choice to make.

Thanks. I would actually prefer to handle this by mail because this makes
communication easier and faster. It would also be useful to known on what you
are working or plan to work on, so that we do not need to rush out releases
while there are other obvious things to fix.

commit 2a9fc56 fixes the access to uninitialized buffers. Given that GnuPG puts
all senstive data into a special memory area which is cleared before a free, I
don't see a problem with a possible data leak.

What is left is the problem that the parser does not always detect invalid
encodings. This can be improved but I am not anymore convinced about that table
driven parser.

marcus claimed this task.
marcus added a subscriber: marcus.

Because werner says he fixed the memory access, I am closing here. werner, if you want to keep track of the invalid encoding issue with the asn.1 parser, please open a new task with some details. pascal, if you find anything missing, please open new tickets (as you said, it's easier to keep track of issues in separate tickets).

It is fine to close this. Reworking the parser is not going to happen anytime soon.