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 34 static atomic_t proc_event_num_listeners = ATOMIC_INIT(0); 35 static 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 */ 38 static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 }; 39 40 static 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 47 void 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 getnstimestamp(&ev->timestamp); 60 ev->what = PROC_EVENT_FORK; 61 ev->event_data.fork.parent_pid = task->real_parent->pid; 62 ev->event_data.fork.parent_tgid = task->real_parent->tgid; 63 ev->event_data.fork.child_pid = task->pid; 64 ev->event_data.fork.child_tgid = task->tgid; 65 66 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 67 msg->ack = 0; /* not used */ 68 msg->len = sizeof(*ev); 69 /* If cn_netlink_send() failed, the data is not sent */ 70 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); 71 } 72 73 void proc_exec_connector(struct task_struct *task) 74 { 75 struct cn_msg *msg; 76 struct proc_event *ev; 77 __u8 buffer[CN_PROC_MSG_SIZE]; 78 79 if (atomic_read(&proc_event_num_listeners) < 1) 80 return; 81 82 msg = (struct cn_msg*)buffer; 83 ev = (struct proc_event*)msg->data; 84 get_seq(&msg->seq, &ev->cpu); 85 getnstimestamp(&ev->timestamp); 86 ev->what = PROC_EVENT_EXEC; 87 ev->event_data.exec.process_pid = task->pid; 88 ev->event_data.exec.process_tgid = task->tgid; 89 90 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 91 msg->ack = 0; /* not used */ 92 msg->len = sizeof(*ev); 93 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); 94 } 95 96 void proc_id_connector(struct task_struct *task, int which_id) 97 { 98 struct cn_msg *msg; 99 struct proc_event *ev; 100 __u8 buffer[CN_PROC_MSG_SIZE]; 101 102 if (atomic_read(&proc_event_num_listeners) < 1) 103 return; 104 105 msg = (struct cn_msg*)buffer; 106 ev = (struct proc_event*)msg->data; 107 ev->what = which_id; 108 ev->event_data.id.process_pid = task->pid; 109 ev->event_data.id.process_tgid = task->tgid; 110 if (which_id == PROC_EVENT_UID) { 111 ev->event_data.id.r.ruid = task->uid; 112 ev->event_data.id.e.euid = task->euid; 113 } else if (which_id == PROC_EVENT_GID) { 114 ev->event_data.id.r.rgid = task->gid; 115 ev->event_data.id.e.egid = task->egid; 116 } else 117 return; 118 get_seq(&msg->seq, &ev->cpu); 119 getnstimestamp(&ev->timestamp); 120 121 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 122 msg->ack = 0; /* not used */ 123 msg->len = sizeof(*ev); 124 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); 125 } 126 127 void proc_exit_connector(struct task_struct *task) 128 { 129 struct cn_msg *msg; 130 struct proc_event *ev; 131 __u8 buffer[CN_PROC_MSG_SIZE]; 132 133 if (atomic_read(&proc_event_num_listeners) < 1) 134 return; 135 136 msg = (struct cn_msg*)buffer; 137 ev = (struct proc_event*)msg->data; 138 get_seq(&msg->seq, &ev->cpu); 139 getnstimestamp(&ev->timestamp); 140 ev->what = PROC_EVENT_EXIT; 141 ev->event_data.exit.process_pid = task->pid; 142 ev->event_data.exit.process_tgid = task->tgid; 143 ev->event_data.exit.exit_code = task->exit_code; 144 ev->event_data.exit.exit_signal = task->exit_signal; 145 146 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 147 msg->ack = 0; /* not used */ 148 msg->len = sizeof(*ev); 149 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); 150 } 151 152 /* 153 * Send an acknowledgement message to userspace 154 * 155 * Use 0 for success, EFOO otherwise. 156 * Note: this is the negative of conventional kernel error 157 * values because it's not being returned via syscall return 158 * mechanisms. 159 */ 160 static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) 161 { 162 struct cn_msg *msg; 163 struct proc_event *ev; 164 __u8 buffer[CN_PROC_MSG_SIZE]; 165 166 if (atomic_read(&proc_event_num_listeners) < 1) 167 return; 168 169 msg = (struct cn_msg*)buffer; 170 ev = (struct proc_event*)msg->data; 171 msg->seq = rcvd_seq; 172 getnstimestamp(&ev->timestamp); 173 ev->cpu = -1; 174 ev->what = PROC_EVENT_NONE; 175 ev->event_data.ack.err = err; 176 memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 177 msg->ack = rcvd_ack + 1; 178 msg->len = sizeof(*ev); 179 cn_netlink_send(msg, CN_IDX_PROC, GFP_KERNEL); 180 } 181 182 /** 183 * cn_proc_mcast_ctl 184 * @data: message sent from userspace via the connector 185 */ 186 static void cn_proc_mcast_ctl(void *data) 187 { 188 struct cn_msg *msg = data; 189 enum proc_cn_mcast_op *mc_op = NULL; 190 int err = 0; 191 192 if (msg->len != sizeof(*mc_op)) 193 return; 194 195 mc_op = (enum proc_cn_mcast_op*)msg->data; 196 switch (*mc_op) { 197 case PROC_CN_MCAST_LISTEN: 198 atomic_inc(&proc_event_num_listeners); 199 break; 200 case PROC_CN_MCAST_IGNORE: 201 atomic_dec(&proc_event_num_listeners); 202 break; 203 default: 204 err = EINVAL; 205 break; 206 } 207 cn_proc_ack(err, msg->seq, msg->ack); 208 } 209 210 /* 211 * cn_proc_init - initialization entry point 212 * 213 * Adds the connector callback to the connector driver. 214 */ 215 static int __init cn_proc_init(void) 216 { 217 int err; 218 219 if ((err = cn_add_callback(&cn_proc_event_id, "cn_proc", 220 &cn_proc_mcast_ctl))) { 221 printk(KERN_WARNING "cn_proc failed to register\n"); 222 return err; 223 } 224 return 0; 225 } 226 227 module_init(cn_proc_init); 228