Advertisement
Guest User

Untitled

a guest
Nov 7th, 2018
160
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 4.70 KB | None | 0 0
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3.  * linux/kernel/futex_compat.c
  4.  *
  5.  * Futex compatibililty routines.
  6.  *
  7.  * Copyright 2006, Red Hat, Inc., Ingo Molnar
  8.  */
  9.  
  10. #include <linux/linkage.h>
  11. #include <linux/compat.h>
  12. #include <linux/nsproxy.h>
  13. #include <linux/futex.h>
  14. #include <linux/ptrace.h>
  15. #include <linux/syscalls.h>
  16.  
  17. #include <linux/uaccess.h>
  18.  
  19.  
  20. /*
  21.  * Fetch a robust-list pointer. Bit 0 signals PI futexes:
  22.  */
  23. static inline int
  24. fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
  25.            compat_uptr_t __user *head, unsigned int *pi)
  26. {
  27.     if (get_user(*uentry, head))
  28.         return -EFAULT;
  29.  
  30.     *entry = compat_ptr((*uentry) & ~1);
  31.     *pi = (unsigned int)(*uentry) & 1;
  32.  
  33.     return 0;
  34. }
  35.  
  36. static void __user *futex_uaddr(struct robust_list __user *entry,
  37.                 compat_long_t futex_offset)
  38. {
  39.     compat_uptr_t base = ptr_to_compat(entry);
  40.     void __user *uaddr = compat_ptr(base + futex_offset);
  41.  
  42.     return uaddr;
  43. }
  44.  
  45. /*
  46.  * Walk curr->robust_list (very carefully, it's a userspace list!)
  47.  * and mark any locks found there dead, and notify any waiters.
  48.  *
  49.  * We silently return on any sign of list-walking problem.
  50.  */
  51. void compat_exit_robust_list(struct task_struct *curr)
  52. {
  53.     struct compat_robust_list_head __user *head = curr->compat_robust_list;
  54.     struct robust_list __user *entry, *next_entry, *pending;
  55.     unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
  56.     unsigned int uninitialized_var(next_pi);
  57.     compat_uptr_t uentry, next_uentry, upending;
  58.     compat_long_t futex_offset;
  59.     int rc;
  60.  
  61.     if (!futex_cmpxchg_enabled)
  62.         return;
  63.  
  64.     /*
  65.      * Fetch the list head (which was registered earlier, via
  66.      * sys_set_robust_list()):
  67.      */
  68.     if (fetch_robust_entry(&uentry, &entry, &head->list.next, &pi))
  69.         return;
  70.     /*
  71.      * Fetch the relative futex offset:
  72.      */
  73.     if (get_user(futex_offset, &head->futex_offset))
  74.         return;
  75.     /*
  76.      * Fetch any possibly pending lock-add first, and handle it
  77.      * if it exists:
  78.      */
  79.     if (fetch_robust_entry(&upending, &pending,
  80.                    &head->list_op_pending, &pip))
  81.         return;
  82.  
  83.     next_entry = NULL;  /* avoid warning with gcc */
  84.     while (entry != (struct robust_list __user *) &head->list) {
  85.         /*
  86.          * Fetch the next entry in the list before calling
  87.          * handle_futex_death:
  88.          */
  89.         rc = fetch_robust_entry(&next_uentry, &next_entry,
  90.             (compat_uptr_t __user *)&entry->next, &next_pi);
  91.         /*
  92.          * A pending lock might already be on the list, so
  93.          * dont process it twice:
  94.          */
  95.         if (entry != pending) {
  96.             void __user *uaddr = futex_uaddr(entry, futex_offset);
  97.  
  98.             if (handle_futex_death(uaddr, curr, pi))
  99.                 return;
  100.         }
  101.         if (rc)
  102.             return;
  103.         uentry = next_uentry;
  104.         entry = next_entry;
  105.         pi = next_pi;
  106.         /*
  107.          * Avoid excessively long or circular lists:
  108.          */
  109.         if (!--limit)
  110.             break;
  111.  
  112.         cond_resched();
  113.     }
  114.     if (pending) {
  115.         void __user *uaddr = futex_uaddr(pending, futex_offset);
  116.  
  117.         handle_futex_death(uaddr, curr, pip);
  118.     }
  119. }
  120.  
  121. COMPAT_SYSCALL_DEFINE2(set_robust_list,
  122.         struct compat_robust_list_head __user *, head,
  123.         compat_size_t, len)
  124. {
  125.     if (!futex_cmpxchg_enabled)
  126.         return -ENOSYS;
  127.  
  128.     if (unlikely(len != sizeof(*head)))
  129.         return -EINVAL;
  130.  
  131.     current->compat_robust_list = head;
  132.  
  133.     return 0;
  134. }
  135.  
  136. COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
  137.             compat_uptr_t __user *, head_ptr,
  138.             compat_size_t __user *, len_ptr)
  139. {
  140.     struct compat_robust_list_head __user *head;
  141.     unsigned long ret;
  142.     struct task_struct *p;
  143.  
  144.     if (!futex_cmpxchg_enabled)
  145.         return -ENOSYS;
  146.  
  147.     rcu_read_lock();
  148.  
  149.     ret = -ESRCH;
  150.     if (!pid)
  151.         p = current;
  152.     else {
  153.         p = find_task_by_vpid(pid);
  154.         if (!p)
  155.             goto err_unlock;
  156.     }
  157.  
  158.     ret = -EPERM;
  159.     if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
  160.         goto err_unlock;
  161.  
  162.     head = p->compat_robust_list;
  163.     rcu_read_unlock();
  164.  
  165.     if (put_user(sizeof(*head), len_ptr))
  166.         return -EFAULT;
  167.     return put_user(ptr_to_compat(head), head_ptr);
  168.  
  169. err_unlock:
  170.     rcu_read_unlock();
  171.  
  172.     return ret;
  173. }
  174.  
  175. COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
  176.         struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
  177.         u32, val3)
  178. {
  179.     struct timespec ts;
  180.     ktime_t t, *tp = NULL;
  181.     int val2 = 0;
  182.     int cmd = op & FUTEX_CMD_MASK;
  183.  
  184.     if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
  185.               cmd == FUTEX_WAIT_BITSET ||
  186.               cmd == FUTEX_WAIT_REQUEUE_PI)) {
  187.         if (compat_get_timespec(&ts, utime))
  188.             return -EFAULT;
  189.         if (!timespec_valid(&ts))
  190.             return -EINVAL;
  191.  
  192.         t = timespec_to_ktime(ts);
  193.         if (cmd == FUTEX_WAIT)
  194.             t = ktime_add_safe(ktime_get(), t);
  195.         tp = &t;
  196.     }
  197.     if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
  198.         cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
  199.         val2 = (int) (unsigned long) utime;
  200.  
  201.     return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
  202. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement