Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'usermode-driver-cleanup' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace into bpf-next

+275 -260
+9 -29
fs/exec.c
··· 1818 1818 /* 1819 1819 * sys_execve() executes a new program. 1820 1820 */ 1821 - static int __do_execve_file(int fd, struct filename *filename, 1822 - struct user_arg_ptr argv, 1823 - struct user_arg_ptr envp, 1824 - int flags, struct file *file) 1821 + static int do_execveat_common(int fd, struct filename *filename, 1822 + struct user_arg_ptr argv, 1823 + struct user_arg_ptr envp, 1824 + int flags) 1825 1825 { 1826 1826 char *pathbuf = NULL; 1827 1827 struct linux_binprm *bprm; 1828 + struct file *file; 1828 1829 struct files_struct *displaced; 1829 1830 int retval; 1830 1831 ··· 1864 1863 check_unsafe_exec(bprm); 1865 1864 current->in_execve = 1; 1866 1865 1867 - if (!file) 1868 - file = do_open_execat(fd, filename, flags); 1866 + file = do_open_execat(fd, filename, flags); 1869 1867 retval = PTR_ERR(file); 1870 1868 if (IS_ERR(file)) 1871 1869 goto out_unmark; ··· 1872 1872 sched_exec(); 1873 1873 1874 1874 bprm->file = file; 1875 - if (!filename) { 1876 - bprm->filename = "none"; 1877 - } else if (fd == AT_FDCWD || filename->name[0] == '/') { 1875 + if (fd == AT_FDCWD || filename->name[0] == '/') { 1878 1876 bprm->filename = filename->name; 1879 1877 } else { 1880 1878 if (filename->name[0] == '\0') ··· 1933 1935 task_numa_free(current, false); 1934 1936 free_bprm(bprm); 1935 1937 kfree(pathbuf); 1936 - if (filename) 1937 - putname(filename); 1938 + putname(filename); 1938 1939 if (displaced) 1939 1940 put_files_struct(displaced); 1940 1941 return retval; ··· 1964 1967 if (displaced) 1965 1968 reset_files_struct(displaced); 1966 1969 out_ret: 1967 - if (filename) 1968 - putname(filename); 1970 + putname(filename); 1969 1971 return retval; 1970 - } 1971 - 1972 - static int do_execveat_common(int fd, struct filename *filename, 1973 - struct user_arg_ptr argv, 1974 - struct user_arg_ptr envp, 1975 - int flags) 1976 - { 1977 - return __do_execve_file(fd, filename, argv, envp, flags, NULL); 1978 - } 1979 - 1980 - int do_execve_file(struct file *file, void *__argv, void *__envp) 1981 - { 1982 - struct user_arg_ptr argv = { .ptr.native = __argv }; 1983 - struct user_arg_ptr envp = { .ptr.native = __envp }; 1984 - 1985 - return __do_execve_file(AT_FDCWD, NULL, argv, envp, 0, file); 1986 1972 } 1987 1973 1988 1974 int do_execve(struct filename *filename,
-1
include/linux/binfmts.h
··· 141 141 const char __user * const __user *, 142 142 const char __user * const __user *, 143 143 int); 144 - int do_execve_file(struct file *file, void *__argv, void *__envp); 145 144 146 145 #endif /* _LINUX_BINFMTS_H */
+4 -3
include/linux/bpfilter.h
··· 3 3 #define _LINUX_BPFILTER_H 4 4 5 5 #include <uapi/linux/bpfilter.h> 6 - #include <linux/umh.h> 6 + #include <linux/usermode_driver.h> 7 7 8 8 struct sock; 9 9 int bpfilter_ip_set_sockopt(struct sock *sk, int optname, char __user *optval, 10 10 unsigned int optlen); 11 11 int bpfilter_ip_get_sockopt(struct sock *sk, int optname, char __user *optval, 12 12 int __user *optlen); 13 + void bpfilter_umh_cleanup(struct umd_info *info); 14 + 13 15 struct bpfilter_umh_ops { 14 - struct umh_info info; 16 + struct umd_info info; 15 17 /* since ip_getsockopt() can run in parallel, serialize access to umh */ 16 18 struct mutex lock; 17 19 int (*sockopt)(struct sock *sk, int optname, 18 20 char __user *optval, 19 21 unsigned int optlen, bool is_set); 20 22 int (*start)(void); 21 - bool stop; 22 23 }; 23 24 extern struct bpfilter_umh_ops bpfilter_ops; 24 25 #endif
-9
include/linux/sched.h
··· 1510 1510 #define PF_KTHREAD 0x00200000 /* I am a kernel thread */ 1511 1511 #define PF_RANDOMIZE 0x00400000 /* Randomize virtual address space */ 1512 1512 #define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */ 1513 - #define PF_UMH 0x02000000 /* I'm an Usermodehelper process */ 1514 1513 #define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_mask */ 1515 1514 #define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */ 1516 1515 #define PF_MEMALLOC_NOCMA 0x10000000 /* All allocation request will have _GFP_MOVABLE cleared */ ··· 2017 2018 } 2018 2019 2019 2020 #endif 2020 - 2021 - void __exit_umh(struct task_struct *tsk); 2022 - 2023 - static inline void exit_umh(struct task_struct *tsk) 2024 - { 2025 - if (unlikely(tsk->flags & PF_UMH)) 2026 - __exit_umh(tsk); 2027 - } 2028 2021 2029 2022 #ifdef CONFIG_DEBUG_RSEQ 2030 2023
+2
include/linux/sched/signal.h
··· 674 674 #define delay_group_leader(p) \ 675 675 (thread_group_leader(p) && !thread_group_empty(p)) 676 676 677 + extern bool thread_group_exited(struct pid *pid); 678 + 677 679 extern struct sighand_struct *__lock_task_sighand(struct task_struct *task, 678 680 unsigned long *flags); 679 681
-15
include/linux/umh.h
··· 22 22 const char *path; 23 23 char **argv; 24 24 char **envp; 25 - struct file *file; 26 25 int wait; 27 26 int retval; 28 - pid_t pid; 29 27 int (*init)(struct subprocess_info *info, struct cred *new); 30 28 void (*cleanup)(struct subprocess_info *info); 31 29 void *data; ··· 37 39 gfp_t gfp_mask, 38 40 int (*init)(struct subprocess_info *info, struct cred *new), 39 41 void (*cleanup)(struct subprocess_info *), void *data); 40 - 41 - struct subprocess_info *call_usermodehelper_setup_file(struct file *file, 42 - int (*init)(struct subprocess_info *info, struct cred *new), 43 - void (*cleanup)(struct subprocess_info *), void *data); 44 - struct umh_info { 45 - const char *cmdline; 46 - struct file *pipe_to_umh; 47 - struct file *pipe_from_umh; 48 - struct list_head list; 49 - void (*cleanup)(struct umh_info *info); 50 - pid_t pid; 51 - }; 52 - int fork_usermode_blob(void *data, size_t len, struct umh_info *info); 53 42 54 43 extern int 55 44 call_usermodehelper_exec(struct subprocess_info *info, int wait);
+18
include/linux/usermode_driver.h
··· 1 + #ifndef __LINUX_USERMODE_DRIVER_H__ 2 + #define __LINUX_USERMODE_DRIVER_H__ 3 + 4 + #include <linux/umh.h> 5 + #include <linux/path.h> 6 + 7 + struct umd_info { 8 + const char *driver_name; 9 + struct file *pipe_to_umh; 10 + struct file *pipe_from_umh; 11 + struct path wd; 12 + struct pid *tgid; 13 + }; 14 + int umd_load_blob(struct umd_info *info, const void *data, size_t len); 15 + int umd_unload_blob(struct umd_info *info); 16 + int fork_usermode_driver(struct umd_info *info); 17 + 18 + #endif /* __LINUX_USERMODE_DRIVER_H__ */
+1
kernel/Makefile
··· 12 12 notifier.o ksysfs.o cred.o reboot.o \ 13 13 async.o range.o smpboot.o ucount.o 14 14 15 + obj-$(CONFIG_BPFILTER) += usermode_driver.o 15 16 obj-$(CONFIG_MODULES) += kmod.o 16 17 obj-$(CONFIG_MULTIUSER) += groups.o 17 18
+24 -1
kernel/exit.c
··· 804 804 exit_task_namespaces(tsk); 805 805 exit_task_work(tsk); 806 806 exit_thread(tsk); 807 - exit_umh(tsk); 808 807 809 808 /* 810 809 * Flush inherited counters to the parent - before the parent ··· 1709 1710 return -EFAULT; 1710 1711 } 1711 1712 #endif 1713 + 1714 + /** 1715 + * thread_group_exited - check that a thread group has exited 1716 + * @pid: tgid of thread group to be checked. 1717 + * 1718 + * Test if the thread group represented by tgid has exited (all 1719 + * threads are zombies, dead or completely gone). 1720 + * 1721 + * Return: true if the thread group has exited. false otherwise. 1722 + */ 1723 + bool thread_group_exited(struct pid *pid) 1724 + { 1725 + struct task_struct *task; 1726 + bool exited; 1727 + 1728 + rcu_read_lock(); 1729 + task = pid_task(pid, PIDTYPE_PID); 1730 + exited = !task || 1731 + (READ_ONCE(task->exit_state) && thread_group_empty(task)); 1732 + rcu_read_unlock(); 1733 + 1734 + return exited; 1735 + } 1736 + EXPORT_SYMBOL(thread_group_exited); 1712 1737 1713 1738 __weak void abort(void) 1714 1739 {
+1 -5
kernel/fork.c
··· 1787 1787 */ 1788 1788 static __poll_t pidfd_poll(struct file *file, struct poll_table_struct *pts) 1789 1789 { 1790 - struct task_struct *task; 1791 1790 struct pid *pid = file->private_data; 1792 1791 __poll_t poll_flags = 0; 1793 1792 1794 1793 poll_wait(file, &pid->wait_pidfd, pts); 1795 1794 1796 - rcu_read_lock(); 1797 - task = pid_task(pid, PIDTYPE_PID); 1798 1795 /* 1799 1796 * Inform pollers only when the whole thread group exits. 1800 1797 * If the thread group leader exits before all other threads in the 1801 1798 * group, then poll(2) should block, similar to the wait(2) family. 1802 1799 */ 1803 - if (!task || (task->exit_state && thread_group_empty(task))) 1800 + if (thread_group_exited(pid)) 1804 1801 poll_flags = EPOLLIN | EPOLLRDNORM; 1805 - rcu_read_unlock(); 1806 1802 1807 1803 return poll_flags; 1808 1804 }
+3 -168
kernel/umh.c
··· 26 26 #include <linux/ptrace.h> 27 27 #include <linux/async.h> 28 28 #include <linux/uaccess.h> 29 - #include <linux/shmem_fs.h> 30 - #include <linux/pipe_fs_i.h> 31 29 32 30 #include <trace/events/module.h> 33 31 ··· 36 38 static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; 37 39 static DEFINE_SPINLOCK(umh_sysctl_lock); 38 40 static DECLARE_RWSEM(umhelper_sem); 39 - static LIST_HEAD(umh_list); 40 - static DEFINE_MUTEX(umh_list_lock); 41 41 42 42 static void call_usermodehelper_freeinfo(struct subprocess_info *info) 43 43 { ··· 98 102 99 103 commit_creds(new); 100 104 101 - sub_info->pid = task_pid_nr(current); 102 - if (sub_info->file) { 103 - retval = do_execve_file(sub_info->file, 104 - sub_info->argv, sub_info->envp); 105 - if (!retval) 106 - current->flags |= PF_UMH; 107 - } else 108 - retval = do_execve(getname_kernel(sub_info->path), 109 - (const char __user *const __user *)sub_info->argv, 110 - (const char __user *const __user *)sub_info->envp); 105 + retval = do_execve(getname_kernel(sub_info->path), 106 + (const char __user *const __user *)sub_info->argv, 107 + (const char __user *const __user *)sub_info->envp); 111 108 out: 112 109 sub_info->retval = retval; 113 110 /* ··· 394 405 } 395 406 EXPORT_SYMBOL(call_usermodehelper_setup); 396 407 397 - struct subprocess_info *call_usermodehelper_setup_file(struct file *file, 398 - int (*init)(struct subprocess_info *info, struct cred *new), 399 - void (*cleanup)(struct subprocess_info *info), void *data) 400 - { 401 - struct subprocess_info *sub_info; 402 - struct umh_info *info = data; 403 - const char *cmdline = (info->cmdline) ? info->cmdline : "usermodehelper"; 404 - 405 - sub_info = kzalloc(sizeof(struct subprocess_info), GFP_KERNEL); 406 - if (!sub_info) 407 - return NULL; 408 - 409 - sub_info->argv = argv_split(GFP_KERNEL, cmdline, NULL); 410 - if (!sub_info->argv) { 411 - kfree(sub_info); 412 - return NULL; 413 - } 414 - 415 - INIT_WORK(&sub_info->work, call_usermodehelper_exec_work); 416 - sub_info->path = "none"; 417 - sub_info->file = file; 418 - sub_info->init = init; 419 - sub_info->cleanup = cleanup; 420 - sub_info->data = data; 421 - return sub_info; 422 - } 423 - 424 - static int umh_pipe_setup(struct subprocess_info *info, struct cred *new) 425 - { 426 - struct umh_info *umh_info = info->data; 427 - struct file *from_umh[2]; 428 - struct file *to_umh[2]; 429 - int err; 430 - 431 - /* create pipe to send data to umh */ 432 - err = create_pipe_files(to_umh, 0); 433 - if (err) 434 - return err; 435 - err = replace_fd(0, to_umh[0], 0); 436 - fput(to_umh[0]); 437 - if (err < 0) { 438 - fput(to_umh[1]); 439 - return err; 440 - } 441 - 442 - /* create pipe to receive data from umh */ 443 - err = create_pipe_files(from_umh, 0); 444 - if (err) { 445 - fput(to_umh[1]); 446 - replace_fd(0, NULL, 0); 447 - return err; 448 - } 449 - err = replace_fd(1, from_umh[1], 0); 450 - fput(from_umh[1]); 451 - if (err < 0) { 452 - fput(to_umh[1]); 453 - replace_fd(0, NULL, 0); 454 - fput(from_umh[0]); 455 - return err; 456 - } 457 - 458 - umh_info->pipe_to_umh = to_umh[1]; 459 - umh_info->pipe_from_umh = from_umh[0]; 460 - return 0; 461 - } 462 - 463 - static void umh_clean_and_save_pid(struct subprocess_info *info) 464 - { 465 - struct umh_info *umh_info = info->data; 466 - 467 - /* cleanup if umh_pipe_setup() was successful but exec failed */ 468 - if (info->pid && info->retval) { 469 - fput(umh_info->pipe_to_umh); 470 - fput(umh_info->pipe_from_umh); 471 - } 472 - 473 - argv_free(info->argv); 474 - umh_info->pid = info->pid; 475 - } 476 - 477 - /** 478 - * fork_usermode_blob - fork a blob of bytes as a usermode process 479 - * @data: a blob of bytes that can be do_execv-ed as a file 480 - * @len: length of the blob 481 - * @info: information about usermode process (shouldn't be NULL) 482 - * 483 - * If info->cmdline is set it will be used as command line for the 484 - * user process, else "usermodehelper" is used. 485 - * 486 - * Returns either negative error or zero which indicates success 487 - * in executing a blob of bytes as a usermode process. In such 488 - * case 'struct umh_info *info' is populated with two pipes 489 - * and a pid of the process. The caller is responsible for health 490 - * check of the user process, killing it via pid, and closing the 491 - * pipes when user process is no longer needed. 492 - */ 493 - int fork_usermode_blob(void *data, size_t len, struct umh_info *info) 494 - { 495 - struct subprocess_info *sub_info; 496 - struct file *file; 497 - ssize_t written; 498 - loff_t pos = 0; 499 - int err; 500 - 501 - file = shmem_kernel_file_setup("", len, 0); 502 - if (IS_ERR(file)) 503 - return PTR_ERR(file); 504 - 505 - written = kernel_write(file, data, len, &pos); 506 - if (written != len) { 507 - err = written; 508 - if (err >= 0) 509 - err = -ENOMEM; 510 - goto out; 511 - } 512 - 513 - err = -ENOMEM; 514 - sub_info = call_usermodehelper_setup_file(file, umh_pipe_setup, 515 - umh_clean_and_save_pid, info); 516 - if (!sub_info) 517 - goto out; 518 - 519 - err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC); 520 - if (!err) { 521 - mutex_lock(&umh_list_lock); 522 - list_add(&info->list, &umh_list); 523 - mutex_unlock(&umh_list_lock); 524 - } 525 - out: 526 - fput(file); 527 - return err; 528 - } 529 - EXPORT_SYMBOL_GPL(fork_usermode_blob); 530 - 531 408 /** 532 409 * call_usermodehelper_exec - start a usermode application 533 410 * @sub_info: information about the subprocessa ··· 553 698 } 554 699 555 700 return 0; 556 - } 557 - 558 - void __exit_umh(struct task_struct *tsk) 559 - { 560 - struct umh_info *info; 561 - pid_t pid = tsk->pid; 562 - 563 - mutex_lock(&umh_list_lock); 564 - list_for_each_entry(info, &umh_list, list) { 565 - if (info->pid == pid) { 566 - list_del(&info->list); 567 - mutex_unlock(&umh_list_lock); 568 - goto out; 569 - } 570 - } 571 - mutex_unlock(&umh_list_lock); 572 - return; 573 - out: 574 - if (info->cleanup) 575 - info->cleanup(info); 576 701 } 577 702 578 703 struct ctl_table usermodehelper_table[] = {
+182
kernel/usermode_driver.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * umd - User mode driver support 4 + */ 5 + #include <linux/shmem_fs.h> 6 + #include <linux/pipe_fs_i.h> 7 + #include <linux/mount.h> 8 + #include <linux/fs_struct.h> 9 + #include <linux/task_work.h> 10 + #include <linux/usermode_driver.h> 11 + 12 + static struct vfsmount *blob_to_mnt(const void *data, size_t len, const char *name) 13 + { 14 + struct file_system_type *type; 15 + struct vfsmount *mnt; 16 + struct file *file; 17 + ssize_t written; 18 + loff_t pos = 0; 19 + 20 + type = get_fs_type("tmpfs"); 21 + if (!type) 22 + return ERR_PTR(-ENODEV); 23 + 24 + mnt = kern_mount(type); 25 + put_filesystem(type); 26 + if (IS_ERR(mnt)) 27 + return mnt; 28 + 29 + file = file_open_root(mnt->mnt_root, mnt, name, O_CREAT | O_WRONLY, 0700); 30 + if (IS_ERR(file)) { 31 + mntput(mnt); 32 + return ERR_CAST(file); 33 + } 34 + 35 + written = kernel_write(file, data, len, &pos); 36 + if (written != len) { 37 + int err = written; 38 + if (err >= 0) 39 + err = -ENOMEM; 40 + filp_close(file, NULL); 41 + mntput(mnt); 42 + return ERR_PTR(err); 43 + } 44 + 45 + fput(file); 46 + 47 + /* Flush delayed fput so exec can open the file read-only */ 48 + flush_delayed_fput(); 49 + task_work_run(); 50 + return mnt; 51 + } 52 + 53 + /** 54 + * umd_load_blob - Remember a blob of bytes for fork_usermode_driver 55 + * @info: information about usermode driver 56 + * @data: a blob of bytes that can be executed as a file 57 + * @len: The lentgh of the blob 58 + * 59 + */ 60 + int umd_load_blob(struct umd_info *info, const void *data, size_t len) 61 + { 62 + struct vfsmount *mnt; 63 + 64 + if (WARN_ON_ONCE(info->wd.dentry || info->wd.mnt)) 65 + return -EBUSY; 66 + 67 + mnt = blob_to_mnt(data, len, info->driver_name); 68 + if (IS_ERR(mnt)) 69 + return PTR_ERR(mnt); 70 + 71 + info->wd.mnt = mnt; 72 + info->wd.dentry = mnt->mnt_root; 73 + return 0; 74 + } 75 + EXPORT_SYMBOL_GPL(umd_load_blob); 76 + 77 + /** 78 + * umd_unload_blob - Disassociate @info from a previously loaded blob 79 + * @info: information about usermode driver 80 + * 81 + */ 82 + int umd_unload_blob(struct umd_info *info) 83 + { 84 + if (WARN_ON_ONCE(!info->wd.mnt || 85 + !info->wd.dentry || 86 + info->wd.mnt->mnt_root != info->wd.dentry)) 87 + return -EINVAL; 88 + 89 + kern_unmount(info->wd.mnt); 90 + info->wd.mnt = NULL; 91 + info->wd.dentry = NULL; 92 + return 0; 93 + } 94 + EXPORT_SYMBOL_GPL(umd_unload_blob); 95 + 96 + static int umd_setup(struct subprocess_info *info, struct cred *new) 97 + { 98 + struct umd_info *umd_info = info->data; 99 + struct file *from_umh[2]; 100 + struct file *to_umh[2]; 101 + int err; 102 + 103 + /* create pipe to send data to umh */ 104 + err = create_pipe_files(to_umh, 0); 105 + if (err) 106 + return err; 107 + err = replace_fd(0, to_umh[0], 0); 108 + fput(to_umh[0]); 109 + if (err < 0) { 110 + fput(to_umh[1]); 111 + return err; 112 + } 113 + 114 + /* create pipe to receive data from umh */ 115 + err = create_pipe_files(from_umh, 0); 116 + if (err) { 117 + fput(to_umh[1]); 118 + replace_fd(0, NULL, 0); 119 + return err; 120 + } 121 + err = replace_fd(1, from_umh[1], 0); 122 + fput(from_umh[1]); 123 + if (err < 0) { 124 + fput(to_umh[1]); 125 + replace_fd(0, NULL, 0); 126 + fput(from_umh[0]); 127 + return err; 128 + } 129 + 130 + set_fs_pwd(current->fs, &umd_info->wd); 131 + umd_info->pipe_to_umh = to_umh[1]; 132 + umd_info->pipe_from_umh = from_umh[0]; 133 + umd_info->tgid = get_pid(task_tgid(current)); 134 + return 0; 135 + } 136 + 137 + static void umd_cleanup(struct subprocess_info *info) 138 + { 139 + struct umd_info *umd_info = info->data; 140 + 141 + /* cleanup if umh_setup() was successful but exec failed */ 142 + if (info->retval) { 143 + fput(umd_info->pipe_to_umh); 144 + fput(umd_info->pipe_from_umh); 145 + put_pid(umd_info->tgid); 146 + umd_info->tgid = NULL; 147 + } 148 + } 149 + 150 + /** 151 + * fork_usermode_driver - fork a usermode driver 152 + * @info: information about usermode driver (shouldn't be NULL) 153 + * 154 + * Returns either negative error or zero which indicates success in 155 + * executing a usermode driver. In such case 'struct umd_info *info' 156 + * is populated with two pipes and a tgid of the process. The caller is 157 + * responsible for health check of the user process, killing it via 158 + * tgid, and closing the pipes when user process is no longer needed. 159 + */ 160 + int fork_usermode_driver(struct umd_info *info) 161 + { 162 + struct subprocess_info *sub_info; 163 + const char *argv[] = { info->driver_name, NULL }; 164 + int err; 165 + 166 + if (WARN_ON_ONCE(info->tgid)) 167 + return -EBUSY; 168 + 169 + err = -ENOMEM; 170 + sub_info = call_usermodehelper_setup(info->driver_name, 171 + (char **)argv, NULL, GFP_KERNEL, 172 + umd_setup, umd_cleanup, info); 173 + if (!sub_info) 174 + goto out; 175 + 176 + err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC); 177 + out: 178 + return err; 179 + } 180 + EXPORT_SYMBOL_GPL(fork_usermode_driver); 181 + 182 +
+19 -19
net/bpfilter/bpfilter_kern.c
··· 15 15 16 16 static void shutdown_umh(void) 17 17 { 18 - struct task_struct *tsk; 18 + struct umd_info *info = &bpfilter_ops.info; 19 + struct pid *tgid = info->tgid; 19 20 20 - if (bpfilter_ops.stop) 21 - return; 22 - 23 - tsk = get_pid_task(find_vpid(bpfilter_ops.info.pid), PIDTYPE_PID); 24 - if (tsk) { 25 - send_sig(SIGKILL, tsk, 1); 26 - put_task_struct(tsk); 21 + if (tgid) { 22 + kill_pid(tgid, SIGKILL, 1); 23 + wait_event(tgid->wait_pidfd, thread_group_exited(tgid)); 24 + bpfilter_umh_cleanup(info); 27 25 } 28 26 } 29 27 ··· 46 48 req.cmd = optname; 47 49 req.addr = (long __force __user)optval; 48 50 req.len = optlen; 49 - if (!bpfilter_ops.info.pid) 51 + if (!bpfilter_ops.info.tgid) 50 52 goto out; 51 53 n = kernel_write(bpfilter_ops.info.pipe_to_umh, &req, sizeof(req), 52 54 &pos); ··· 75 77 int err; 76 78 77 79 /* fork usermode process */ 78 - err = fork_usermode_blob(&bpfilter_umh_start, 79 - &bpfilter_umh_end - &bpfilter_umh_start, 80 - &bpfilter_ops.info); 80 + err = fork_usermode_driver(&bpfilter_ops.info); 81 81 if (err) 82 82 return err; 83 - bpfilter_ops.stop = false; 84 - pr_info("Loaded bpfilter_umh pid %d\n", bpfilter_ops.info.pid); 83 + pr_info("Loaded bpfilter_umh pid %d\n", pid_nr(bpfilter_ops.info.tgid)); 85 84 86 85 /* health check that usermode process started correctly */ 87 86 if (__bpfilter_process_sockopt(NULL, 0, NULL, 0, 0) != 0) { ··· 93 98 { 94 99 int err; 95 100 101 + err = umd_load_blob(&bpfilter_ops.info, 102 + &bpfilter_umh_start, 103 + &bpfilter_umh_end - &bpfilter_umh_start); 104 + if (err) 105 + return err; 106 + 96 107 mutex_lock(&bpfilter_ops.lock); 97 - if (!bpfilter_ops.stop) { 98 - err = -EFAULT; 99 - goto out; 100 - } 101 108 err = start_umh(); 102 109 if (!err && IS_ENABLED(CONFIG_INET)) { 103 110 bpfilter_ops.sockopt = &__bpfilter_process_sockopt; 104 111 bpfilter_ops.start = &start_umh; 105 112 } 106 - out: 107 113 mutex_unlock(&bpfilter_ops.lock); 114 + if (err) 115 + umd_unload_blob(&bpfilter_ops.info); 108 116 return err; 109 117 } 110 118 ··· 120 122 bpfilter_ops.sockopt = NULL; 121 123 } 122 124 mutex_unlock(&bpfilter_ops.lock); 125 + 126 + umd_unload_blob(&bpfilter_ops.info); 123 127 } 124 128 module_init(load_umh); 125 129 module_exit(fini_umh);
+1 -1
net/bpfilter/bpfilter_umh_blob.S
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 - .section .rodata, "a" 2 + .section .init.rodata, "a" 3 3 .global bpfilter_umh_start 4 4 bpfilter_umh_start: 5 5 .incbin "net/bpfilter/bpfilter_umh"
+11 -9
net/ipv4/bpfilter/sockopt.c
··· 12 12 struct bpfilter_umh_ops bpfilter_ops; 13 13 EXPORT_SYMBOL_GPL(bpfilter_ops); 14 14 15 - static void bpfilter_umh_cleanup(struct umh_info *info) 15 + void bpfilter_umh_cleanup(struct umd_info *info) 16 16 { 17 - mutex_lock(&bpfilter_ops.lock); 18 - bpfilter_ops.stop = true; 19 17 fput(info->pipe_to_umh); 20 18 fput(info->pipe_from_umh); 21 - info->pid = 0; 22 - mutex_unlock(&bpfilter_ops.lock); 19 + put_pid(info->tgid); 20 + info->tgid = NULL; 23 21 } 22 + EXPORT_SYMBOL_GPL(bpfilter_umh_cleanup); 24 23 25 24 static int bpfilter_mbox_request(struct sock *sk, int optname, 26 25 char __user *optval, ··· 37 38 goto out; 38 39 } 39 40 } 40 - if (bpfilter_ops.stop) { 41 + if (bpfilter_ops.info.tgid && 42 + thread_group_exited(bpfilter_ops.info.tgid)) 43 + bpfilter_umh_cleanup(&bpfilter_ops.info); 44 + 45 + if (!bpfilter_ops.info.tgid) { 41 46 err = bpfilter_ops.start(); 42 47 if (err) 43 48 goto out; ··· 72 69 static int __init bpfilter_sockopt_init(void) 73 70 { 74 71 mutex_init(&bpfilter_ops.lock); 75 - bpfilter_ops.stop = true; 76 - bpfilter_ops.info.cmdline = "bpfilter_umh"; 77 - bpfilter_ops.info.cleanup = &bpfilter_umh_cleanup; 72 + bpfilter_ops.info.tgid = NULL; 73 + bpfilter_ops.info.driver_name = "bpfilter_umh"; 78 74 79 75 return 0; 80 76 }