Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/connector/cn_proc.c
15109 views
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 <[email protected]>
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/ktime.h>
28
#include <linux/init.h>
29
#include <linux/connector.h>
30
#include <linux/gfp.h>
31
#include <asm/atomic.h>
32
#include <asm/unaligned.h>
33
34
#include <linux/cn_proc.h>
35
36
#define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event))
37
38
static atomic_t proc_event_num_listeners = ATOMIC_INIT(0);
39
static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC };
40
41
/* proc_event_counts is used as the sequence number of the netlink message */
42
static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 };
43
44
static inline void get_seq(__u32 *ts, int *cpu)
45
{
46
preempt_disable();
47
*ts = __this_cpu_inc_return(proc_event_counts) -1;
48
*cpu = smp_processor_id();
49
preempt_enable();
50
}
51
52
void proc_fork_connector(struct task_struct *task)
53
{
54
struct cn_msg *msg;
55
struct proc_event *ev;
56
__u8 buffer[CN_PROC_MSG_SIZE];
57
struct timespec ts;
58
59
if (atomic_read(&proc_event_num_listeners) < 1)
60
return;
61
62
msg = (struct cn_msg*)buffer;
63
ev = (struct proc_event*)msg->data;
64
get_seq(&msg->seq, &ev->cpu);
65
ktime_get_ts(&ts); /* get high res monotonic timestamp */
66
put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
67
ev->what = PROC_EVENT_FORK;
68
ev->event_data.fork.parent_pid = task->real_parent->pid;
69
ev->event_data.fork.parent_tgid = task->real_parent->tgid;
70
ev->event_data.fork.child_pid = task->pid;
71
ev->event_data.fork.child_tgid = task->tgid;
72
73
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
74
msg->ack = 0; /* not used */
75
msg->len = sizeof(*ev);
76
/* If cn_netlink_send() failed, the data is not sent */
77
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
78
}
79
80
void proc_exec_connector(struct task_struct *task)
81
{
82
struct cn_msg *msg;
83
struct proc_event *ev;
84
struct timespec ts;
85
__u8 buffer[CN_PROC_MSG_SIZE];
86
87
if (atomic_read(&proc_event_num_listeners) < 1)
88
return;
89
90
msg = (struct cn_msg*)buffer;
91
ev = (struct proc_event*)msg->data;
92
get_seq(&msg->seq, &ev->cpu);
93
ktime_get_ts(&ts); /* get high res monotonic timestamp */
94
put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
95
ev->what = PROC_EVENT_EXEC;
96
ev->event_data.exec.process_pid = task->pid;
97
ev->event_data.exec.process_tgid = task->tgid;
98
99
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
100
msg->ack = 0; /* not used */
101
msg->len = sizeof(*ev);
102
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
103
}
104
105
void proc_id_connector(struct task_struct *task, int which_id)
106
{
107
struct cn_msg *msg;
108
struct proc_event *ev;
109
__u8 buffer[CN_PROC_MSG_SIZE];
110
struct timespec ts;
111
const struct cred *cred;
112
113
if (atomic_read(&proc_event_num_listeners) < 1)
114
return;
115
116
msg = (struct cn_msg*)buffer;
117
ev = (struct proc_event*)msg->data;
118
ev->what = which_id;
119
ev->event_data.id.process_pid = task->pid;
120
ev->event_data.id.process_tgid = task->tgid;
121
rcu_read_lock();
122
cred = __task_cred(task);
123
if (which_id == PROC_EVENT_UID) {
124
ev->event_data.id.r.ruid = cred->uid;
125
ev->event_data.id.e.euid = cred->euid;
126
} else if (which_id == PROC_EVENT_GID) {
127
ev->event_data.id.r.rgid = cred->gid;
128
ev->event_data.id.e.egid = cred->egid;
129
} else {
130
rcu_read_unlock();
131
return;
132
}
133
rcu_read_unlock();
134
get_seq(&msg->seq, &ev->cpu);
135
ktime_get_ts(&ts); /* get high res monotonic timestamp */
136
put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
137
138
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
139
msg->ack = 0; /* not used */
140
msg->len = sizeof(*ev);
141
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
142
}
143
144
void proc_sid_connector(struct task_struct *task)
145
{
146
struct cn_msg *msg;
147
struct proc_event *ev;
148
struct timespec ts;
149
__u8 buffer[CN_PROC_MSG_SIZE];
150
151
if (atomic_read(&proc_event_num_listeners) < 1)
152
return;
153
154
msg = (struct cn_msg *)buffer;
155
ev = (struct proc_event *)msg->data;
156
get_seq(&msg->seq, &ev->cpu);
157
ktime_get_ts(&ts); /* get high res monotonic timestamp */
158
put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
159
ev->what = PROC_EVENT_SID;
160
ev->event_data.sid.process_pid = task->pid;
161
ev->event_data.sid.process_tgid = task->tgid;
162
163
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
164
msg->ack = 0; /* not used */
165
msg->len = sizeof(*ev);
166
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
167
}
168
169
void proc_exit_connector(struct task_struct *task)
170
{
171
struct cn_msg *msg;
172
struct proc_event *ev;
173
__u8 buffer[CN_PROC_MSG_SIZE];
174
struct timespec ts;
175
176
if (atomic_read(&proc_event_num_listeners) < 1)
177
return;
178
179
msg = (struct cn_msg*)buffer;
180
ev = (struct proc_event*)msg->data;
181
get_seq(&msg->seq, &ev->cpu);
182
ktime_get_ts(&ts); /* get high res monotonic timestamp */
183
put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
184
ev->what = PROC_EVENT_EXIT;
185
ev->event_data.exit.process_pid = task->pid;
186
ev->event_data.exit.process_tgid = task->tgid;
187
ev->event_data.exit.exit_code = task->exit_code;
188
ev->event_data.exit.exit_signal = task->exit_signal;
189
190
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
191
msg->ack = 0; /* not used */
192
msg->len = sizeof(*ev);
193
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
194
}
195
196
/*
197
* Send an acknowledgement message to userspace
198
*
199
* Use 0 for success, EFOO otherwise.
200
* Note: this is the negative of conventional kernel error
201
* values because it's not being returned via syscall return
202
* mechanisms.
203
*/
204
static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
205
{
206
struct cn_msg *msg;
207
struct proc_event *ev;
208
__u8 buffer[CN_PROC_MSG_SIZE];
209
struct timespec ts;
210
211
if (atomic_read(&proc_event_num_listeners) < 1)
212
return;
213
214
msg = (struct cn_msg*)buffer;
215
ev = (struct proc_event*)msg->data;
216
msg->seq = rcvd_seq;
217
ktime_get_ts(&ts); /* get high res monotonic timestamp */
218
put_unaligned(timespec_to_ns(&ts), (__u64 *)&ev->timestamp_ns);
219
ev->cpu = -1;
220
ev->what = PROC_EVENT_NONE;
221
ev->event_data.ack.err = err;
222
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
223
msg->ack = rcvd_ack + 1;
224
msg->len = sizeof(*ev);
225
cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL);
226
}
227
228
/**
229
* cn_proc_mcast_ctl
230
* @data: message sent from userspace via the connector
231
*/
232
static void cn_proc_mcast_ctl(struct cn_msg *msg,
233
struct netlink_skb_parms *nsp)
234
{
235
enum proc_cn_mcast_op *mc_op = NULL;
236
int err = 0;
237
238
if (msg->len != sizeof(*mc_op))
239
return;
240
241
mc_op = (enum proc_cn_mcast_op*)msg->data;
242
switch (*mc_op) {
243
case PROC_CN_MCAST_LISTEN:
244
atomic_inc(&proc_event_num_listeners);
245
break;
246
case PROC_CN_MCAST_IGNORE:
247
atomic_dec(&proc_event_num_listeners);
248
break;
249
default:
250
err = EINVAL;
251
break;
252
}
253
cn_proc_ack(err, msg->seq, msg->ack);
254
}
255
256
/*
257
* cn_proc_init - initialization entry point
258
*
259
* Adds the connector callback to the connector driver.
260
*/
261
static int __init cn_proc_init(void)
262
{
263
int err;
264
265
if ((err = cn_add_callback(&cn_proc_event_id, "cn_proc",
266
&cn_proc_mcast_ctl))) {
267
printk(KERN_WARNING "cn_proc failed to register\n");
268
return err;
269
}
270
return 0;
271
}
272
273
module_init(cn_proc_init);
274
275