diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 81 |
1 files changed, 50 insertions, 31 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index e10c5c8786a6..7c6cbabe52b3 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -92,11 +92,12 @@ struct futex_pi_state { | |||
92 | * A futex_q has a woken state, just like tasks have TASK_RUNNING. | 92 | * A futex_q has a woken state, just like tasks have TASK_RUNNING. |
93 | * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0. | 93 | * It is considered woken when plist_node_empty(&q->list) || q->lock_ptr == 0. |
94 | * The order of wakup is always to make the first condition true, then | 94 | * The order of wakup is always to make the first condition true, then |
95 | * wake up q->waiters, then make the second condition true. | 95 | * wake up q->waiter, then make the second condition true. |
96 | */ | 96 | */ |
97 | struct futex_q { | 97 | struct futex_q { |
98 | struct plist_node list; | 98 | struct plist_node list; |
99 | wait_queue_head_t waiters; | 99 | /* There can only be a single waiter */ |
100 | wait_queue_head_t waiter; | ||
100 | 101 | ||
101 | /* Which hash list lock to use: */ | 102 | /* Which hash list lock to use: */ |
102 | spinlock_t *lock_ptr; | 103 | spinlock_t *lock_ptr; |
@@ -405,13 +406,20 @@ static void free_pi_state(struct futex_pi_state *pi_state) | |||
405 | static struct task_struct * futex_find_get_task(pid_t pid) | 406 | static struct task_struct * futex_find_get_task(pid_t pid) |
406 | { | 407 | { |
407 | struct task_struct *p; | 408 | struct task_struct *p; |
409 | const struct cred *cred = current_cred(), *pcred; | ||
408 | 410 | ||
409 | rcu_read_lock(); | 411 | rcu_read_lock(); |
410 | p = find_task_by_vpid(pid); | 412 | p = find_task_by_vpid(pid); |
411 | if (!p || ((current->euid != p->euid) && (current->euid != p->uid))) | 413 | if (!p) { |
412 | p = ERR_PTR(-ESRCH); | 414 | p = ERR_PTR(-ESRCH); |
413 | else | 415 | } else { |
414 | get_task_struct(p); | 416 | pcred = __task_cred(p); |
417 | if (cred->euid != pcred->euid && | ||
418 | cred->euid != pcred->uid) | ||
419 | p = ERR_PTR(-ESRCH); | ||
420 | else | ||
421 | get_task_struct(p); | ||
422 | } | ||
415 | 423 | ||
416 | rcu_read_unlock(); | 424 | rcu_read_unlock(); |
417 | 425 | ||
@@ -573,7 +581,7 @@ static void wake_futex(struct futex_q *q) | |||
573 | * The lock in wake_up_all() is a crucial memory barrier after the | 581 | * The lock in wake_up_all() is a crucial memory barrier after the |
574 | * plist_del() and also before assigning to q->lock_ptr. | 582 | * plist_del() and also before assigning to q->lock_ptr. |
575 | */ | 583 | */ |
576 | wake_up_all(&q->waiters); | 584 | wake_up(&q->waiter); |
577 | /* | 585 | /* |
578 | * The waiting task can free the futex_q as soon as this is written, | 586 | * The waiting task can free the futex_q as soon as this is written, |
579 | * without taking any locks. This must come last. | 587 | * without taking any locks. This must come last. |
@@ -930,7 +938,7 @@ static inline struct futex_hash_bucket *queue_lock(struct futex_q *q) | |||
930 | { | 938 | { |
931 | struct futex_hash_bucket *hb; | 939 | struct futex_hash_bucket *hb; |
932 | 940 | ||
933 | init_waitqueue_head(&q->waiters); | 941 | init_waitqueue_head(&q->waiter); |
934 | 942 | ||
935 | get_futex_key_refs(&q->key); | 943 | get_futex_key_refs(&q->key); |
936 | hb = hash_futex(&q->key); | 944 | hb = hash_futex(&q->key); |
@@ -1142,12 +1150,13 @@ handle_fault: | |||
1142 | * In case we must use restart_block to restart a futex_wait, | 1150 | * In case we must use restart_block to restart a futex_wait, |
1143 | * we encode in the 'flags' shared capability | 1151 | * we encode in the 'flags' shared capability |
1144 | */ | 1152 | */ |
1145 | #define FLAGS_SHARED 1 | 1153 | #define FLAGS_SHARED 0x01 |
1154 | #define FLAGS_CLOCKRT 0x02 | ||
1146 | 1155 | ||
1147 | static long futex_wait_restart(struct restart_block *restart); | 1156 | static long futex_wait_restart(struct restart_block *restart); |
1148 | 1157 | ||
1149 | static int futex_wait(u32 __user *uaddr, int fshared, | 1158 | static int futex_wait(u32 __user *uaddr, int fshared, |
1150 | u32 val, ktime_t *abs_time, u32 bitset) | 1159 | u32 val, ktime_t *abs_time, u32 bitset, int clockrt) |
1151 | { | 1160 | { |
1152 | struct task_struct *curr = current; | 1161 | struct task_struct *curr = current; |
1153 | DECLARE_WAITQUEUE(wait, curr); | 1162 | DECLARE_WAITQUEUE(wait, curr); |
@@ -1220,7 +1229,7 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
1220 | 1229 | ||
1221 | /* add_wait_queue is the barrier after __set_current_state. */ | 1230 | /* add_wait_queue is the barrier after __set_current_state. */ |
1222 | __set_current_state(TASK_INTERRUPTIBLE); | 1231 | __set_current_state(TASK_INTERRUPTIBLE); |
1223 | add_wait_queue(&q.waiters, &wait); | 1232 | add_wait_queue(&q.waiter, &wait); |
1224 | /* | 1233 | /* |
1225 | * !plist_node_empty() is safe here without any lock. | 1234 | * !plist_node_empty() is safe here without any lock. |
1226 | * q.lock_ptr != 0 is not safe, because of ordering against wakeup. | 1235 | * q.lock_ptr != 0 is not safe, because of ordering against wakeup. |
@@ -1233,8 +1242,10 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
1233 | slack = current->timer_slack_ns; | 1242 | slack = current->timer_slack_ns; |
1234 | if (rt_task(current)) | 1243 | if (rt_task(current)) |
1235 | slack = 0; | 1244 | slack = 0; |
1236 | hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC, | 1245 | hrtimer_init_on_stack(&t.timer, |
1237 | HRTIMER_MODE_ABS); | 1246 | clockrt ? CLOCK_REALTIME : |
1247 | CLOCK_MONOTONIC, | ||
1248 | HRTIMER_MODE_ABS); | ||
1238 | hrtimer_init_sleeper(&t, current); | 1249 | hrtimer_init_sleeper(&t, current); |
1239 | hrtimer_set_expires_range_ns(&t.timer, *abs_time, slack); | 1250 | hrtimer_set_expires_range_ns(&t.timer, *abs_time, slack); |
1240 | 1251 | ||
@@ -1289,6 +1300,8 @@ static int futex_wait(u32 __user *uaddr, int fshared, | |||
1289 | 1300 | ||
1290 | if (fshared) | 1301 | if (fshared) |
1291 | restart->futex.flags |= FLAGS_SHARED; | 1302 | restart->futex.flags |= FLAGS_SHARED; |
1303 | if (clockrt) | ||
1304 | restart->futex.flags |= FLAGS_CLOCKRT; | ||
1292 | return -ERESTART_RESTARTBLOCK; | 1305 | return -ERESTART_RESTARTBLOCK; |
1293 | } | 1306 | } |
1294 | 1307 | ||
@@ -1312,7 +1325,8 @@ static long futex_wait_restart(struct restart_block *restart) | |||
1312 | if (restart->futex.flags & FLAGS_SHARED) | 1325 | if (restart->futex.flags & FLAGS_SHARED) |
1313 | fshared = 1; | 1326 | fshared = 1; |
1314 | return (long)futex_wait(uaddr, fshared, restart->futex.val, &t, | 1327 | return (long)futex_wait(uaddr, fshared, restart->futex.val, &t, |
1315 | restart->futex.bitset); | 1328 | restart->futex.bitset, |
1329 | restart->futex.flags & FLAGS_CLOCKRT); | ||
1316 | } | 1330 | } |
1317 | 1331 | ||
1318 | 1332 | ||
@@ -1558,12 +1572,11 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, | |||
1558 | 1572 | ||
1559 | uaddr_faulted: | 1573 | uaddr_faulted: |
1560 | /* | 1574 | /* |
1561 | * We have to r/w *(int __user *)uaddr, but we can't modify it | 1575 | * We have to r/w *(int __user *)uaddr, and we have to modify it |
1562 | * non-atomically. Therefore, if get_user below is not | 1576 | * atomically. Therefore, if we continue to fault after get_user() |
1563 | * enough, we need to handle the fault ourselves, while | 1577 | * below, we need to handle the fault ourselves, while still holding |
1564 | * still holding the mmap_sem. | 1578 | * the mmap_sem. This can occur if the uaddr is under contention as |
1565 | * | 1579 | * we have to drop the mmap_sem in order to call get_user(). |
1566 | * ... and hb->lock. :-) --ANK | ||
1567 | */ | 1580 | */ |
1568 | queue_unlock(&q, hb); | 1581 | queue_unlock(&q, hb); |
1569 | 1582 | ||
@@ -1575,7 +1588,7 @@ static int futex_lock_pi(u32 __user *uaddr, int fshared, | |||
1575 | } | 1588 | } |
1576 | 1589 | ||
1577 | ret = get_user(uval, uaddr); | 1590 | ret = get_user(uval, uaddr); |
1578 | if (!ret && (uval != -EFAULT)) | 1591 | if (!ret) |
1579 | goto retry; | 1592 | goto retry; |
1580 | 1593 | ||
1581 | if (to) | 1594 | if (to) |
@@ -1669,12 +1682,11 @@ out: | |||
1669 | 1682 | ||
1670 | pi_faulted: | 1683 | pi_faulted: |
1671 | /* | 1684 | /* |
1672 | * We have to r/w *(int __user *)uaddr, but we can't modify it | 1685 | * We have to r/w *(int __user *)uaddr, and we have to modify it |
1673 | * non-atomically. Therefore, if get_user below is not | 1686 | * atomically. Therefore, if we continue to fault after get_user() |
1674 | * enough, we need to handle the fault ourselves, while | 1687 | * below, we need to handle the fault ourselves, while still holding |
1675 | * still holding the mmap_sem. | 1688 | * the mmap_sem. This can occur if the uaddr is under contention as |
1676 | * | 1689 | * we have to drop the mmap_sem in order to call get_user(). |
1677 | * ... and hb->lock. --ANK | ||
1678 | */ | 1690 | */ |
1679 | spin_unlock(&hb->lock); | 1691 | spin_unlock(&hb->lock); |
1680 | 1692 | ||
@@ -1687,7 +1699,7 @@ pi_faulted: | |||
1687 | } | 1699 | } |
1688 | 1700 | ||
1689 | ret = get_user(uval, uaddr); | 1701 | ret = get_user(uval, uaddr); |
1690 | if (!ret && (uval != -EFAULT)) | 1702 | if (!ret) |
1691 | goto retry; | 1703 | goto retry; |
1692 | 1704 | ||
1693 | return ret; | 1705 | return ret; |
@@ -1742,6 +1754,7 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr, | |||
1742 | { | 1754 | { |
1743 | struct robust_list_head __user *head; | 1755 | struct robust_list_head __user *head; |
1744 | unsigned long ret; | 1756 | unsigned long ret; |
1757 | const struct cred *cred = current_cred(), *pcred; | ||
1745 | 1758 | ||
1746 | if (!futex_cmpxchg_enabled) | 1759 | if (!futex_cmpxchg_enabled) |
1747 | return -ENOSYS; | 1760 | return -ENOSYS; |
@@ -1757,8 +1770,10 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr, | |||
1757 | if (!p) | 1770 | if (!p) |
1758 | goto err_unlock; | 1771 | goto err_unlock; |
1759 | ret = -EPERM; | 1772 | ret = -EPERM; |
1760 | if ((current->euid != p->euid) && (current->euid != p->uid) && | 1773 | pcred = __task_cred(p); |
1761 | !capable(CAP_SYS_PTRACE)) | 1774 | if (cred->euid != pcred->euid && |
1775 | cred->euid != pcred->uid && | ||
1776 | !capable(CAP_SYS_PTRACE)) | ||
1762 | goto err_unlock; | 1777 | goto err_unlock; |
1763 | head = p->robust_list; | 1778 | head = p->robust_list; |
1764 | rcu_read_unlock(); | 1779 | rcu_read_unlock(); |
@@ -1905,18 +1920,22 @@ void exit_robust_list(struct task_struct *curr) | |||
1905 | long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, | 1920 | long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout, |
1906 | u32 __user *uaddr2, u32 val2, u32 val3) | 1921 | u32 __user *uaddr2, u32 val2, u32 val3) |
1907 | { | 1922 | { |
1908 | int ret = -ENOSYS; | 1923 | int clockrt, ret = -ENOSYS; |
1909 | int cmd = op & FUTEX_CMD_MASK; | 1924 | int cmd = op & FUTEX_CMD_MASK; |
1910 | int fshared = 0; | 1925 | int fshared = 0; |
1911 | 1926 | ||
1912 | if (!(op & FUTEX_PRIVATE_FLAG)) | 1927 | if (!(op & FUTEX_PRIVATE_FLAG)) |
1913 | fshared = 1; | 1928 | fshared = 1; |
1914 | 1929 | ||
1930 | clockrt = op & FUTEX_CLOCK_REALTIME; | ||
1931 | if (clockrt && cmd != FUTEX_WAIT_BITSET) | ||
1932 | return -ENOSYS; | ||
1933 | |||
1915 | switch (cmd) { | 1934 | switch (cmd) { |
1916 | case FUTEX_WAIT: | 1935 | case FUTEX_WAIT: |
1917 | val3 = FUTEX_BITSET_MATCH_ANY; | 1936 | val3 = FUTEX_BITSET_MATCH_ANY; |
1918 | case FUTEX_WAIT_BITSET: | 1937 | case FUTEX_WAIT_BITSET: |
1919 | ret = futex_wait(uaddr, fshared, val, timeout, val3); | 1938 | ret = futex_wait(uaddr, fshared, val, timeout, val3, clockrt); |
1920 | break; | 1939 | break; |
1921 | case FUTEX_WAKE: | 1940 | case FUTEX_WAKE: |
1922 | val3 = FUTEX_BITSET_MATCH_ANY; | 1941 | val3 = FUTEX_BITSET_MATCH_ANY; |