Blame view

drivers/connector/cn_proc.c 9.49 KB
9f46080c4   Matt Helsley   [PATCH] Process E...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * cn_proc.c - process events connector
   *
   * Copyright (C) Matt Helsley, IBM Corp. 2005
   * Based on cn_fork.c by Guillaume Thouvenin <guillaume.thouvenin@bull.net>
   * Original copyright notice follows:
   * Copyright (C) 2005 BULL SA.
   *
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   */
  
  #include <linux/module.h>
  #include <linux/kernel.h>
caf3c9dc5   Matt Helsley   [PATCH] Switch ge...
27
  #include <linux/ktime.h>
9f46080c4   Matt Helsley   [PATCH] Process E...
28
  #include <linux/init.h>
1d31a4ea8   Matt Helsley   [PATCH] Process E...
29
  #include <linux/connector.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
30
  #include <linux/gfp.h>
f701e5b73   Vladimir Zapolskiy   connector: add an...
31
  #include <linux/ptrace.h>
60063497a   Arun Sharma   atomic: use <linu...
32
  #include <linux/atomic.h>
af3e095a1   Erik Jacobson   [PATCH] connector...
33
  #include <asm/unaligned.h>
9f46080c4   Matt Helsley   [PATCH] Process E...
34
35
36
37
38
39
40
  
  #include <linux/cn_proc.h>
  
  #define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event))
  
  static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);
  static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
cc398c2ea   David S. Miller   [PATCH] drivers/c...
41
  /* proc_event_counts is used as the sequence number of the netlink message */
9f46080c4   Matt Helsley   [PATCH] Process E...
42
43
44
45
  static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
  
  static inline void get_seq(__u32 *ts, int *cpu)
  {
3ea9f6833   Christoph Lameter   connector: Use th...
46
47
  	preempt_disable();
  	*ts = __this_cpu_inc_return(proc_event_counts) -1;
9f46080c4   Matt Helsley   [PATCH] Process E...
48
  	*cpu = smp_processor_id();
3ea9f6833   Christoph Lameter   connector: Use th...
49
  	preempt_enable();
9f46080c4   Matt Helsley   [PATCH] Process E...
50
51
52
53
54
55
56
  }
  
  void proc_fork_connector(struct task_struct *task)
  {
  	struct cn_msg *msg;
  	struct proc_event *ev;
  	__u8 buffer[CN_PROC_MSG_SIZE];
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
57
  	struct timespec ts;
9e8f90dfe   Oleg Nesterov   proc_fork_connect...
58
  	struct task_struct *parent;
9f46080c4   Matt Helsley   [PATCH] Process E...
59
60
61
62
63
64
65
  
  	if (atomic_read(&proc_event_num_listeners) < 1)
  		return;
  
  	msg = (struct cn_msg*)buffer;
  	ev = (struct proc_event*)msg->data;
  	get_seq(&msg->seq, &ev->cpu);
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
66
  	ktime_get_ts(&ts); /* get high res monotonic timestamp */
af3e095a1   Erik Jacobson   [PATCH] connector...
67
  	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
9f46080c4   Matt Helsley   [PATCH] Process E...
68
  	ev->what = PROC_EVENT_FORK;
9e8f90dfe   Oleg Nesterov   proc_fork_connect...
69
70
71
72
73
  	rcu_read_lock();
  	parent = rcu_dereference(task->real_parent);
  	ev->event_data.fork.parent_pid = parent->pid;
  	ev->event_data.fork.parent_tgid = parent->tgid;
  	rcu_read_unlock();
9f46080c4   Matt Helsley   [PATCH] Process E...
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  	ev->event_data.fork.child_pid = task->pid;
  	ev->event_data.fork.child_tgid = task->tgid;
  
  	memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
  	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);
  }
  
  void proc_exec_connector(struct task_struct *task)
  {
  	struct cn_msg *msg;
  	struct proc_event *ev;
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
88
  	struct timespec ts;
9f46080c4   Matt Helsley   [PATCH] Process E...
89
90
91
92
93
94
95
96
  	__u8 buffer[CN_PROC_MSG_SIZE];
  
  	if (atomic_read(&proc_event_num_listeners) < 1)
  		return;
  
  	msg = (struct cn_msg*)buffer;
  	ev = (struct proc_event*)msg->data;
  	get_seq(&msg->seq, &ev->cpu);
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
97
  	ktime_get_ts(&ts); /* get high res monotonic timestamp */
af3e095a1   Erik Jacobson   [PATCH] connector...
98
  	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
9f46080c4   Matt Helsley   [PATCH] Process E...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  	ev->what = PROC_EVENT_EXEC;
  	ev->event_data.exec.process_pid = task->pid;
  	ev->event_data.exec.process_tgid = task->tgid;
  
  	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);
  }
  
  void proc_id_connector(struct task_struct *task, int which_id)
  {
  	struct cn_msg *msg;
  	struct proc_event *ev;
  	__u8 buffer[CN_PROC_MSG_SIZE];
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
114
  	struct timespec ts;
c69e8d9c0   David Howells   CRED: Use RCU to ...
115
  	const struct cred *cred;
9f46080c4   Matt Helsley   [PATCH] Process E...
116
117
118
119
120
121
122
123
124
  
  	if (atomic_read(&proc_event_num_listeners) < 1)
  		return;
  
  	msg = (struct cn_msg*)buffer;
  	ev = (struct proc_event*)msg->data;
  	ev->what = which_id;
  	ev->event_data.id.process_pid = task->pid;
  	ev->event_data.id.process_tgid = task->tgid;
c69e8d9c0   David Howells   CRED: Use RCU to ...
125
126
  	rcu_read_lock();
  	cred = __task_cred(task);
9f46080c4   Matt Helsley   [PATCH] Process E...
127
  	if (which_id == PROC_EVENT_UID) {
c69e8d9c0   David Howells   CRED: Use RCU to ...
128
129
  		ev->event_data.id.r.ruid = cred->uid;
  		ev->event_data.id.e.euid = cred->euid;
9f46080c4   Matt Helsley   [PATCH] Process E...
130
  	} else if (which_id == PROC_EVENT_GID) {
c69e8d9c0   David Howells   CRED: Use RCU to ...
131
132
133
134
  		ev->event_data.id.r.rgid = cred->gid;
  		ev->event_data.id.e.egid = cred->egid;
  	} else {
  		rcu_read_unlock();
9f46080c4   Matt Helsley   [PATCH] Process E...
135
  	     	return;
c69e8d9c0   David Howells   CRED: Use RCU to ...
136
137
  	}
  	rcu_read_unlock();
9f46080c4   Matt Helsley   [PATCH] Process E...
138
  	get_seq(&msg->seq, &ev->cpu);
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
139
  	ktime_get_ts(&ts); /* get high res monotonic timestamp */
af3e095a1   Erik Jacobson   [PATCH] connector...
140
  	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
9f46080c4   Matt Helsley   [PATCH] Process E...
141
142
143
144
145
146
  
  	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);
  }
