========== Presentation ============

The goal of this plugin is to highlight a bug in gcc and/or libiberty. 

We do this by showing that the md5 computed using md5_process_bytes (from
libiberty/md5.c) does not give the same result as when we use the md5sum shell
command.

Written by Pierre Vittet, piervit@pvittet.com

========== Using the plugin ============

It looks like the bug only appears with a libiberty.a compiled with flags -g
-O0 instead of -O2. So you should not use the one given by your distribution
but recompile a fresh gcc with -g -O0 as cflags and --enable-plugins.

Once this is done, you should compile the plugin with:
make

You can install it on your system using:
make install

Then to try to plugin:
gcc -fplugin=md5sum_plugin -c empty.c


The printed md5 is the concatenation of the 2 followings buffers:
char buffer1[29] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaa";
char buffer2[355] ="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";


Basically the plugin do the following:

md5_init_ctx (&ctx);
md5_process_bytes (buffer1 , sizeof(char)*29, &ctx);
md5_process_bytes (buffer2 , sizeof(char)*355, &ctx);
md5_finish_ctx (&ctx, md5res);

The correct md5 can be obtained using md5sum with the following shell command:

echo -n "aaaaaaaaaaaaaaaaaaaaaaaaaaaa\0bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\0" | md5sum 

The -n option means we don't add the final \0 of the string (as it is manually added).

The correct md5 is a71bf110fa2d8aee68bcf8e6bb8428f9

The md5 computed with libiberty compiled in -O0 and the plugin is :
ef77b1b718f0d98d250e973a5600036f

========== How to explain the bug ============

This section must be read with a look at the function md5_process_bytes in
libiberty/md5.c. Using gdb, might make things more clear.

The bug is produced in the following case:
* First we call md5_process_bytes with a buffer smaller than 64 bits. This
cause the bits of this buffer to not be processed immediatly with
md5_process_block but to be kept in a temporary buffer of the context (variable
ctx).

* We call a new time md5_process_bytes with a buffer of a size 'LenBuf2' as:
  LenBuf2 - (128-LenBuf1) = Mul64 with Mul64 a number such as  % 64 =0.

* This cause ctx->buffer to be completed to 128 bits and to be processed with
  md5_process_block. We then reach the line if (UNALIGNED_P (buffer)). In
  order to produce the bug the condition must be true. When entering the
  function md5_process_bytes, the buffer 'buffer' is aligned but as we have
  shifted it from some bits to complete ctx->buffer, this can now be unaligned.
  I have chosen a case in which it is : 128 - 29= 99. So buffer = buffer +
  99. On my machine int are aligned to 4 bits, 99%4 != 0 so, it is not aligned.

  With my size of buffer, at this step, I have 'len' = 355- (129-29)= 256
  The 'while (len > 64)' successively process 3 blocks of 64 bits. We stop
  the loop with len = 64. We then reach line 
  'buffer = (const void *) ((const char *) buffer + (len & ~63));'. It
  appears that (64 & ~63) = 64. This means that buffer is going to be shifted
  of 64 bits while those bits haven't been processed. This produce the bug.

As said previously the bug only appears with libiberty compiled with -O0. I
highly suspect that there is another bug in gcc in the optimization system. The
optimizer 'does not see' that in this partilar case we can do something
nontrivial line 249 of md5.c.




