X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;ds=sidebyside;f=kernel%2Ffutex_compat.c;h=00b572666cc76178d81979f512dc9e3078b08fda;hb=30fa0d0f0c0ab2aa0d4c2f88eda49eaa19ea6f8d;hp=9c077cf9aa84b81c0da8d87450b6fb491b3a231f;hpb=8f17d3a5049d32392b79925c73a0cf99ce6d5af0;p=safe%2Fjmp%2Flinux-2.6 diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index 9c077cf..00b5726 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -8,10 +8,28 @@ #include #include +#include #include #include + +/* + * Fetch a robust-list pointer. Bit 0 signals PI futexes: + */ +static inline int +fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry, + compat_uptr_t __user *head, int *pi) +{ + if (get_user(*uentry, head)) + return -EFAULT; + + *entry = compat_ptr((*uentry) & ~1); + *pi = (unsigned int)(*uentry) & 1; + + return 0; +} + /* * Walk curr->robust_list (very carefully, it's a userspace list!) * and mark any locks found there dead, and notify any waiters. @@ -21,18 +39,18 @@ void compat_exit_robust_list(struct task_struct *curr) { struct compat_robust_list_head __user *head = curr->compat_robust_list; - struct robust_list __user *entry, *pending; - compat_uptr_t uentry, upending; - unsigned int limit = ROBUST_LIST_LIMIT; + struct robust_list __user *entry, *next_entry, *pending; + unsigned int limit = ROBUST_LIST_LIMIT, pi, next_pi, pip; + compat_uptr_t uentry, next_uentry, upending; compat_long_t futex_offset; + int rc; /* * Fetch the list head (which was registered earlier, via * sys_set_robust_list()): */ - if (get_user(uentry, &head->list.next)) + if (fetch_robust_entry(&uentry, &entry, &head->list.next, &pi)) return; - entry = compat_ptr(uentry); /* * Fetch the relative futex offset: */ @@ -42,28 +60,32 @@ void compat_exit_robust_list(struct task_struct *curr) * Fetch any possibly pending lock-add first, and handle it * if it exists: */ - if (get_user(upending, &head->list_op_pending)) + if (fetch_robust_entry(&upending, &pending, + &head->list_op_pending, &pip)) return; - pending = compat_ptr(upending); - if (upending) - handle_futex_death((void *)pending + futex_offset, curr); - while (compat_ptr(uentry) != &head->list) { + next_entry = NULL; /* avoid warning with gcc */ + while (entry != (struct robust_list __user *) &head->list) { + /* + * Fetch the next entry in the list before calling + * handle_futex_death: + */ + rc = fetch_robust_entry(&next_uentry, &next_entry, + (compat_uptr_t __user *)&entry->next, &next_pi); /* * A pending lock might already be on the list, so * dont process it twice: */ if (entry != pending) - if (handle_futex_death((void *)entry + futex_offset, - curr)) + if (handle_futex_death((void __user *)entry + futex_offset, + curr, pi)) return; - /* - * Fetch the next entry in the list: - */ - if (get_user(uentry, (compat_uptr_t *)&entry->next)) + if (rc) return; - entry = compat_ptr(uentry); + uentry = next_uentry; + entry = next_entry; + pi = next_pi; /* * Avoid excessively long or circular lists: */ @@ -72,6 +94,9 @@ void compat_exit_robust_list(struct task_struct *curr) cond_resched(); } + if (pending) + handle_futex_death((void __user *)pending + futex_offset, + curr, pip); } asmlinkage long @@ -87,10 +112,10 @@ compat_sys_set_robust_list(struct compat_robust_list_head __user *head, } asmlinkage long -compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr, +compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, compat_size_t __user *len_ptr) { - struct compat_robust_list_head *head; + struct compat_robust_list_head __user *head; unsigned long ret; if (!pid) @@ -100,7 +125,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr, ret = -ESRCH; read_lock(&tasklist_lock); - p = find_task_by_pid(pid); + p = find_task_by_vpid(pid); if (!p) goto err_unlock; ret = -EPERM; @@ -125,17 +150,24 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, struct compat_timespec __user *utime, u32 __user *uaddr2, u32 val3) { - struct timespec t; - unsigned long timeout = MAX_SCHEDULE_TIMEOUT; + struct timespec ts; + ktime_t t, *tp = NULL; int val2 = 0; + int cmd = op & FUTEX_CMD_MASK; - if ((op == FUTEX_WAIT) && utime) { - if (get_compat_timespec(&t, utime)) + if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI)) { + if (get_compat_timespec(&ts, utime)) return -EFAULT; - timeout = timespec_to_jiffies(&t) + 1; + if (!timespec_valid(&ts)) + return -EINVAL; + + t = timespec_to_ktime(ts); + if (cmd == FUTEX_WAIT) + t = ktime_add(ktime_get(), t); + tp = &t; } - if (op >= FUTEX_REQUEUE) + if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE) val2 = (int) (unsigned long) utime; - return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3); + return do_futex(uaddr, op, val, tp, uaddr2, val2, val3); }