02b51df1b   Scott James Remnant   proc connector: a...
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  void proc_sid_connector(struct task_struct *task)
  {
  	struct cn_msg *msg;
  	struct proc_event *ev;
  	struct timespec ts;
  	__u8 buffer[CN_PROC_MSG_SIZE];
  
  	if (atomic_read(&proc_event_num_listeners) < 1)
  		return;
  
  	msg = (struct cn_msg *)buffer;
  	ev = (struct proc_event *)msg->data;
  	get_seq(&msg->seq, &ev->cpu);
  	ktime_get_ts(&ts); /* get high res monotonic timestamp */
  	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
  	ev->what = PROC_EVENT_SID;
  	ev->event_data.sid.process_pid = task->pid;
  	ev->event_data.sid.process_tgid = task->tgid;
  
  	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);
  }
f701e5b73   Vladimir Zapolskiy   connector: add an...
171
172
173
174
175
176
  void proc_ptrace_connector(struct task_struct *task, int ptrace_id)
  {
  	struct cn_msg *msg;
  	struct proc_event *ev;
  	struct timespec ts;
  	__u8 buffer[CN_PROC_MSG_SIZE];
f701e5b73   Vladimir Zapolskiy   connector: add an...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  
  	if (atomic_read(&proc_event_num_listeners) < 1)
  		return;
  
  	msg = (struct cn_msg *)buffer;
  	ev = (struct proc_event *)msg->data;
  	get_seq(&msg->seq, &ev->cpu);
  	ktime_get_ts(&ts); /* get high res monotonic timestamp */
  	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
  	ev->what = PROC_EVENT_PTRACE;
  	ev->event_data.ptrace.process_pid  = task->pid;
  	ev->event_data.ptrace.process_tgid = task->tgid;
  	if (ptrace_id == PTRACE_ATTACH) {
  		ev->event_data.ptrace.tracer_pid  = current->pid;
  		ev->event_data.ptrace.tracer_tgid = current->tgid;
  	} else if (ptrace_id == PTRACE_DETACH) {
  		ev->event_data.ptrace.tracer_pid  = 0;
  		ev->event_data.ptrace.tracer_tgid = 0;
  	} else
  		return;
  
  	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);
  }
