aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/connector/Kconfig8
-rw-r--r--drivers/connector/Makefile1
-rw-r--r--drivers/connector/cn_proc.c222
-rw-r--r--fs/exec.c2
-rw-r--r--include/linux/cn_proc.h127
-rw-r--r--include/linux/connector.h6
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/sys.c9
9 files changed, 379 insertions, 0 deletions
diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig
index 0bc2059c1e08..e0bdc0db9640 100644
--- a/drivers/connector/Kconfig
+++ b/drivers/connector/Kconfig
@@ -10,4 +10,12 @@ config CONNECTOR
10 Connector support can also be built as a module. If so, the module 10 Connector support can also be built as a module. If so, the module
11 will be called cn.ko. 11 will be called cn.ko.
12 12
13config PROC_EVENTS
14 boolean "Report process events to userspace"
15 depends on CONNECTOR=y
16 default y
17 ---help---
18 Provide a connector that reports process events to userspace. Send
19 events such as fork, exec, id change (uid, gid, suid, etc), and exit.
20
13endmenu 21endmenu
diff --git a/drivers/connector/Makefile b/drivers/connector/Makefile
index 12ca79e8234d..1f255e46e916 100644
--- a/drivers/connector/Makefile
+++ b/drivers/connector/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_CONNECTOR) += cn.o 1obj-$(CONFIG_CONNECTOR) += cn.o
2obj-$(CONFIG_PROC_EVENTS) += cn_proc.o
2 3
3cn-y += cn_queue.o connector.o 4cn-y += cn_queue.o connector.o
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
new file mode 100644
index 000000000000..fcdf0fff13a6
--- /dev/null
+++ b/drivers/connector/cn_proc.c
@@ -0,0 +1,222 @@
1/*
2 * cn_proc.c - process events connector
3 *
4 * Copyright (C) Matt Helsley, IBM Corp. 2005
5 * Based on cn_fork.c by Guillaume Thouvenin <guillaume.thouvenin@bull.net>
6 * Original copyright notice follows:
7 * Copyright (C) 2005 BULL SA.
8 *
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25#include <linux/module.h>
26#include <linux/kernel.h>
27#include <linux/init.h>
28#include <asm/atomic.h>
29
30#include <linux/cn_proc.h>
31
32#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event))
33
34static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);
35static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
36
37/* proc_counts is used as the sequence number of the netlink message */
38static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
39
40static inline void get_seq(__u32 *ts, int *cpu)
41{
42 *ts = get_cpu_var(proc_event_counts)++;
43 *cpu = smp_processor_id();
44 put_cpu_var(proc_counts);
45}
46
47void proc_fork_connector(struct task_struct *task)
48{
49 struct cn_msg *msg;
50 struct proc_event *ev;
51 __u8 buffer[CN_PROC_MSG_SIZE];
52
53 if (atomic_read(&proc_event_num_listeners) < 1)
54 return;
55
56 msg = (struct cn_msg*)buffer;
57 ev = (struct proc_event*)msg->data;
58 get_seq(&msg->seq, &ev->cpu);
59 ev->what = PROC_EVENT_FORK;
60 ev->event_data.fork.parent_pid = task->real_parent->pid;
61 ev->event_data.fork.parent_tgid = task->real_parent->tgid;
62 ev->event_data.fork.child_pid = task->pid;
63 ev->event_data.fork.child_tgid = task->tgid;
64
65 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
66 msg->ack = 0; /* not used */
67 msg->len = sizeof(*ev);
68 /* If cn_netlink_send() failed, the data is not sent */
69 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
70}
71
72void proc_exec_connector(struct task_struct *task)
73{
74 struct cn_msg *msg;
75 struct proc_event *ev;
76 __u8 buffer[CN_PROC_MSG_SIZE];
77
78 if (atomic_read(&proc_event_num_listeners) < 1)
79 return;
80
81 msg = (struct cn_msg*)buffer;
82 ev = (struct proc_event*)msg->data;
83 get_seq(&msg->seq, &ev->cpu);
84 ev->what = PROC_EVENT_EXEC;
85 ev->event_data.exec.process_pid = task->pid;
86 ev->event_data.exec.process_tgid = task->tgid;
87
88 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
89 msg->ack = 0; /* not used */
90 msg->len = sizeof(*ev);
91 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
92}
93
94void proc_id_connector(struct task_struct *task, int which_id)
95{
96 struct cn_msg *msg;
97 struct proc_event *ev;
98 __u8 buffer[CN_PROC_MSG_SIZE];
99
100 if (atomic_read(&proc_event_num_listeners) < 1)
101 return;
102
103 msg = (struct cn_msg*)buffer;
104 ev = (struct proc_event*)msg->data;
105 ev->what = which_id;
106 ev->event_data.id.process_pid = task->pid;
107 ev->event_data.id.process_tgid = task->tgid;
108 if (which_id == PROC_EVENT_UID) {
109 ev->event_data.id.r.ruid = task->uid;
110 ev->event_data.id.e.euid = task->euid;
111 } else if (which_id == PROC_EVENT_GID) {
112 ev->event_data.id.r.rgid = task->gid;
113 ev->event_data.id.e.egid = task->egid;
114 } else
115 return;
116 get_seq(&msg->seq, &ev->cpu);
117
118 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
119 msg->ack = 0; /* not used */
120 msg->len = sizeof(*ev);
121 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
122}
123
124void proc_exit_connector(struct task_struct *task)
125{
126 struct cn_msg *msg;
127 struct proc_event *ev;
128 __u8 buffer[CN_PROC_MSG_SIZE];
129
130 if (atomic_read(&proc_event_num_listeners) < 1)
131 return;
132
133 msg = (struct cn_msg*)buffer;
134 ev = (struct proc_event*)msg->data;
135 get_seq(&msg->seq, &ev->cpu);
136 ev->what = PROC_EVENT_EXIT;
137 ev->event_data.exit.process_pid = task->pid;
138 ev->event_data.exit.process_tgid = task->tgid;
139 ev->event_data.exit.exit_code = task->exit_code;
140 ev->event_data.exit.exit_signal = task->exit_signal;
141
142 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
143 msg->ack = 0; /* not used */
144 msg->len = sizeof(*ev);
145 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
146}
147
148/*
149 * Send an acknowledgement message to userspace
150 *
151 * Use 0 for success, EFOO otherwise.
152 * Note: this is the negative of conventional kernel error
153 * values because it's not being returned via syscall return
154 * mechanisms.
155 */
156static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
157{
158 struct cn_msg *msg;
159 struct proc_event *ev;
160 __u8 buffer[CN_PROC_MSG_SIZE];
161
162 if (atomic_read(&proc_event_num_listeners) < 1)
163 return;
164
165 msg = (struct cn_msg*)buffer;
166 ev = (struct proc_event*)msg->data;
167 msg->seq = rcvd_seq;
168 ev->cpu = -1;
169 ev->what = PROC_EVENT_NONE;
170 ev->event_data.ack.err = err;
171 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
172 msg->ack = rcvd_ack + 1;
173 msg->len = sizeof(*ev);
174 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
175}
176
177/**
178 * cn_proc_mcast_ctl
179 * @data: message sent from userspace via the connector
180 */
181static void cn_proc_mcast_ctl(void *data)
182{
183 struct cn_msg *msg = data;
184 enum proc_cn_mcast_op *mc_op = NULL;
185 int err = 0;
186
187 if (msg->len != sizeof(*mc_op))
188 return;
189
190 mc_op = (enum proc_cn_mcast_op*)msg->data;
191 switch (*mc_op) {
192 case PROC_CN_MCAST_LISTEN:
193 atomic_inc(&proc_event_num_listeners);
194 break;
195 case PROC_CN_MCAST_IGNORE:
196 atomic_dec(&proc_event_num_listeners);
197 break;
198 default:
199 err = EINVAL;
200 break;
201 }
202 cn_proc_ack(err, msg->seq, msg->ack);
203}
204
205/*
206 * cn_proc_init - initialization entry point
207 *
208 * Adds the connector callback to the connector driver.
209 */
210static int __init cn_proc_init(void)
211{
212 int err;
213
214 if ((err = cn_add_callback(&cn_proc_event_id, "cn_proc",
215 &cn_proc_mcast_ctl))) {
216 printk(KERN_WARNING "cn_proc failed to register\n");
217 return err;
218 }
219 return 0;
220}
221
222module_init(cn_proc_init);
diff --git a/fs/exec.c b/fs/exec.c
index 10d493fea7ce..ce76b33f25ac 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -48,6 +48,7 @@
48#include <linux/syscalls.h> 48#include <linux/syscalls.h>
49#include <linux/rmap.h> 49#include <linux/rmap.h>
50#include <linux/acct.h> 50#include <linux/acct.h>
51#include <linux/cn_proc.h>
51 52
52#include <asm/uaccess.h> 53#include <asm/uaccess.h>
53#include <asm/mmu_context.h> 54#include <asm/mmu_context.h>
@@ -1096,6 +1097,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
1096 fput(bprm->file); 1097 fput(bprm->file);
1097 bprm->file = NULL; 1098 bprm->file = NULL;
1098 current->did_exec = 1; 1099 current->did_exec = 1;
1100 proc_exec_connector(current);
1099 return retval; 1101 return retval;
1100 } 1102 }
1101 read_lock(&binfmt_lock); 1103 read_lock(&binfmt_lock);
diff --git a/include/linux/cn_proc.h b/include/linux/cn_proc.h
new file mode 100644
index 000000000000..70ab56317380
--- /dev/null
+++ b/include/linux/cn_proc.h
@@ -0,0 +1,127 @@
1/*
2 * cn_proc.h - process events connector
3 *
4 * Copyright (C) Matt Helsley, IBM Corp. 2005
5 * Based on cn_fork.h by Nguyen Anh Quynh and Guillaume Thouvenin
6 * Original copyright notice follows:
7 * Copyright (C) 2005 Nguyen Anh Quynh <aquynh@gmail.com>
8 * Copyright (C) 2005 Guillaume Thouvenin <guillaume.thouvenin@bull.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25#ifndef CN_PROC_H
26#define CN_PROC_H
27
28#include <linux/types.h>
29#include <linux/connector.h>
30
31/*
32 * Userspace sends this enum to register with the kernel that it is listening
33 * for events on the connector.
34 */
35enum proc_cn_mcast_op {
36 PROC_CN_MCAST_LISTEN = 1,
37 PROC_CN_MCAST_IGNORE = 2
38};
39
40/*
41 * From the user's point of view, the process
42 * ID is the thread group ID and thread ID is the internal
43 * kernel "pid". So, fields are assigned as follow:
44 *
45 * In user space - In kernel space
46 *
47 * parent process ID = parent->tgid
48 * parent thread ID = parent->pid
49 * child process ID = child->tgid
50 * child thread ID = child->pid
51 */
52
53struct proc_event {
54 enum what {
55 /* Use successive bits so the enums can be used to record
56 * sets of events as well
57 */
58 PROC_EVENT_NONE = 0x00000000,
59 PROC_EVENT_FORK = 0x00000001,
60 PROC_EVENT_EXEC = 0x00000002,
61 PROC_EVENT_UID = 0x00000004,
62 PROC_EVENT_GID = 0x00000040,
63 /* "next" should be 0x00000400 */
64 /* "last" is the last process event: exit */
65 PROC_EVENT_EXIT = 0x80000000
66 } what;
67 __u32 cpu;
68 union { /* must be last field of proc_event struct */
69 struct {
70 __u32 err;
71 } ack;
72
73 struct fork_proc_event {
74 pid_t parent_pid;
75 pid_t parent_tgid;
76 pid_t child_pid;
77 pid_t child_tgid;
78 } fork;
79
80 struct exec_proc_event {
81 pid_t process_pid;
82 pid_t process_tgid;
83 } exec;
84
85 struct id_proc_event {
86 pid_t process_pid;
87 pid_t process_tgid;
88 union {
89 uid_t ruid; /* current->uid */
90 gid_t rgid; /* current->gid */
91 } r;
92 union {
93 uid_t euid;
94 gid_t egid;
95 } e;
96 } id;
97
98 struct exit_proc_event {
99 pid_t process_pid;
100 pid_t process_tgid;
101 __u32 exit_code, exit_signal;
102 } exit;
103 } event_data;
104};
105
106#ifdef __KERNEL__
107#ifdef CONFIG_PROC_EVENTS
108void proc_fork_connector(struct task_struct *task);
109void proc_exec_connector(struct task_struct *task);
110void proc_id_connector(struct task_struct *task, int which_id);
111void proc_exit_connector(struct task_struct *task);
112#else
113static inline void proc_fork_connector(struct task_struct *task)
114{}
115
116static inline void proc_exec_connector(struct task_struct *task)
117{}
118
119static inline void proc_id_connector(struct task_struct *task,
120 int which_id)
121{}
122
123static inline void proc_exit_connector(struct task_struct *task)
124{}
125#endif /* CONFIG_PROC_EVENTS */
126#endif /* __KERNEL__ */
127#endif /* CN_PROC_H */
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 95952cc1f525..c5769c6585f4 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -27,6 +27,12 @@
27#define CN_IDX_CONNECTOR 0xffffffff 27#define CN_IDX_CONNECTOR 0xffffffff
28#define CN_VAL_CONNECTOR 0xffffffff 28#define CN_VAL_CONNECTOR 0xffffffff
29 29
30/*
31 * Process Events connector unique ids -- used for message routing
32 */
33#define CN_IDX_PROC 0x1
34#define CN_VAL_PROC 0x1
35
30#define CN_NETLINK_USERS 1 36#define CN_NETLINK_USERS 1
31 37
32/* 38/*
diff --git a/kernel/exit.c b/kernel/exit.c
index 537394b25e8d..452a1d116178 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -28,6 +28,7 @@
28#include <linux/cpuset.h> 28#include <linux/cpuset.h>
29#include <linux/syscalls.h> 29#include <linux/syscalls.h>
30#include <linux/signal.h> 30#include <linux/signal.h>
31#include <linux/cn_proc.h>
31 32
32#include <asm/uaccess.h> 33#include <asm/uaccess.h>
33#include <asm/unistd.h> 34#include <asm/unistd.h>
@@ -863,6 +864,7 @@ fastcall NORET_TYPE void do_exit(long code)
863 module_put(tsk->binfmt->module); 864 module_put(tsk->binfmt->module);
864 865
865 tsk->exit_code = code; 866 tsk->exit_code = code;
867 proc_exit_connector(tsk);
866 exit_notify(tsk); 868 exit_notify(tsk);
867#ifdef CONFIG_NUMA 869#ifdef CONFIG_NUMA
868 mpol_free(tsk->mempolicy); 870 mpol_free(tsk->mempolicy);
diff --git a/kernel/fork.c b/kernel/fork.c
index 8a069612eac3..efac2c58ec7d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -42,6 +42,7 @@
42#include <linux/profile.h> 42#include <linux/profile.h>
43#include <linux/rmap.h> 43#include <linux/rmap.h>
44#include <linux/acct.h> 44#include <linux/acct.h>
45#include <linux/cn_proc.h>
45 46
46#include <asm/pgtable.h> 47#include <asm/pgtable.h>
47#include <asm/pgalloc.h> 48#include <asm/pgalloc.h>
@@ -1143,6 +1144,7 @@ static task_t *copy_process(unsigned long clone_flags,
1143 __get_cpu_var(process_counts)++; 1144 __get_cpu_var(process_counts)++;
1144 } 1145 }
1145 1146
1147 proc_fork_connector(p);
1146 if (!current->signal->tty && p->signal->tty) 1148 if (!current->signal->tty && p->signal->tty)
1147 p->signal->tty = NULL; 1149 p->signal->tty = NULL;
1148 1150
diff --git a/kernel/sys.c b/kernel/sys.c
index 2fa1ed18123c..1e1f41b3fdf6 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -28,6 +28,7 @@
28#include <linux/suspend.h> 28#include <linux/suspend.h>
29#include <linux/tty.h> 29#include <linux/tty.h>
30#include <linux/signal.h> 30#include <linux/signal.h>
31#include <linux/cn_proc.h>
31 32
32#include <linux/compat.h> 33#include <linux/compat.h>
33#include <linux/syscalls.h> 34#include <linux/syscalls.h>
@@ -623,6 +624,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
623 current->egid = new_egid; 624 current->egid = new_egid;
624 current->gid = new_rgid; 625 current->gid = new_rgid;
625 key_fsgid_changed(current); 626 key_fsgid_changed(current);
627 proc_id_connector(current, PROC_EVENT_GID);
626 return 0; 628 return 0;
627} 629}
628 630
@@ -662,6 +664,7 @@ asmlinkage long sys_setgid(gid_t gid)
662 return -EPERM; 664 return -EPERM;
663 665
664 key_fsgid_changed(current); 666 key_fsgid_changed(current);
667 proc_id_connector(current, PROC_EVENT_GID);
665 return 0; 668 return 0;
666} 669}
667 670
@@ -751,6 +754,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
751 current->fsuid = current->euid; 754 current->fsuid = current->euid;
752 755
753 key_fsuid_changed(current); 756 key_fsuid_changed(current);
757 proc_id_connector(current, PROC_EVENT_UID);
754 758
755 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE); 759 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
756} 760}
@@ -798,6 +802,7 @@ asmlinkage long sys_setuid(uid_t uid)
798 current->suid = new_suid; 802 current->suid = new_suid;
799 803
800 key_fsuid_changed(current); 804 key_fsuid_changed(current);
805 proc_id_connector(current, PROC_EVENT_UID);
801 806
802 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID); 807 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
803} 808}
@@ -846,6 +851,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
846 current->suid = suid; 851 current->suid = suid;
847 852
848 key_fsuid_changed(current); 853 key_fsuid_changed(current);
854 proc_id_connector(current, PROC_EVENT_UID);
849 855
850 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES); 856 return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
851} 857}
@@ -898,6 +904,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
898 current->sgid = sgid; 904 current->sgid = sgid;
899 905
900 key_fsgid_changed(current); 906 key_fsgid_changed(current);
907 proc_id_connector(current, PROC_EVENT_GID);
901 return 0; 908 return 0;
902} 909}
903 910
@@ -940,6 +947,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
940 } 947 }
941 948
942 key_fsuid_changed(current); 949 key_fsuid_changed(current);
950 proc_id_connector(current, PROC_EVENT_UID);
943 951
944 security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); 952 security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
945 953
@@ -968,6 +976,7 @@ asmlinkage long sys_setfsgid(gid_t gid)
968 } 976 }
969 current->fsgid = gid; 977 current->fsgid = gid;
970 key_fsgid_changed(current); 978 key_fsgid_changed(current);
979 proc_id_connector(current, PROC_EVENT_GID);
971 } 980 }
972 return old_fsgid; 981 return old_fsgid;
973} 982}