.. | .. |
---|
205 | 205 | * |
---|
206 | 206 | * Memory ordering: |
---|
207 | 207 | * Most ordering is enforced by using spin_lock() and spin_unlock(). |
---|
208 | | - * The special case is use_global_lock: |
---|
| 208 | + * |
---|
| 209 | + * Exceptions: |
---|
| 210 | + * 1) use_global_lock: (SEM_BARRIER_1) |
---|
209 | 211 | * Setting it from non-zero to 0 is a RELEASE, this is ensured by |
---|
210 | | - * using smp_store_release(). |
---|
| 212 | + * using smp_store_release(): Immediately after setting it to 0, |
---|
| 213 | + * a simple op can start. |
---|
211 | 214 | * Testing if it is non-zero is an ACQUIRE, this is ensured by using |
---|
212 | 215 | * smp_load_acquire(). |
---|
213 | 216 | * Setting it from 0 to non-zero must be ordered with regards to |
---|
214 | 217 | * this smp_load_acquire(), this is guaranteed because the smp_load_acquire() |
---|
215 | 218 | * is inside a spin_lock() and after a write from 0 to non-zero a |
---|
216 | 219 | * spin_lock()+spin_unlock() is done. |
---|
| 220 | + * |
---|
| 221 | + * 2) queue.status: (SEM_BARRIER_2) |
---|
| 222 | + * Initialization is done while holding sem_lock(), so no further barrier is |
---|
| 223 | + * required. |
---|
| 224 | + * Setting it to a result code is a RELEASE, this is ensured by both a |
---|
| 225 | + * smp_store_release() (for case a) and while holding sem_lock() |
---|
| 226 | + * (for case b). |
---|
| 227 | + * The AQUIRE when reading the result code without holding sem_lock() is |
---|
| 228 | + * achieved by using READ_ONCE() + smp_acquire__after_ctrl_dep(). |
---|
| 229 | + * (case a above). |
---|
| 230 | + * Reading the result code while holding sem_lock() needs no further barriers, |
---|
| 231 | + * the locks inside sem_lock() enforce ordering (case b above) |
---|
| 232 | + * |
---|
| 233 | + * 3) current->state: |
---|
| 234 | + * current->state is set to TASK_INTERRUPTIBLE while holding sem_lock(). |
---|
| 235 | + * The wakeup is handled using the wake_q infrastructure. wake_q wakeups may |
---|
| 236 | + * happen immediately after calling wake_q_add. As wake_q_add_safe() is called |
---|
| 237 | + * when holding sem_lock(), no further barriers are required. |
---|
| 238 | + * |
---|
| 239 | + * See also ipc/mqueue.c for more details on the covered races. |
---|
217 | 240 | */ |
---|
218 | 241 | |
---|
219 | 242 | #define sc_semmsl sem_ctls[0] |
---|
.. | .. |
---|
344 | 367 | return; |
---|
345 | 368 | } |
---|
346 | 369 | if (sma->use_global_lock == 1) { |
---|
347 | | - /* |
---|
348 | | - * Immediately after setting use_global_lock to 0, |
---|
349 | | - * a simple op can start. Thus: all memory writes |
---|
350 | | - * performed by the current operation must be visible |
---|
351 | | - * before we set use_global_lock to 0. |
---|
352 | | - */ |
---|
| 370 | + |
---|
| 371 | + /* See SEM_BARRIER_1 for purpose/pairing */ |
---|
353 | 372 | smp_store_release(&sma->use_global_lock, 0); |
---|
354 | 373 | } else { |
---|
355 | 374 | sma->use_global_lock--; |
---|
.. | .. |
---|
400 | 419 | */ |
---|
401 | 420 | spin_lock(&sem->lock); |
---|
402 | 421 | |
---|
403 | | - /* pairs with smp_store_release() */ |
---|
| 422 | + /* see SEM_BARRIER_1 for purpose/pairing */ |
---|
404 | 423 | if (!smp_load_acquire(&sma->use_global_lock)) { |
---|
405 | 424 | /* fast path successful! */ |
---|
406 | 425 | return sops->sem_num; |
---|
.. | .. |
---|
488 | 507 | static struct sem_array *sem_alloc(size_t nsems) |
---|
489 | 508 | { |
---|
490 | 509 | struct sem_array *sma; |
---|
491 | | - size_t size; |
---|
492 | 510 | |
---|
493 | 511 | if (nsems > (INT_MAX - sizeof(*sma)) / sizeof(sma->sems[0])) |
---|
494 | 512 | return NULL; |
---|
495 | 513 | |
---|
496 | | - size = sizeof(*sma) + nsems * sizeof(sma->sems[0]); |
---|
497 | | - sma = kvmalloc(size, GFP_KERNEL); |
---|
| 514 | + sma = kvzalloc(struct_size(sma, sems, nsems), GFP_KERNEL_ACCOUNT); |
---|
498 | 515 | if (unlikely(!sma)) |
---|
499 | 516 | return NULL; |
---|
500 | | - |
---|
501 | | - memset(sma, 0, size); |
---|
502 | 517 | |
---|
503 | 518 | return sma; |
---|
504 | 519 | } |
---|
.. | .. |
---|
570 | 585 | /* |
---|
571 | 586 | * Called with sem_ids.rwsem and ipcp locked. |
---|
572 | 587 | */ |
---|
573 | | -static inline int sem_more_checks(struct kern_ipc_perm *ipcp, |
---|
574 | | - struct ipc_params *params) |
---|
| 588 | +static int sem_more_checks(struct kern_ipc_perm *ipcp, struct ipc_params *params) |
---|
575 | 589 | { |
---|
576 | 590 | struct sem_array *sma; |
---|
577 | 591 | |
---|
.. | .. |
---|
770 | 784 | static inline void wake_up_sem_queue_prepare(struct sem_queue *q, int error, |
---|
771 | 785 | struct wake_q_head *wake_q) |
---|
772 | 786 | { |
---|
773 | | - wake_q_add(wake_q, q->sleeper); |
---|
774 | | - /* |
---|
775 | | - * Rely on the above implicit barrier, such that we can |
---|
776 | | - * ensure that we hold reference to the task before setting |
---|
777 | | - * q->status. Otherwise we could race with do_exit if the |
---|
778 | | - * task is awoken by an external event before calling |
---|
779 | | - * wake_up_process(). |
---|
780 | | - */ |
---|
781 | | - WRITE_ONCE(q->status, error); |
---|
| 787 | + struct task_struct *sleeper; |
---|
| 788 | + |
---|
| 789 | + sleeper = get_task_struct(q->sleeper); |
---|
| 790 | + |
---|
| 791 | + /* see SEM_BARRIER_2 for purpuse/pairing */ |
---|
| 792 | + smp_store_release(&q->status, error); |
---|
| 793 | + |
---|
| 794 | + wake_q_add_safe(wake_q, sleeper); |
---|
782 | 795 | } |
---|
783 | 796 | |
---|
784 | 797 | static void unlink_queue(struct sem_array *sma, struct sem_queue *q) |
---|
.. | .. |
---|
1634 | 1647 | return err; |
---|
1635 | 1648 | } |
---|
1636 | 1649 | |
---|
1637 | | -long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg) |
---|
| 1650 | +static long ksys_semctl(int semid, int semnum, int cmd, unsigned long arg, int version) |
---|
1638 | 1651 | { |
---|
1639 | | - int version; |
---|
1640 | 1652 | struct ipc_namespace *ns; |
---|
1641 | 1653 | void __user *p = (void __user *)arg; |
---|
1642 | 1654 | struct semid64_ds semid64; |
---|
.. | .. |
---|
1645 | 1657 | if (semid < 0) |
---|
1646 | 1658 | return -EINVAL; |
---|
1647 | 1659 | |
---|
1648 | | - version = ipc_parse_version(&cmd); |
---|
1649 | 1660 | ns = current->nsproxy->ipc_ns; |
---|
1650 | 1661 | |
---|
1651 | 1662 | switch (cmd) { |
---|
.. | .. |
---|
1682 | 1693 | case IPC_SET: |
---|
1683 | 1694 | if (copy_semid_from_user(&semid64, p, version)) |
---|
1684 | 1695 | return -EFAULT; |
---|
| 1696 | + fallthrough; |
---|
1685 | 1697 | case IPC_RMID: |
---|
1686 | 1698 | return semctl_down(ns, semid, cmd, &semid64); |
---|
1687 | 1699 | default: |
---|
.. | .. |
---|
1691 | 1703 | |
---|
1692 | 1704 | SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) |
---|
1693 | 1705 | { |
---|
1694 | | - return ksys_semctl(semid, semnum, cmd, arg); |
---|
| 1706 | + return ksys_semctl(semid, semnum, cmd, arg, IPC_64); |
---|
1695 | 1707 | } |
---|
| 1708 | + |
---|
| 1709 | +#ifdef CONFIG_ARCH_WANT_IPC_PARSE_VERSION |
---|
| 1710 | +long ksys_old_semctl(int semid, int semnum, int cmd, unsigned long arg) |
---|
| 1711 | +{ |
---|
| 1712 | + int version = ipc_parse_version(&cmd); |
---|
| 1713 | + |
---|
| 1714 | + return ksys_semctl(semid, semnum, cmd, arg, version); |
---|
| 1715 | +} |
---|
| 1716 | + |
---|
| 1717 | +SYSCALL_DEFINE4(old_semctl, int, semid, int, semnum, int, cmd, unsigned long, arg) |
---|
| 1718 | +{ |
---|
| 1719 | + return ksys_old_semctl(semid, semnum, cmd, arg); |
---|
| 1720 | +} |
---|
| 1721 | +#endif |
---|
1696 | 1722 | |
---|
1697 | 1723 | #ifdef CONFIG_COMPAT |
---|
1698 | 1724 | |
---|
1699 | 1725 | struct compat_semid_ds { |
---|
1700 | 1726 | struct compat_ipc_perm sem_perm; |
---|
1701 | | - compat_time_t sem_otime; |
---|
1702 | | - compat_time_t sem_ctime; |
---|
| 1727 | + old_time32_t sem_otime; |
---|
| 1728 | + old_time32_t sem_ctime; |
---|
1703 | 1729 | compat_uptr_t sem_base; |
---|
1704 | 1730 | compat_uptr_t sem_pending; |
---|
1705 | 1731 | compat_uptr_t sem_pending_last; |
---|
.. | .. |
---|
1744 | 1770 | } |
---|
1745 | 1771 | } |
---|
1746 | 1772 | |
---|
1747 | | -long compat_ksys_semctl(int semid, int semnum, int cmd, int arg) |
---|
| 1773 | +static long compat_ksys_semctl(int semid, int semnum, int cmd, int arg, int version) |
---|
1748 | 1774 | { |
---|
1749 | 1775 | void __user *p = compat_ptr(arg); |
---|
1750 | 1776 | struct ipc_namespace *ns; |
---|
1751 | 1777 | struct semid64_ds semid64; |
---|
1752 | | - int version = compat_ipc_parse_version(&cmd); |
---|
1753 | 1778 | int err; |
---|
1754 | 1779 | |
---|
1755 | 1780 | ns = current->nsproxy->ipc_ns; |
---|
.. | .. |
---|
1782 | 1807 | case IPC_SET: |
---|
1783 | 1808 | if (copy_compat_semid_from_user(&semid64, p, version)) |
---|
1784 | 1809 | return -EFAULT; |
---|
1785 | | - /* fallthru */ |
---|
| 1810 | + fallthrough; |
---|
1786 | 1811 | case IPC_RMID: |
---|
1787 | 1812 | return semctl_down(ns, semid, cmd, &semid64); |
---|
1788 | 1813 | default: |
---|
.. | .. |
---|
1792 | 1817 | |
---|
1793 | 1818 | COMPAT_SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, int, arg) |
---|
1794 | 1819 | { |
---|
1795 | | - return compat_ksys_semctl(semid, semnum, cmd, arg); |
---|
| 1820 | + return compat_ksys_semctl(semid, semnum, cmd, arg, IPC_64); |
---|
1796 | 1821 | } |
---|
| 1822 | + |
---|
| 1823 | +#ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION |
---|
| 1824 | +long compat_ksys_old_semctl(int semid, int semnum, int cmd, int arg) |
---|
| 1825 | +{ |
---|
| 1826 | + int version = compat_ipc_parse_version(&cmd); |
---|
| 1827 | + |
---|
| 1828 | + return compat_ksys_semctl(semid, semnum, cmd, arg, version); |
---|
| 1829 | +} |
---|
| 1830 | + |
---|
| 1831 | +COMPAT_SYSCALL_DEFINE4(old_semctl, int, semid, int, semnum, int, cmd, int, arg) |
---|
| 1832 | +{ |
---|
| 1833 | + return compat_ksys_old_semctl(semid, semnum, cmd, arg); |
---|
| 1834 | +} |
---|
| 1835 | +#endif |
---|
1797 | 1836 | #endif |
---|
1798 | 1837 | |
---|
1799 | 1838 | /* If the task doesn't already have a undo_list, then allocate one |
---|
.. | .. |
---|
1813 | 1852 | |
---|
1814 | 1853 | undo_list = current->sysvsem.undo_list; |
---|
1815 | 1854 | if (!undo_list) { |
---|
1816 | | - undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL); |
---|
| 1855 | + undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL_ACCOUNT); |
---|
1817 | 1856 | if (undo_list == NULL) |
---|
1818 | 1857 | return -ENOMEM; |
---|
1819 | 1858 | spin_lock_init(&undo_list->lock); |
---|
.. | .. |
---|
1830 | 1869 | { |
---|
1831 | 1870 | struct sem_undo *un; |
---|
1832 | 1871 | |
---|
1833 | | - list_for_each_entry_rcu(un, &ulp->list_proc, list_proc) { |
---|
| 1872 | + list_for_each_entry_rcu(un, &ulp->list_proc, list_proc, |
---|
| 1873 | + spin_is_locked(&ulp->lock)) { |
---|
1834 | 1874 | if (un->semid == semid) |
---|
1835 | 1875 | return un; |
---|
1836 | 1876 | } |
---|
.. | .. |
---|
1897 | 1937 | rcu_read_unlock(); |
---|
1898 | 1938 | |
---|
1899 | 1939 | /* step 2: allocate new undo structure */ |
---|
1900 | | - new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL); |
---|
| 1940 | + new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL_ACCOUNT); |
---|
1901 | 1941 | if (!new) { |
---|
1902 | 1942 | ipc_rcu_putref(&sma->sem_perm, sem_rcu_free); |
---|
1903 | 1943 | return ERR_PTR(-ENOMEM); |
---|
.. | .. |
---|
2125 | 2165 | } |
---|
2126 | 2166 | |
---|
2127 | 2167 | do { |
---|
| 2168 | + /* memory ordering ensured by the lock in sem_lock() */ |
---|
2128 | 2169 | WRITE_ONCE(queue.status, -EINTR); |
---|
2129 | 2170 | queue.sleeper = current; |
---|
2130 | 2171 | |
---|
| 2172 | + /* memory ordering is ensured by the lock in sem_lock() */ |
---|
2131 | 2173 | __set_current_state(TASK_INTERRUPTIBLE); |
---|
2132 | 2174 | sem_unlock(sma, locknum); |
---|
2133 | 2175 | rcu_read_unlock(); |
---|
.. | .. |
---|
2148 | 2190 | * scenarios where we were awakened externally, during the |
---|
2149 | 2191 | * window between wake_q_add() and wake_up_q(). |
---|
2150 | 2192 | */ |
---|
| 2193 | + rcu_read_lock(); |
---|
2151 | 2194 | error = READ_ONCE(queue.status); |
---|
2152 | 2195 | if (error != -EINTR) { |
---|
2153 | | - /* |
---|
2154 | | - * User space could assume that semop() is a memory |
---|
2155 | | - * barrier: Without the mb(), the cpu could |
---|
2156 | | - * speculatively read in userspace stale data that was |
---|
2157 | | - * overwritten by the previous owner of the semaphore. |
---|
2158 | | - */ |
---|
2159 | | - smp_mb(); |
---|
| 2196 | + /* see SEM_BARRIER_2 for purpose/pairing */ |
---|
| 2197 | + smp_acquire__after_ctrl_dep(); |
---|
| 2198 | + rcu_read_unlock(); |
---|
2160 | 2199 | goto out_free; |
---|
2161 | 2200 | } |
---|
2162 | 2201 | |
---|
2163 | | - rcu_read_lock(); |
---|
2164 | 2202 | locknum = sem_lock(sma, sops, nsops); |
---|
2165 | 2203 | |
---|
2166 | 2204 | if (!ipc_valid_object(&sma->sem_perm)) |
---|
2167 | 2205 | goto out_unlock_free; |
---|
2168 | 2206 | |
---|
| 2207 | + /* |
---|
| 2208 | + * No necessity for any barrier: We are protect by sem_lock() |
---|
| 2209 | + */ |
---|
2169 | 2210 | error = READ_ONCE(queue.status); |
---|
2170 | 2211 | |
---|
2171 | 2212 | /* |
---|
.. | .. |
---|
2214 | 2255 | #ifdef CONFIG_COMPAT_32BIT_TIME |
---|
2215 | 2256 | long compat_ksys_semtimedop(int semid, struct sembuf __user *tsems, |
---|
2216 | 2257 | unsigned int nsops, |
---|
2217 | | - const struct compat_timespec __user *timeout) |
---|
| 2258 | + const struct old_timespec32 __user *timeout) |
---|
2218 | 2259 | { |
---|
2219 | 2260 | if (timeout) { |
---|
2220 | 2261 | struct timespec64 ts; |
---|
2221 | | - if (compat_get_timespec64(&ts, timeout)) |
---|
| 2262 | + if (get_old_timespec32(&ts, timeout)) |
---|
2222 | 2263 | return -EFAULT; |
---|
2223 | 2264 | return do_semtimedop(semid, tsems, nsops, &ts); |
---|
2224 | 2265 | } |
---|
2225 | 2266 | return do_semtimedop(semid, tsems, nsops, NULL); |
---|
2226 | 2267 | } |
---|
2227 | 2268 | |
---|
2228 | | -COMPAT_SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsems, |
---|
| 2269 | +SYSCALL_DEFINE4(semtimedop_time32, int, semid, struct sembuf __user *, tsems, |
---|
2229 | 2270 | unsigned int, nsops, |
---|
2230 | | - const struct compat_timespec __user *, timeout) |
---|
| 2271 | + const struct old_timespec32 __user *, timeout) |
---|
2231 | 2272 | { |
---|
2232 | 2273 | return compat_ksys_semtimedop(semid, tsems, nsops, timeout); |
---|
2233 | 2274 | } |
---|