From: Matt Helsley This patch makes process events utilize task watchers instead of calling from fork, exec, exit, and [re][ug]id changes directly. Signed-off-by: Matt Helsley Cc: Guillaume Thouvenin Signed-off-by: Andrew Morton --- drivers/connector/cn_proc.c | 65 ++++++++++++++++++++++++++++------ fs/exec.c | 2 - include/linux/cn_proc.h | 22 ----------- kernel/exit.c | 2 - kernel/fork.c | 7 +-- kernel/sys.c | 8 ---- 6 files changed, 57 insertions(+), 49 deletions(-) diff -puN drivers/connector/cn_proc.c~task-watchers-register-process-events-task-watcher drivers/connector/cn_proc.c --- a/drivers/connector/cn_proc.c~task-watchers-register-process-events-task-watcher +++ a/drivers/connector/cn_proc.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -46,7 +47,7 @@ static inline void get_seq(__u32 *ts, in put_cpu_var(proc_event_counts); } -void proc_fork_connector(struct task_struct *task) +static void proc_fork_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; @@ -69,10 +70,10 @@ void proc_fork_connector(struct task_str msg->ack = 0; /* not used */ msg->len = sizeof(*ev); /* If cn_netlink_send() failed, the data is not sent */ - cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); + cn_netlink_send(msg, CN_IDX_PROC, GFP_ATOMIC); } -void proc_exec_connector(struct task_struct *task) +static void proc_exec_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; @@ -92,10 +93,10 @@ void proc_exec_connector(struct task_str memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); - cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); + cn_netlink_send(msg, CN_IDX_PROC, GFP_ATOMIC); } -void proc_id_connector(struct task_struct *task, int which_id) +static void proc_id_connector(struct task_struct *task, int which_id) { struct cn_msg *msg; struct proc_event *ev; @@ -123,10 +124,10 @@ void proc_id_connector(struct task_struc memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); - cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); + cn_netlink_send(msg, CN_IDX_PROC, GFP_ATOMIC); } -void proc_exit_connector(struct task_struct *task) +static void proc_exit_connector(struct task_struct *task) { struct cn_msg *msg; struct proc_event *ev; @@ -148,7 +149,7 @@ void proc_exit_connector(struct task_str memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); msg->ack = 0; /* not used */ msg->len = sizeof(*ev); - cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); + cn_netlink_send(msg, CN_IDX_PROC, GFP_ATOMIC); } /* @@ -209,6 +210,45 @@ static void cn_proc_mcast_ctl(void *data cn_proc_ack(err, msg->seq, msg->ack); } + +/* + * Dispatch task watcher events to the appropriate process event + * generation function. + */ +static int cn_proc_watch_task(struct notifier_block *nb, unsigned long val, + void *t) +{ + struct task_struct *task = t; + int rc = NOTIFY_OK; + + switch (get_watch_event(val)) { + case WATCH_TASK_CLONE: + proc_fork_connector(task); + break; + case WATCH_TASK_EXEC: + proc_exec_connector(task); + break; + case WATCH_TASK_UID: + proc_id_connector(task, PROC_EVENT_UID); + break; + case WATCH_TASK_GID: + proc_id_connector(task, PROC_EVENT_GID); + break; + case WATCH_TASK_EXIT: + proc_exit_connector(task); + break; + default: /* we don't care about WATCH_TASK_INIT|FREE because we + don't keep per-task info */ + rc = NOTIFY_DONE; /* ignore all other notifications */ + break; + } + return rc; +} + +static struct notifier_block __read_mostly cn_proc_nb = { + .notifier_call = cn_proc_watch_task, +}; + /* * cn_proc_init - initialization entry point * @@ -221,9 +261,14 @@ static int __init cn_proc_init(void) if ((err = cn_add_callback(&cn_proc_event_id, "cn_proc", &cn_proc_mcast_ctl))) { printk(KERN_WARNING "cn_proc failed to register\n"); - return err; + goto out; } - return 0; + + err = register_task_watcher(&cn_proc_nb); + if (err != 0) + cn_del_callback(&cn_proc_event_id); +out: + return err; } module_init(cn_proc_init); diff -puN fs/exec.c~task-watchers-register-process-events-task-watcher fs/exec.c --- a/fs/exec.c~task-watchers-register-process-events-task-watcher +++ a/fs/exec.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include @@ -1099,7 +1098,6 @@ int search_binary_handler(struct linux_b bprm->file = NULL; current->did_exec = 1; notify_watchers(WATCH_TASK_EXEC, current); - proc_exec_connector(current); return retval; } read_lock(&binfmt_lock); diff -puN include/linux/cn_proc.h~task-watchers-register-process-events-task-watcher include/linux/cn_proc.h --- a/include/linux/cn_proc.h~task-watchers-register-process-events-task-watcher +++ a/include/linux/cn_proc.h @@ -95,26 +95,4 @@ struct proc_event { } exit; } event_data; }; - -#ifdef __KERNEL__ -#ifdef CONFIG_PROC_EVENTS -void proc_fork_connector(struct task_struct *task); -void proc_exec_connector(struct task_struct *task); -void proc_id_connector(struct task_struct *task, int which_id); -void proc_exit_connector(struct task_struct *task); -#else -static inline void proc_fork_connector(struct task_struct *task) -{} - -static inline void proc_exec_connector(struct task_struct *task) -{} - -static inline void proc_id_connector(struct task_struct *task, - int which_id) -{} - -static inline void proc_exit_connector(struct task_struct *task) -{} -#endif /* CONFIG_PROC_EVENTS */ -#endif /* __KERNEL__ */ #endif /* CN_PROC_H */ diff -puN kernel/exit.c~task-watchers-register-process-events-task-watcher kernel/exit.c --- a/kernel/exit.c~task-watchers-register-process-events-task-watcher +++ a/kernel/exit.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -935,7 +934,6 @@ fastcall NORET_TYPE void do_exit(long co if (tsk->binfmt) module_put(tsk->binfmt->module); - proc_exit_connector(tsk); exit_notify(tsk); #ifdef CONFIG_NUMA mpol_free(tsk->mempolicy); diff -puN kernel/fork.c~task-watchers-register-process-events-task-watcher kernel/fork.c --- a/kernel/fork.c~task-watchers-register-process-events-task-watcher +++ a/kernel/fork.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -1230,10 +1229,8 @@ static task_t *copy_process(unsigned lon spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); notify_result = notify_watchers(WATCH_TASK_CLONE, p); - if (notify_result & NOTIFY_STOP_MASK) - goto bad_fork_cleanup_namespaces; - proc_fork_connector(p); - return p; + if (!(notify_result & NOTIFY_STOP_MASK)) + return p; bad_fork_cleanup_namespaces: exit_task_namespaces(p); diff -puN kernel/sys.c~task-watchers-register-process-events-task-watcher kernel/sys.c --- a/kernel/sys.c~task-watchers-register-process-events-task-watcher +++ a/kernel/sys.c @@ -860,7 +860,6 @@ asmlinkage long sys_setregid(gid_t rgid, current->gid = new_rgid; key_fsgid_changed(current); notify_watchers(WATCH_TASK_GID, current); - proc_id_connector(current, PROC_EVENT_GID); return 0; } @@ -901,7 +900,6 @@ asmlinkage long sys_setgid(gid_t gid) key_fsgid_changed(current); notify_watchers(WATCH_TASK_GID, current); - proc_id_connector(current, PROC_EVENT_GID); return 0; } @@ -992,7 +990,6 @@ asmlinkage long sys_setreuid(uid_t ruid, key_fsuid_changed(current); notify_watchers(WATCH_TASK_UID, current); - proc_id_connector(current, PROC_EVENT_UID); return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); } @@ -1041,7 +1038,6 @@ asmlinkage long sys_setuid(uid_t uid) key_fsuid_changed(current); notify_watchers(WATCH_TASK_UID, current); - proc_id_connector(current, PROC_EVENT_UID); return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); } @@ -1091,7 +1087,6 @@ asmlinkage long sys_setresuid(uid_t ruid key_fsuid_changed(current); notify_watchers(WATCH_TASK_UID, current); - proc_id_connector(current, PROC_EVENT_UID); return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); } @@ -1145,7 +1140,6 @@ asmlinkage long sys_setresgid(gid_t rgid key_fsgid_changed(current); notify_watchers(WATCH_TASK_GID, current); - proc_id_connector(current, PROC_EVENT_GID); return 0; } @@ -1189,7 +1183,6 @@ asmlinkage long sys_setfsuid(uid_t uid) key_fsuid_changed(current); notify_watchers(WATCH_TASK_UID, current); - proc_id_connector(current, PROC_EVENT_UID); security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); @@ -1219,7 +1212,6 @@ asmlinkage long sys_setfsgid(gid_t gid) current->fsgid = gid; key_fsgid_changed(current); notify_watchers(WATCH_TASK_GID, current); - proc_id_connector(current, PROC_EVENT_GID); } return old_fsgid; } _