From 2a8f21b67f26ca8594ce03260ead8aaf04ee2850 Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 10 Sep 2012 16:20:16 -0500 Subject: [PATCH] (PR14488 partial fix) Make memory writing more robust. * runtime/dyninst/linux_defs.h (__copy_from_user): Remove unused code (and update comment). (__put_user): New macro. (__copy_to_user): New function. (__put_user_fn): Ditto. * runtime/dyninst/loc2c-runtime.h (__get_user_asm): Fix macro to return error code. (__put_user_asm): New macro. --- runtime/dyninst/linux_defs.h | 75 ++++++++++++++++++++++++++++----- runtime/dyninst/loc2c-runtime.h | 4 +- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/runtime/dyninst/linux_defs.h b/runtime/dyninst/linux_defs.h index 4934f4219..7ccdf56d9 100644 --- a/runtime/dyninst/linux_defs.h +++ b/runtime/dyninst/linux_defs.h @@ -160,17 +160,14 @@ static inline __must_check long __copy_from_user(void *to, { int rc = 0; - /* The pread syscall is faster than lseek()/read() (since it - * is only one syscall). + /* + * The pread syscall is faster than lseek()/read() (since it + * is only one syscall). Also, if we used lseek()/read() we + * couldn't use a cached fd - since 2 threads might hit this + * code at the same time and the 2nd lseek() might finish + * before the 1st read()... */ - /* FIXME _ need a pread configure test */ -#define HAVE_PREAD -#ifdef HAVE_PREAD - if (pread (_stp_mem_fd, to, n, (off_t)from) != n) -#else - if (lseek (_stp_mem_fd, (off_t)from, SEEK_SET) == -1 - || read (_stp_mem_fd, to, n) != n) -#endif + if (pread(_stp_mem_fd, to, n, (off_t)from) != n) rc = -EFAULT; return rc; } @@ -183,6 +180,64 @@ static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) extern int __get_user_bad(void) __attribute__((noreturn)); +#define __put_user(x, ptr) \ +({ \ + int __gu_err = -EFAULT; \ + __chk_user_ptr(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: { \ + unsigned char __x = (unsigned char)(x); \ + __gu_err = __put_user_fn(sizeof (*(ptr)), \ + ptr, &__x); \ + break; \ + }; \ + case 2: { \ + unsigned short __x = (unsigned short)(x); \ + __gu_err = __put_user_fn(sizeof (*(ptr)), \ + ptr, &__x); \ + break; \ + }; \ + case 4: { \ + unsigned int __x = (unsigned int)(x); \ + __gu_err = __put_user_fn(sizeof (*(ptr)), \ + ptr, &__x); \ + break; \ + }; \ + case 8: { \ + unsigned long long __x = (unsigned long long)(x); \ + __gu_err = __put_user_fn(sizeof (*(ptr)), \ + ptr, &__x); \ + break; \ + }; \ + default: \ + __put_user_bad(); \ + break; \ + } \ + __gu_err; \ +}) + +static inline __must_check long __copy_to_user(void *to, const void *from, + unsigned long n) +{ + int rc = 0; + + /* + * The pwrite syscall is faster than lseek()/write() (since it + * is only one syscall). + */ + if (pwrite(_stp_mem_fd, to, n, (off_t)from) != n) + rc = -EFAULT; + return rc; +} + +static inline int __put_user_fn(size_t size, const void __user *ptr, void *x) +{ + size = __copy_to_user(x, ptr, size); + return size ? -EFAULT : size; +} + +extern int __put_user_bad(void) __attribute__((noreturn)); + static inline void INIT_LIST_HEAD(struct list_head *list) { list->next = list; diff --git a/runtime/dyninst/loc2c-runtime.h b/runtime/dyninst/loc2c-runtime.h index 42dd2c218..53532ebde 100644 --- a/runtime/dyninst/loc2c-runtime.h +++ b/runtime/dyninst/loc2c-runtime.h @@ -1,5 +1,7 @@ #include "../loc2c-runtime.h" #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \ - __get_user((x), (typeof(x)*)(addr)) + (err) = __get_user((x), (typeof(x)*)(addr)) +#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \ + (err) = __put_user((x), (typeof(x)*)(addr)) -- 2.43.5