diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 65 |
1 files changed, 24 insertions, 41 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 75675b9bf6df..fe83343da24b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -248,7 +248,11 @@ static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node) | |||
248 | struct page *page = alloc_pages_node(node, THREADINFO_GFP, | 248 | struct page *page = alloc_pages_node(node, THREADINFO_GFP, |
249 | THREAD_SIZE_ORDER); | 249 | THREAD_SIZE_ORDER); |
250 | 250 | ||
251 | return page ? page_address(page) : NULL; | 251 | if (likely(page)) { |
252 | tsk->stack = page_address(page); | ||
253 | return tsk->stack; | ||
254 | } | ||
255 | return NULL; | ||
252 | #endif | 256 | #endif |
253 | } | 257 | } |
254 | 258 | ||
@@ -1712,31 +1716,6 @@ const struct file_operations pidfd_fops = { | |||
1712 | #endif | 1716 | #endif |
1713 | }; | 1717 | }; |
1714 | 1718 | ||
1715 | /** | ||
1716 | * pidfd_create() - Create a new pid file descriptor. | ||
1717 | * | ||
1718 | * @pid: struct pid that the pidfd will reference | ||
1719 | * | ||
1720 | * This creates a new pid file descriptor with the O_CLOEXEC flag set. | ||
1721 | * | ||
1722 | * Note, that this function can only be called after the fd table has | ||
1723 | * been unshared to avoid leaking the pidfd to the new process. | ||
1724 | * | ||
1725 | * Return: On success, a cloexec pidfd is returned. | ||
1726 | * On error, a negative errno number will be returned. | ||
1727 | */ | ||
1728 | static int pidfd_create(struct pid *pid) | ||
1729 | { | ||
1730 | int fd; | ||
1731 | |||
1732 | fd = anon_inode_getfd("[pidfd]", &pidfd_fops, get_pid(pid), | ||
1733 | O_RDWR | O_CLOEXEC); | ||
1734 | if (fd < 0) | ||
1735 | put_pid(pid); | ||
1736 | |||
1737 | return fd; | ||
1738 | } | ||
1739 | |||
1740 | static void __delayed_free_task(struct rcu_head *rhp) | 1719 | static void __delayed_free_task(struct rcu_head *rhp) |
1741 | { | 1720 | { |
1742 | struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); | 1721 | struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); |
@@ -1774,6 +1753,7 @@ static __latent_entropy struct task_struct *copy_process( | |||
1774 | int pidfd = -1, retval; | 1753 | int pidfd = -1, retval; |
1775 | struct task_struct *p; | 1754 | struct task_struct *p; |
1776 | struct multiprocess_signals delayed; | 1755 | struct multiprocess_signals delayed; |
1756 | struct file *pidfile = NULL; | ||
1777 | 1757 | ||
1778 | /* | 1758 | /* |
1779 | * Don't allow sharing the root directory with processes in a different | 1759 | * Don't allow sharing the root directory with processes in a different |
@@ -1822,8 +1802,6 @@ static __latent_entropy struct task_struct *copy_process( | |||
1822 | } | 1802 | } |
1823 | 1803 | ||
1824 | if (clone_flags & CLONE_PIDFD) { | 1804 | if (clone_flags & CLONE_PIDFD) { |
1825 | int reserved; | ||
1826 | |||
1827 | /* | 1805 | /* |
1828 | * - CLONE_PARENT_SETTID is useless for pidfds and also | 1806 | * - CLONE_PARENT_SETTID is useless for pidfds and also |
1829 | * parent_tidptr is used to return pidfds. | 1807 | * parent_tidptr is used to return pidfds. |
@@ -1834,16 +1812,6 @@ static __latent_entropy struct task_struct *copy_process( | |||
1834 | if (clone_flags & | 1812 | if (clone_flags & |
1835 | (CLONE_DETACHED | CLONE_PARENT_SETTID | CLONE_THREAD)) | 1813 | (CLONE_DETACHED | CLONE_PARENT_SETTID | CLONE_THREAD)) |
1836 | return ERR_PTR(-EINVAL); | 1814 | return ERR_PTR(-EINVAL); |
1837 | |||
1838 | /* | ||
1839 | * Verify that parent_tidptr is sane so we can potentially | ||
1840 | * reuse it later. | ||
1841 | */ | ||
1842 | if (get_user(reserved, parent_tidptr)) | ||
1843 | return ERR_PTR(-EFAULT); | ||
1844 | |||
1845 | if (reserved != 0) | ||
1846 | return ERR_PTR(-EINVAL); | ||
1847 | } | 1815 | } |
1848 | 1816 | ||
1849 | /* | 1817 | /* |
@@ -2058,11 +2026,21 @@ static __latent_entropy struct task_struct *copy_process( | |||
2058 | * if the fd table isn't shared). | 2026 | * if the fd table isn't shared). |
2059 | */ | 2027 | */ |
2060 | if (clone_flags & CLONE_PIDFD) { | 2028 | if (clone_flags & CLONE_PIDFD) { |
2061 | retval = pidfd_create(pid); | 2029 | retval = get_unused_fd_flags(O_RDWR | O_CLOEXEC); |
2062 | if (retval < 0) | 2030 | if (retval < 0) |
2063 | goto bad_fork_free_pid; | 2031 | goto bad_fork_free_pid; |
2064 | 2032 | ||
2065 | pidfd = retval; | 2033 | pidfd = retval; |
2034 | |||
2035 | pidfile = anon_inode_getfile("[pidfd]", &pidfd_fops, pid, | ||
2036 | O_RDWR | O_CLOEXEC); | ||
2037 | if (IS_ERR(pidfile)) { | ||
2038 | put_unused_fd(pidfd); | ||
2039 | retval = PTR_ERR(pidfile); | ||
2040 | goto bad_fork_free_pid; | ||
2041 | } | ||
2042 | get_pid(pid); /* held by pidfile now */ | ||
2043 | |||
2066 | retval = put_user(pidfd, parent_tidptr); | 2044 | retval = put_user(pidfd, parent_tidptr); |
2067 | if (retval) | 2045 | if (retval) |
2068 | goto bad_fork_put_pidfd; | 2046 | goto bad_fork_put_pidfd; |
@@ -2180,6 +2158,9 @@ static __latent_entropy struct task_struct *copy_process( | |||
2180 | goto bad_fork_cancel_cgroup; | 2158 | goto bad_fork_cancel_cgroup; |
2181 | } | 2159 | } |
2182 | 2160 | ||
2161 | /* past the last point of failure */ | ||
2162 | if (pidfile) | ||
2163 | fd_install(pidfd, pidfile); | ||
2183 | 2164 | ||
2184 | init_task_pid_links(p); | 2165 | init_task_pid_links(p); |
2185 | if (likely(p->pid)) { | 2166 | if (likely(p->pid)) { |
@@ -2246,8 +2227,10 @@ bad_fork_cancel_cgroup: | |||
2246 | bad_fork_cgroup_threadgroup_change_end: | 2227 | bad_fork_cgroup_threadgroup_change_end: |
2247 | cgroup_threadgroup_change_end(current); | 2228 | cgroup_threadgroup_change_end(current); |
2248 | bad_fork_put_pidfd: | 2229 | bad_fork_put_pidfd: |
2249 | if (clone_flags & CLONE_PIDFD) | 2230 | if (clone_flags & CLONE_PIDFD) { |
2250 | ksys_close(pidfd); | 2231 | fput(pidfile); |
2232 | put_unused_fd(pidfd); | ||
2233 | } | ||
2251 | bad_fork_free_pid: | 2234 | bad_fork_free_pid: |
2252 | if (pid != &init_struct_pid) | 2235 | if (pid != &init_struct_pid) |
2253 | free_pid(pid); | 2236 | free_pid(pid); |