f786ecba4   Vladimir Zapolskiy   connector: add co...
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  void proc_comm_connector(struct task_struct *task)
  {
  	struct cn_msg *msg;
  	struct proc_event *ev;
  	struct timespec ts;
  	__u8 buffer[CN_PROC_MSG_SIZE];
  
  	if (atomic_read(&proc_event_num_listeners) < 1)
  		return;
  
  	msg = (struct cn_msg *)buffer;
  	ev = (struct proc_event *)msg->data;
  	get_seq(&msg->seq, &ev->cpu);
  	ktime_get_ts(&ts); /* get high res monotonic timestamp */
  	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
  	ev->what = PROC_EVENT_COMM;
  	ev->event_data.comm.process_pid  = task->pid;
  	ev->event_data.comm.process_tgid = task->tgid;
  	get_task_comm(ev->event_data.comm.comm, task);
  
  	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);
  }
9f46080c4   Matt Helsley   [PATCH] Process E...
228
229
230
231
232
  void proc_exit_connector(struct task_struct *task)
  {
  	struct cn_msg *msg;
  	struct proc_event *ev;
  	__u8 buffer[CN_PROC_MSG_SIZE];
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
233
  	struct timespec ts;
9f46080c4   Matt Helsley   [PATCH] Process E...
234
235
236
237
238
239
240
  
  	if (atomic_read(&proc_event_num_listeners) < 1)
  		return;
  
  	msg = (struct cn_msg*)buffer;
  	ev = (struct proc_event*)msg->data;
  	get_seq(&msg->seq, &ev->cpu);
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
241
  	ktime_get_ts(&ts); /* get high res monotonic timestamp */
af3e095a1   Erik Jacobson   [PATCH] connector...
242
  	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
9f46080c4   Matt Helsley   [PATCH] Process E...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	ev->what = PROC_EVENT_EXIT;
  	ev->event_data.exit.process_pid = task->pid;
  	ev->event_data.exit.process_tgid = task->tgid;
  	ev->event_data.exit.exit_code = task->exit_code;
  	ev->event_data.exit.exit_signal = task->exit_signal;
  
  	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);
  }
  
  /*
   * Send an acknowledgement message to userspace
   *
   * Use 0 for success, EFOO otherwise.
   * Note: this is the negative of conventional kernel error
   * values because it's not being returned via syscall return
   * mechanisms.
   */
  static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
  {
  	struct cn_msg *msg;
  	struct proc_event *ev;
  	__u8 buffer[CN_PROC_MSG_SIZE];
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
268
  	struct timespec ts;
9f46080c4   Matt Helsley   [PATCH] Process E...
269
270
271
272
273
274
275
  
  	if (atomic_read(&proc_event_num_listeners) < 1)
  		return;
  
  	msg = (struct cn_msg*)buffer;
  	ev = (struct proc_event*)msg->data;
  	msg->seq = rcvd_seq;
822cfbff2   Chandra Seetharaman   [PATCH] Process E...
276
  	ktime_get_ts(&ts); /* get high res monotonic timestamp */
af3e095a1   Erik Jacobson   [PATCH] connector...
277
  	put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
9f46080c4   Matt Helsley   [PATCH] Process E...
278
279
280
281
282
283
284
285
286
287
288
289
290
  	ev->cpu = -1;
  	ev->what = PROC_EVENT_NONE;
  	ev->event_data.ack.err = err;
  	memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
  	msg->ack = rcvd_ack + 1;
  	msg->len = sizeof(*ev);
  	cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
  }
  
  /**
   * cn_proc_mcast_ctl
   * @data: message sent from userspace via the connector
   */
f0b25932b   Stephen Boyd   connector: Fix in...
291
292
  static void cn_proc_mcast_ctl(struct cn_msg *msg,
  			      struct netlink_skb_parms *nsp)
9f46080c4   Matt Helsley   [PATCH] Process E...
293
  {
9f46080c4   Matt Helsley   [PATCH] Process E...
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  	enum proc_cn_mcast_op *mc_op = NULL;
  	int err = 0;
  
  	if (msg->len != sizeof(*mc_op))
  		return;
  
  	mc_op = (enum proc_cn_mcast_op*)msg->data;
  	switch (*mc_op) {
  	case PROC_CN_MCAST_LISTEN:
  		atomic_inc(&proc_event_num_listeners);
  		break;
  	case PROC_CN_MCAST_IGNORE:
  		atomic_dec(&proc_event_num_listeners);
  		break;
  	default:
  		err = EINVAL;
  		break;
  	}
  	cn_proc_ack(err, msg->seq, msg->ack);
  }
  
  /*
   * cn_proc_init - initialization entry point
   *
   * Adds the connector callback to the connector driver.
   */
  static int __init cn_proc_init(void)
  {
  	int err;
  
  	if ((err = cn_add_callback(&cn_proc_event_id, "cn_proc",
  	 			   &cn_proc_mcast_ctl))) {
  		printk(KERN_WARNING "cn_proc failed to register
  ");
  		return err;
  	}
  	return 0;
  }
  
  module_init(cn_proc_init);