futex_compat.c 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /*
  2. * linux/kernel/futex_compat.c
  3. *
  4. * Futex compatibililty routines.
  5. *
  6. * Copyright 2006, Red Hat, Inc., Ingo Molnar
  7. */
  8. #include <linux/linkage.h>
  9. #include <linux/compat.h>
  10. #include <linux/futex.h>
  11. #include <asm/uaccess.h>
  12. /*
  13. * Walk curr->robust_list (very carefully, it's a userspace list!)
  14. * and mark any locks found there dead, and notify any waiters.
  15. *
  16. * We silently return on any sign of list-walking problem.
  17. */
  18. void compat_exit_robust_list(struct task_struct *curr)
  19. {
  20. struct compat_robust_list_head __user *head = curr->compat_robust_list;
  21. struct robust_list __user *entry, *pending;
  22. compat_uptr_t uentry, upending;
  23. unsigned int limit = ROBUST_LIST_LIMIT;
  24. compat_long_t futex_offset;
  25. /*
  26. * Fetch the list head (which was registered earlier, via
  27. * sys_set_robust_list()):
  28. */
  29. if (get_user(uentry, &head->list.next))
  30. return;
  31. entry = compat_ptr(uentry);
  32. /*
  33. * Fetch the relative futex offset:
  34. */
  35. if (get_user(futex_offset, &head->futex_offset))
  36. return;
  37. /*
  38. * Fetch any possibly pending lock-add first, and handle it
  39. * if it exists:
  40. */
  41. if (get_user(upending, &head->list_op_pending))
  42. return;
  43. pending = compat_ptr(upending);
  44. if (upending)
  45. handle_futex_death((void *)pending + futex_offset, curr);
  46. while (compat_ptr(uentry) != &head->list) {
  47. /*
  48. * A pending lock might already be on the list, so
  49. * dont process it twice:
  50. */
  51. if (entry != pending)
  52. if (handle_futex_death((void *)entry + futex_offset,
  53. curr))
  54. return;
  55. /*
  56. * Fetch the next entry in the list:
  57. */
  58. if (get_user(uentry, (compat_uptr_t *)&entry->next))
  59. return;
  60. entry = compat_ptr(uentry);
  61. /*
  62. * Avoid excessively long or circular lists:
  63. */
  64. if (!--limit)
  65. break;
  66. cond_resched();
  67. }
  68. }
  69. asmlinkage long
  70. compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
  71. compat_size_t len)
  72. {
  73. if (unlikely(len != sizeof(*head)))
  74. return -EINVAL;
  75. current->compat_robust_list = head;
  76. return 0;
  77. }
  78. asmlinkage long
  79. compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr,
  80. compat_size_t __user *len_ptr)
  81. {
  82. struct compat_robust_list_head *head;
  83. unsigned long ret;
  84. if (!pid)
  85. head = current->compat_robust_list;
  86. else {
  87. struct task_struct *p;
  88. ret = -ESRCH;
  89. read_lock(&tasklist_lock);
  90. p = find_task_by_pid(pid);
  91. if (!p)
  92. goto err_unlock;
  93. ret = -EPERM;
  94. if ((current->euid != p->euid) && (current->euid != p->uid) &&
  95. !capable(CAP_SYS_PTRACE))
  96. goto err_unlock;
  97. head = p->compat_robust_list;
  98. read_unlock(&tasklist_lock);
  99. }
  100. if (put_user(sizeof(*head), len_ptr))
  101. return -EFAULT;
  102. return put_user(ptr_to_compat(head), head_ptr);
  103. err_unlock:
  104. read_unlock(&tasklist_lock);
  105. return ret;
  106. }
  107. asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val,
  108. struct compat_timespec __user *utime, u32 __user *uaddr2,
  109. u32 val3)
  110. {
  111. struct timespec t;
  112. unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
  113. int val2 = 0;
  114. if (utime && (op == FUTEX_WAIT || op == FUTEX_LOCK_PI)) {
  115. if (get_compat_timespec(&t, utime))
  116. return -EFAULT;
  117. if (!timespec_valid(&t))
  118. return -EINVAL;
  119. if (op == FUTEX_WAIT)
  120. timeout = timespec_to_jiffies(&t) + 1;
  121. else {
  122. timeout = t.tv_sec;
  123. val2 = t.tv_nsec;
  124. }
  125. }
  126. if (op == FUTEX_REQUEUE || op == FUTEX_CMP_REQUEUE)
  127. val2 = (int) (unsigned long) utime;
  128. return do_futex(uaddr, op, val, timeout, uaddr2, val2, val3);
  129. }