diff options
-rw-r--r-- | include/linux/sched.h | 9 | ||||
-rw-r--r-- | include/linux/umh.h | 2 | ||||
-rw-r--r-- | kernel/exit.c | 1 | ||||
-rw-r--r-- | kernel/umh.c | 33 |
4 files changed, 43 insertions, 2 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 89541d248893..e35e35b9fc48 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1406,6 +1406,7 @@ extern struct pid *cad_pid; | |||
1406 | #define PF_RANDOMIZE 0x00400000 /* Randomize virtual address space */ | 1406 | #define PF_RANDOMIZE 0x00400000 /* Randomize virtual address space */ |
1407 | #define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */ | 1407 | #define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */ |
1408 | #define PF_MEMSTALL 0x01000000 /* Stalled due to lack of memory */ | 1408 | #define PF_MEMSTALL 0x01000000 /* Stalled due to lack of memory */ |
1409 | #define PF_UMH 0x02000000 /* I'm an Usermodehelper process */ | ||
1409 | #define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */ | 1410 | #define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */ |
1410 | #define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */ | 1411 | #define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */ |
1411 | #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ | 1412 | #define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ |
@@ -1904,6 +1905,14 @@ static inline void rseq_execve(struct task_struct *t) | |||
1904 | 1905 | ||
1905 | #endif | 1906 | #endif |
1906 | 1907 | ||
1908 | void __exit_umh(struct task_struct *tsk); | ||
1909 | |||
1910 | static inline void exit_umh(struct task_struct *tsk) | ||
1911 | { | ||
1912 | if (unlikely(tsk->flags & PF_UMH)) | ||
1913 | __exit_umh(tsk); | ||
1914 | } | ||
1915 | |||
1907 | #ifdef CONFIG_DEBUG_RSEQ | 1916 | #ifdef CONFIG_DEBUG_RSEQ |
1908 | 1917 | ||
1909 | void rseq_syscall(struct pt_regs *regs); | 1918 | void rseq_syscall(struct pt_regs *regs); |
diff --git a/include/linux/umh.h b/include/linux/umh.h index 235f51b62c71..0c08de356d0d 100644 --- a/include/linux/umh.h +++ b/include/linux/umh.h | |||
@@ -47,6 +47,8 @@ struct umh_info { | |||
47 | const char *cmdline; | 47 | const char *cmdline; |
48 | struct file *pipe_to_umh; | 48 | struct file *pipe_to_umh; |
49 | struct file *pipe_from_umh; | 49 | struct file *pipe_from_umh; |
50 | struct list_head list; | ||
51 | void (*cleanup)(struct umh_info *info); | ||
50 | pid_t pid; | 52 | pid_t pid; |
51 | }; | 53 | }; |
52 | int fork_usermode_blob(void *data, size_t len, struct umh_info *info); | 54 | int fork_usermode_blob(void *data, size_t len, struct umh_info *info); |
diff --git a/kernel/exit.c b/kernel/exit.c index 8a01b671dc1f..dad70419195c 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -866,6 +866,7 @@ void __noreturn do_exit(long code) | |||
866 | exit_task_namespaces(tsk); | 866 | exit_task_namespaces(tsk); |
867 | exit_task_work(tsk); | 867 | exit_task_work(tsk); |
868 | exit_thread(tsk); | 868 | exit_thread(tsk); |
869 | exit_umh(tsk); | ||
869 | 870 | ||
870 | /* | 871 | /* |
871 | * Flush inherited counters to the parent - before the parent | 872 | * Flush inherited counters to the parent - before the parent |
diff --git a/kernel/umh.c b/kernel/umh.c index 0baa672e023c..d937cbad903a 100644 --- a/kernel/umh.c +++ b/kernel/umh.c | |||
@@ -37,6 +37,8 @@ static kernel_cap_t usermodehelper_bset = CAP_FULL_SET; | |||
37 | static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; | 37 | static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; |
38 | static DEFINE_SPINLOCK(umh_sysctl_lock); | 38 | static DEFINE_SPINLOCK(umh_sysctl_lock); |
39 | static DECLARE_RWSEM(umhelper_sem); | 39 | static DECLARE_RWSEM(umhelper_sem); |
40 | static LIST_HEAD(umh_list); | ||
41 | static DEFINE_MUTEX(umh_list_lock); | ||
40 | 42 | ||
41 | static void call_usermodehelper_freeinfo(struct subprocess_info *info) | 43 | static void call_usermodehelper_freeinfo(struct subprocess_info *info) |
42 | { | 44 | { |
@@ -100,10 +102,12 @@ static int call_usermodehelper_exec_async(void *data) | |||
100 | commit_creds(new); | 102 | commit_creds(new); |
101 | 103 | ||
102 | sub_info->pid = task_pid_nr(current); | 104 | sub_info->pid = task_pid_nr(current); |
103 | if (sub_info->file) | 105 | if (sub_info->file) { |
104 | retval = do_execve_file(sub_info->file, | 106 | retval = do_execve_file(sub_info->file, |
105 | sub_info->argv, sub_info->envp); | 107 | sub_info->argv, sub_info->envp); |
106 | else | 108 | if (!retval) |
109 | current->flags |= PF_UMH; | ||
110 | } else | ||
107 | retval = do_execve(getname_kernel(sub_info->path), | 111 | retval = do_execve(getname_kernel(sub_info->path), |
108 | (const char __user *const __user *)sub_info->argv, | 112 | (const char __user *const __user *)sub_info->argv, |
109 | (const char __user *const __user *)sub_info->envp); | 113 | (const char __user *const __user *)sub_info->envp); |
@@ -517,6 +521,11 @@ int fork_usermode_blob(void *data, size_t len, struct umh_info *info) | |||
517 | goto out; | 521 | goto out; |
518 | 522 | ||
519 | err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC); | 523 | err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC); |
524 | if (!err) { | ||
525 | mutex_lock(&umh_list_lock); | ||
526 | list_add(&info->list, &umh_list); | ||
527 | mutex_unlock(&umh_list_lock); | ||
528 | } | ||
520 | out: | 529 | out: |
521 | fput(file); | 530 | fput(file); |
522 | return err; | 531 | return err; |
@@ -679,6 +688,26 @@ static int proc_cap_handler(struct ctl_table *table, int write, | |||
679 | return 0; | 688 | return 0; |
680 | } | 689 | } |
681 | 690 | ||
691 | void __exit_umh(struct task_struct *tsk) | ||
692 | { | ||
693 | struct umh_info *info; | ||
694 | pid_t pid = tsk->pid; | ||
695 | |||
696 | mutex_lock(&umh_list_lock); | ||
697 | list_for_each_entry(info, &umh_list, list) { | ||
698 | if (info->pid == pid) { | ||
699 | list_del(&info->list); | ||
700 | mutex_unlock(&umh_list_lock); | ||
701 | goto out; | ||
702 | } | ||
703 | } | ||
704 | mutex_unlock(&umh_list_lock); | ||
705 | return; | ||
706 | out: | ||
707 | if (info->cleanup) | ||
708 | info->cleanup(info); | ||
709 | } | ||
710 | |||
682 | struct ctl_table usermodehelper_table[] = { | 711 | struct ctl_table usermodehelper_table[] = { |
683 | { | 712 | { |
684 | .procname = "bset", | 713 | .procname = "bset", |