This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] Preload infrastructure.
- From: OndÅej BÃlka <neleai at seznam dot cz>
- To: libc-alpha at sourceware dot org
- Date: Mon, 21 Oct 2013 21:36:17 +0200
- Subject: [PATCH] Preload infrastructure.
- Authentication-results: sourceware.org; auth=none
Hi, to continue idea from
http://www.sourceware.org/ml/libc-alpha/2013-10/msg00303.html
I wrote a simple custom library to detect undefined behaviour and
performance problems.
A first implementation does:
- overflow checks for string routines.
- detection of strcat usage that leads to quadratic behaviour
- detection passing long unaligned strings to memcpy
- detection of passing closed file descriptor to freopen (bug 15701)
OK to commit?
* preload: New directory.
* preload/Makefile: New file.
* preload/common.c: Likewise.
* preload/common.h: Likewise.
* preload/freopen.c: Likewise.
* preload/string.c: Likewise.
* preload/use_preload: Likewise.
diff --git a/preload/Makefile b/preload/Makefile
new file mode 100644
index 0000000..7663d83
--- /dev/null
+++ b/preload/Makefile
@@ -0,0 +1,2 @@
+all:
+ gcc *.c -fPIC -ldl -shared -o libc_preload.so
diff --git a/preload/common.c b/preload/common.c
new file mode 100644
index 0000000..098d307
--- /dev/null
+++ b/preload/common.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+#include <dlfcn.h>
+FILE *__preload_log;
+void *__libc_handle;
+long __preload_counter = 0;
+static void __attribute__ ((constructor))
+init ()
+{
+ __preload_log = fopen ("/tmp/preload_log", "a");
+ __libc_handle = dlopen ("libc.so.6", RTLD_NOW);
+}
+static void __attribute__ ((destructor))
+fini ()
+{
+ fclose (__preload_log);
+}
+
+void
+__add_counter ()
+{
+ __preload_counter++;
+}
diff --git a/preload/common.h b/preload/common.h
new file mode 100644
index 0000000..0a3e2ba
--- /dev/null
+++ b/preload/common.h
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <dlfcn.h>
+extern FILE *__preload_log;
+extern long __preload_counter;
+extern void *__libc_handle;
+
+#define log(...) fprintf(__preload_log,__VA_ARGS__)
diff --git a/preload/freopen.c b/preload/freopen.c
new file mode 100644
index 0000000..6a955eb
--- /dev/null
+++ b/preload/freopen.c
@@ -0,0 +1,13 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include "common.h"
+FILE *freopen(const char *path, const char *mode, FILE *stream)
+{
+ int fd = fileno (stream);
+ /* Check that file descriptor is open. */
+ if (fcntl(fd, F_GETFD) == -1)
+ return NULL;
+ FILE *(*fp)(const char *, const char *, FILE *) = dlsym (__libc_handle, "freopen");
+ return fp (path, mode, stream);
+}
+
diff --git a/preload/string.c b/preload/string.c
new file mode 100644
index 0000000..5de89b4
--- /dev/null
+++ b/preload/string.c
@@ -0,0 +1,134 @@
+#include <stdlib.h>
+#include <string.h>
+#include "common.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 %i: Misaligned copy of size %i\n", __preload_counter, n);
+ if (getenv ("ABORT_MISALIGNED"))
+ abort ();
+ misaligned = 1;
+ }
+ if (src - n < dest && dest < src + n)
+ {
+ fprintf (stderr, "memcpy %i - overlapping areas\n", __preload_counter);
+ 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 %i - overlapping areas", __preload_counter);
+ 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 %i - overlapping areas", __preload_counter);
+ 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 %i: Detected likely quadratic loop.\n", __preload_counter);
+ if (getenv ("ABORT_LOOP"))
+ abort ();
+ quad = 1;
+ }
+
+
+ if (src - len < dest && dest < p)
+ {
+ fprintf (stderr, "memcpy %i - overlapping areas", __preload_counter);
+ 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 %i - overlapping areas", __preload_counter);
+ abort ();
+ }
+
+ void *p = memchr (src, c, n);
+
+ if (p != NULL)
+ return mempcpy (dest, src, p - src + 1);
+
+ memcpy (dest, src, n);
+ return NULL;
+}
diff --git a/preload/use_preload b/preload/use_preload
new file mode 100755
index 0000000..908042c
--- /dev/null
+++ b/preload/use_preload
@@ -0,0 +1,7 @@
+#!/bin/bash
+rm /tmp/preload_log
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+LD_PRELOAD=$DIR/preload.so $*
+echo
+echo "preload warnings:"
+cat /tmp/preload_log