This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] Knobs to detect undefined behaviour.


On Wed, Oct 09, 2013 at 02:33:25PM -0400, Carlos O'Donell wrote:
> On 10/09/2013 03:28 AM, OndÅej BÃlka wrote:
> > On Tue, Oct 08, 2013 at 01:04:16PM -0600, Jeff Law wrote:
> >> When I first proposed the idea for these sanity checking dl-preload
> >> libraries for Fedora I envisioned that we could go beyond just
> >> checking for overlapping memory areas in the mem* and str*
> >> functions.  There could be a set of pthread wrapper functions that
> >> check for whatever invariants we can in the pthread* functions
> >> without a huge performance hit.
> >>
> > It is possible but we could use a environment variable in libc as
> > alternative. Then we could choose detecting implementation by ifunc.
> > 
> > Or add assert-like macro that will be compiled into libc_sanitized.so
> > 
> > Main advantage is visibility. If user needs to find ten various libraries 
> > and preload them few of users will do that. It should be moved to one place
> > 
> > As we could add to manpages something like:
> > 
> > A glibc could detect various undefined behaviours and abort when it is
> > detected. But it could break third party binaries so this needs to be
> > enabled manually. For checking use:
> > 
> > GLIBC_SANITIZE=true program
> > 
> > 
> > There are various areas that could be covered:
> > 
> > str/mem routines - could we merge memstomp?
> > 
> > malloc - A efence got this almost right but tried to detect all
> > overruns.
> > 
> > If we detect these only statisticaly it could be done only with using
> > twice more memory, for requests upto 4096 bytes we will use arena that
> > alternates between protected and usable pages like:
> > prot use prot use prot use prot
> > and for more than 4096 bytes we could use mmap.
> > 
> > If we placed a 64-bit canary before/after each alloc we could also add
> > bounds checking by looking for that canary.
> > 
> > What else?
> 
> There is a lot we could talk about here.
> 
> The linker already does process the environment variables so it could
> be done via env vars I think.
> 
> We need to make forward progress on tunnables per our discussions 
> at Cauldron 2013, which is to unify internally all the existing
> tunnables.
> 
> We also need to make forward progress on env vars, which is to flesh
> out the policy and check to see if existing env vars match the
> policy and if not then talk about how we might clean things up.
> 
> https://sourceware.org/glibc/wiki/TuningLibraryRuntimeBehavior
> https://sourceware.org/glibc/wiki/EnvVarGuide
> 
> Cheers,
> Carlos.

I wrote a quick alternative for LD_PRELOAD. I added two performance
related warnings. First one is when user tries to concatenate strings in
strcat that leads to quadratic behavior.

A second is to warn if there are many large misaligned copies. I do not
have qualification of what means many yet.

Comments?

#include <stdlib.h>
#include <string.h>
#undef memcpy

void *
memcpy (void *dest, const void *src, size_t n)
{
  static int misaligned = 0;
  size_t i;
  if (n > 4096 && (dest - src) % 16 && !misaligned)
    {
      log ("memcpy : Misaligned copy of size %i\n", n);
      if (getenv ("ABORT_MISALIGNED"))
	abort ();
      misaligned = 1;
    }
  if (src - n < dest && dest < src + n)
    {
      fprintf (stderr, "memcpy  - overlapping areas\n");
      abort ();
    }
  __add_counter ();

  memmove (dest, src, n); /* memmove is not overloaded */
  return dest;
}
void *
mempcpy (void *dest, const void *src, size_t n)
{
  return memcpy (dest, src, n) + n;
}
char *
strcpy (char *dest, const char *src)
{
  size_t n = strlen (src) + 1;
  return memcpy (dest, src, n);
}
char *
stpcpy (char *dest, const char *src)
{
  size_t n = strlen (src) + 1;
  return memcpy (dest, src, n) + n - 1;
}

char *
strncpy (char *dest, const char *src, size_t n)
{
  if (src - n < dest && dest < src + n)
    {
      fprintf (stderr, "memcpy  - overlapping areas");
      abort ();
    }
  size_t len = strnlen (src, n);
  memcpy (dest, src, len);
  memset (dest + len, 0, n - len);
  return dest;
}

char *
stpncpy (char *dest, const char *src, size_t n)
{
  if (src - n < dest && dest < src + n)
    {
      fprintf (stderr, "memcpy  - overlapping areas");
      abort ();
    }
  size_t len = strnlen (src, n);
  memcpy (dest, src, len);
  memset (dest + len, 0, n - len);
  return dest + len;
}


char *
strncat (char *dest, const char *src, size_t n)
{
  static char *last; static int cnt; static int lastsize;
  size_t len = strnlen (src, n);
  char *p = dest + strlen (dest);

  if (dest == last && len >= lastsize)
    {
      cnt++;
    }
  else
    {
      cnt = 0;
    }
  lastsize = len;

  static int quad = 0;
  if (cnt > 10 && !quad)
    {
      log ("str(n)cat : Detected likely quadratic loop.\n");
      if (getenv ("ABORT_LOOP"))
	abort ();
      quad = 1;
    }


  if (src - len < dest && dest < p)
    {
      fprintf (stderr, "memcpy  - overlapping areas");
      abort ();
    }

  memcpy (p, src, len);
  p[len] = 0;
  return dest;
}

char *
strcat (char *dest, const char *src)
{
  return strncat (dest, src, strlen (src));
}

void *
memccpy (void *dest, const void *src, int c, size_t n)
{
  if (src - n < dest && dest < src + n)
    {
      fprintf (stderr, "memccpy  - overlapping areas");
      abort ();
    }

  void *p = memchr (src, c, n);

  if (p != NULL)
    return mempcpy (dest, src, p - src + 1);

  memcpy (dest, src, n);
  return NULL;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]