On Tue, 26 Apr 2022, Jakub Jelinek wrote:

> Hi!
> 
> On the following testcase, we have in main's frame 3 variables,
> some red zone padding, 4 byte d, followed by 12 bytes of red zone padding, 
> then
> 8 byte b followed by 24 bytes of red zone padding, then 40 bytes c followed
> by some red zone padding.
> The intended content of shadow memory for that is (note, each byte describes
> 8 bytes of memory):
> f1 f1 f1 f1 04 f2 00 f2 f2 f2 00 00 00 00 00 f3 f3 f3 f3 f3
> left red    d  mr b  middle r c              right red zone
> 
> f1 is left red zone magic
> f2 is middle red zone magic
> f3 is right red zone magic
> 00 when all 8 bytes are accessible
> 01-07 when only 1 to 7 bytes are accessible followed by inaccessible bytes
> 
> The -fdump-rtl-expand-details dump makes it clear that it misbehaves:
> Flushing rzbuffer at offset -160 with: f1 f1 f1 f1
> Flushing rzbuffer at offset -128 with: 04 f2 00 00
> Flushing rzbuffer at offset -128 with: 00 00 00 f2
> Flushing rzbuffer at offset -96 with: f2 f2 00 00
> Flushing rzbuffer at offset -64 with: 00 00 00 f3
> Flushing rzbuffer at offset -32 with: f3 f3 f3 f3
> In the end we end up with
> f1 f1 f1 f1 00 00 00 f2 f2 f2 00 00 00 00 00 f3 f3 f3 f3 f3
> shadow bytes because at offset -128 there are 2 overlapping stores
> as asan_redzone_buffer::emit_redzone_byte has flushed the temporary 4 byte
> buffer in the middle.
> 
> The function is called with an offset and value.  If the passed offset is
> consecutive with the prev_offset + buffer size (off == offset), then
> we handle it correctly, similarly if the new offset is far enough from the
> old one (we then flush whatever was in the buffer and if needed add up to 3
> bytes of 00 before actually pushing value.
> 
> But what isn't handled correctly is when the offset isn't consecutive to
> what has been added last time, but it is in the same 4 byte word of shadow
> memory (32 bytes of actual memory), like the above case where
> we have consecutive 04 f2 and then skip one shadow memory byte (aka 8 bytes
> of real memory) and then want to emit f2.  Emitting that as a store
> of little-endian 0x0000f204 followed by a store of 0xf2000000 to the same
> address doesn't work, we want to emit 0xf200f204.
> 
> The following patch does that by pushing 1 or 2 00 bytes.
> Additionally, as a small cleanup, instead of using
>       m_shadow_bytes.safe_push (value);
>       flush_if_full ();
> in all of if, else if and else bodies it sinks those 2 stmts to the end
> of function as all do the same thing.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Richard.

> 2022-04-26  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR sanitizer/105396
>       * asan.cc (asan_redzone_buffer::emit_redzone_byte): Handle the case
>       where offset is bigger than off but smaller than m_prev_offset + 32
>       bits by pushing one or more 0 bytes.  Sink the
>       m_shadow_bytes.safe_push (value); flush_if_full (); statements from
>       all cases to the end of the function.
> 
>       * gcc.dg/asan/pr105396.c: New test.
> 
> --- gcc/asan.cc.jj    2022-02-19 09:03:50.000000000 +0100
> +++ gcc/asan.cc       2022-04-26 16:57:49.737316329 +0200
> @@ -1497,10 +1497,14 @@ asan_redzone_buffer::emit_redzone_byte (
>    HOST_WIDE_INT off
>      = m_prev_offset + ASAN_SHADOW_GRANULARITY * m_shadow_bytes.length ();
>    if (off == offset)
> +    /* Consecutive shadow memory byte.  */;
> +  else if (offset < m_prev_offset + (HOST_WIDE_INT) (ASAN_SHADOW_GRANULARITY
> +                                                  * RZ_BUFFER_SIZE)
> +        && !m_shadow_bytes.is_empty ())
>      {
> -      /* Consecutive shadow memory byte.  */
> -      m_shadow_bytes.safe_push (value);
> -      flush_if_full ();
> +      /* Shadow memory byte with a small gap.  */
> +      for (; off < offset; off += ASAN_SHADOW_GRANULARITY)
> +     m_shadow_bytes.safe_push (0);
>      }
>    else
>      {
> @@ -1521,9 +1525,9 @@ asan_redzone_buffer::emit_redzone_byte (
>        m_shadow_mem = adjust_address (m_shadow_mem, VOIDmode,
>                                    diff >> ASAN_SHADOW_SHIFT);
>        m_prev_offset = offset;
> -      m_shadow_bytes.safe_push (value);
> -      flush_if_full ();
>      }
> +  m_shadow_bytes.safe_push (value);
> +  flush_if_full ();
>  }
>  
>  /* Emit RTX emission of the content of the buffer.  */
> --- gcc/testsuite/gcc.dg/asan/pr105396.c.jj   2022-04-26 16:56:34.522348879 
> +0200
> +++ gcc/testsuite/gcc.dg/asan/pr105396.c      2022-04-26 17:00:54.757776387 
> +0200
> @@ -0,0 +1,19 @@
> +/* PR sanitizer/105396 */
> +/* { dg-do run } */
> +/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */
> +/* { dg-shouldfail "asan" } */
> +
> +int
> +main ()
> +{
> +  int a;
> +  int *b[1];
> +  int c[10];
> +  int d[1][1];
> +  for (a = 0; a < 1; a++)
> +    d[1][a] = 0;
> +  return 0;
> +}
> +
> +/* { dg-output "ERROR: AddressSanitizer: stack-buffer-overflow on 
> address.*(\n|\r\n|\r)" } */
> +/* { dg-output "WRITE of size.*" } */
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)

Reply via email to