Current-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: gcc 5.3 version of libasan is broken



On 2016/06/07 8:58, Christos Zoulas wrote:
This is what I was thinking. Perhaps it is easier to use syscall for ILP32
and __syscall for LP64. But then there is lseek...

Yes. And it fails for LP64BE. I made the revised patch, where 3 kinds of
internal_syscall macros are provided for different types of retval:

  - internal_syscall     for 32-bit length (int, pid_t)
  - internal_syscall64   for 64-bit length (off_t)
  - internal_syscall_ptr for pointer and (s)size_t

This seems a little messy, but it is a reliable and simple solution for
sharing codes between ILP32 and LP64 / LE and BE. I tested that libasan
works just fine for amd64, i386, and earmv7hf-eb; it detects a buffer
overflow like this:

  #include <stdlib.h>
  #include <string.h>
  int main()
  {
    char *dest, *from = "123";

    dest = malloc(3);
    strcpy(dest, from);
    return 0;
  }

I also checked libubsan on amd64, i386, and earmv7hf-eb. It can detect
an undefined operation like this:

  int main()
  {
    int i = 1, j = 0;
    return i / j;
  }

I expect that it maybe works also for LP64BE though I could not test.

On 2016/06/07 8:57, Christos Zoulas wrote:
Are you sure this works for 64 bit? I am worried about the (long)0, padding.

Yes. I checked. The padding for mmap(2) is long:
https://nxr.netbsd.org/source/xref/src/sys/sys/syscallargs.h#1215

I also checked and reorganized arguments for other syscalls in the
attached patch.

I did not test on GCC 5.4. But I suppose that it should work because
no syscall-related changes were made for libsanitizer.

Thanks,
Rin
====
--- ./src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc.orig	2016-06-07 16:36:47.544537652 +0900
+++ ./src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc	2016-06-07 19:25:02.083848571 +0900
@@ -25,7 +25,22 @@
 # define SYSCALL(name) __NR_ ## name
 #endif
-#if (SANITIZER_FREEBSD && defined(__x86_64__)) || SANITIZER_NETBSD
+#if SANITIZER_NETBSD
+// We use 3 kinds of internal_syscall's for different types of retval in order
+// to address problems related to the byte order.
+//   - internal_syscall     for 32-bit length (int, pid_t)
+//   - internal_syscall64   for 64-bit length (off_t)
+//   - internal_syscall_ptr for pointer and (s)size_t
+# define  internal_syscall	syscall
+# define  internal_syscall64	__syscall
+# if SANITIZER_WORDSIZE == 64
+#  define internal_syscall_ptr	__syscall
+# else
+#  define internal_syscall_ptr	syscall
+# endif
+#endif
+
+#if (SANITIZER_FREEBSD && defined(__x86_64__))
 # define internal_syscall __syscall
 # else
 # define internal_syscall syscall
--- ./src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_linux.cc.orig	2016-06-07 16:36:59.863423802 +0900
+++ ./src/external/gpl3/gcc/dist/libsanitizer/sanitizer_common/sanitizer_linux.cc	2016-06-07 21:46:48.721082396 +0900
@@ -101,7 +101,10 @@
 // --------------- sanitizer_libc.h
 uptr internal_mmap(void *addr, uptr length, int prot, int flags,
                     int fd, u64 offset) {
-#if SANITIZER_NETBSD || SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+#if SANITIZER_NETBSD
+  return internal_syscall_ptr(SYSCALL(mmap), addr, length, prot, flags, fd,
+			      (long)0, offset);
+#elif SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
   return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
                           offset, 0);
 #else
@@ -142,21 +145,33 @@
uptr internal_read(fd_t fd, void *buf, uptr count) {
   sptr res;
+#ifdef SANITIZER_NETBSD
+  HANDLE_EINTR(res, internal_syscall_ptr(SYSCALL(read), fd, buf, count));
+#else
   HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf,
                count));
+#endif
   return res;
 }
uptr internal_write(fd_t fd, const void *buf, uptr count) {
   sptr res;
+#ifdef SANITIZER_NETBSD
+  HANDLE_EINTR(res, internal_syscall_ptr(SYSCALL(write), fd, buf, count));
+#else
   HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf,
                count));
+#endif
   return res;
 }
uptr internal_ftruncate(fd_t fd, uptr size) {
   sptr res;
+#ifdef SANITIZER_NETBSD
+  HANDLE_EINTR(res, internal_syscall(SYSCALL(ftruncate), fd, 0, (s64)size));
+#else
   HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size));
+#endif
   return res;
 }
@@ -239,7 +254,9 @@
 }
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
-#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+#if SANITIZER_NETBSD
+  return internal_syscall_ptr(SYSCALL(readlink), path, buf, bufsize);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
   return internal_syscall(SYSCALL(readlinkat), AT_FDCWD,
                           (uptr)path, (uptr)buf, bufsize);
 #else
@@ -311,7 +328,11 @@
   kernel_timeval tv;
 #endif
   internal_memset(&tv, 0, sizeof(tv));
+#if SANITIZER_NETBSD
+  internal_syscall(SYSCALL(gettimeofday), &tv, NULL);
+#else
   internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0);
+#endif
   return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
 }
@@ -486,14 +507,22 @@
 };
// Syscall wrappers.
+#if SANITIZER_NETBSD
+// XXX We need to convert arguments.
+#else
 uptr internal_ptrace(int request, int pid, void *addr, void *data) {
   return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
                           (uptr)data);
 }
+#endif
uptr internal_waitpid(int pid, int *status, int options) {
+#if SANITIZER_NETBSD
+  return internal_syscall(SYSCALL(wait4), pid, status, options, NULL);
+#else
   return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
                           0 /* rusage */);
+#endif
 }
uptr internal_getpid() {
@@ -505,7 +534,9 @@
 }
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
-#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+#if SANITIZER_NETBSD
+  return internal_syscall(SYSCALL(getdents), fd, dirp->d_name, (uptr)count);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
   return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
 #else
   return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
@@ -513,7 +544,11 @@
 }
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
+#if SANITIZER_NETBSD
+  return internal_syscall64(SYSCALL(lseek), fd, 0, offset, whence);
+#else
   return internal_syscall(SYSCALL(lseek), fd, offset, whence);
+#endif
 }
#if SANITIZER_LINUX

Home | Main Index | Thread Index | Old Index