19f46080cSMatt Helsley /* 29f46080cSMatt Helsley * cn_proc.c - process events connector 39f46080cSMatt Helsley * 49f46080cSMatt Helsley * Copyright (C) Matt Helsley, IBM Corp. 2005 59f46080cSMatt Helsley * Based on cn_fork.c by Guillaume Thouvenin <guillaume.thouvenin@bull.net> 69f46080cSMatt Helsley * Original copyright notice follows: 79f46080cSMatt Helsley * Copyright (C) 2005 BULL SA. 89f46080cSMatt Helsley * 99f46080cSMatt Helsley * 109f46080cSMatt Helsley * This program is free software; you can redistribute it and/or modify 119f46080cSMatt Helsley * it under the terms of the GNU General Public License as published by 129f46080cSMatt Helsley * the Free Software Foundation; either version 2 of the License, or 139f46080cSMatt Helsley * (at your option) any later version. 149f46080cSMatt Helsley * 159f46080cSMatt Helsley * This program is distributed in the hope that it will be useful, 169f46080cSMatt Helsley * but WITHOUT ANY WARRANTY; without even the implied warranty of 179f46080cSMatt Helsley * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 189f46080cSMatt Helsley * GNU General Public License for more details. 199f46080cSMatt Helsley * 209f46080cSMatt Helsley * You should have received a copy of the GNU General Public License 219f46080cSMatt Helsley * along with this program; if not, write to the Free Software 229f46080cSMatt Helsley * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 239f46080cSMatt Helsley */ 249f46080cSMatt Helsley 259f46080cSMatt Helsley #include <linux/kernel.h> 26caf3c9dcSMatt Helsley #include <linux/ktime.h> 279f46080cSMatt Helsley #include <linux/init.h> 281d31a4eaSMatt Helsley #include <linux/connector.h> 295a0e3ad6STejun Heo #include <linux/gfp.h> 30f701e5b7SVladimir Zapolskiy #include <linux/ptrace.h> 3160063497SArun Sharma #include <linux/atomic.h> 329582d901SEric W. Biederman #include <linux/pid_namespace.h> 3360063497SArun Sharma 349f46080cSMatt Helsley #include <linux/cn_proc.h> 359f46080cSMatt Helsley 361ca1a4cfSChris Metcalf /* 371ca1a4cfSChris Metcalf * Size of a cn_msg followed by a proc_event structure. Since the 381ca1a4cfSChris Metcalf * sizeof struct cn_msg is a multiple of 4 bytes, but not 8 bytes, we 391ca1a4cfSChris Metcalf * add one 4-byte word to the size here, and then start the actual 401ca1a4cfSChris Metcalf * cn_msg structure 4 bytes into the stack buffer. The result is that 411ca1a4cfSChris Metcalf * the immediately following proc_event structure is aligned to 8 bytes. 421ca1a4cfSChris Metcalf */ 431ca1a4cfSChris Metcalf #define CN_PROC_MSG_SIZE (sizeof(struct cn_msg) + sizeof(struct proc_event) + 4) 441ca1a4cfSChris Metcalf 451ca1a4cfSChris Metcalf /* See comment above; we test our assumption about sizeof struct cn_msg here. */ 461ca1a4cfSChris Metcalf static inline struct cn_msg *buffer_to_cn_msg(__u8 *buffer) 471ca1a4cfSChris Metcalf { 481ca1a4cfSChris Metcalf BUILD_BUG_ON(sizeof(struct cn_msg) != 20); 491ca1a4cfSChris Metcalf return (struct cn_msg *)(buffer + 4); 501ca1a4cfSChris Metcalf } 519f46080cSMatt Helsley 529f46080cSMatt Helsley static atomic_t proc_event_num_listeners = ATOMIC_INIT(0); 539f46080cSMatt Helsley static struct cb_id cn_proc_event_id = { CN_IDX_PROC, CN_VAL_PROC }; 549f46080cSMatt Helsley 55cc398c2eSDavid S. Miller /* proc_event_counts is used as the sequence number of the netlink message */ 569f46080cSMatt Helsley static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 }; 579f46080cSMatt Helsley 58ab8ed951SAaron Campbell static inline void send_msg(struct cn_msg *msg) 599f46080cSMatt Helsley { 603ea9f683SChristoph Lameter preempt_disable(); 61ab8ed951SAaron Campbell 62ab8ed951SAaron Campbell msg->seq = __this_cpu_inc_return(proc_event_counts) - 1; 63ab8ed951SAaron Campbell ((struct proc_event *)msg->data)->cpu = smp_processor_id(); 64ab8ed951SAaron Campbell 65ab8ed951SAaron Campbell /* 66ab8ed951SAaron Campbell * Preemption remains disabled during send to ensure the messages are 67ab8ed951SAaron Campbell * ordered according to their sequence numbers. 68ab8ed951SAaron Campbell * 69ab8ed951SAaron Campbell * If cn_netlink_send() fails, the data is not sent. 70ab8ed951SAaron Campbell */ 71ab8ed951SAaron Campbell cn_netlink_send(msg, 0, CN_IDX_PROC, GFP_NOWAIT); 72ab8ed951SAaron Campbell 733ea9f683SChristoph Lameter preempt_enable(); 749f46080cSMatt Helsley } 759f46080cSMatt Helsley 769f46080cSMatt Helsley void proc_fork_connector(struct task_struct *task) 779f46080cSMatt Helsley { 789f46080cSMatt Helsley struct cn_msg *msg; 799f46080cSMatt Helsley struct proc_event *ev; 801ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 819e8f90dfSOleg Nesterov struct task_struct *parent; 829f46080cSMatt Helsley 839f46080cSMatt Helsley if (atomic_read(&proc_event_num_listeners) < 1) 849f46080cSMatt Helsley return; 859f46080cSMatt Helsley 861ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 879f46080cSMatt Helsley ev = (struct proc_event *)msg->data; 88e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 899e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 909f46080cSMatt Helsley ev->what = PROC_EVENT_FORK; 919e8f90dfSOleg Nesterov rcu_read_lock(); 929e8f90dfSOleg Nesterov parent = rcu_dereference(task->real_parent); 939e8f90dfSOleg Nesterov ev->event_data.fork.parent_pid = parent->pid; 949e8f90dfSOleg Nesterov ev->event_data.fork.parent_tgid = parent->tgid; 959e8f90dfSOleg Nesterov rcu_read_unlock(); 969f46080cSMatt Helsley ev->event_data.fork.child_pid = task->pid; 979f46080cSMatt Helsley ev->event_data.fork.child_tgid = task->tgid; 989f46080cSMatt Helsley 999f46080cSMatt Helsley memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 1009f46080cSMatt Helsley msg->ack = 0; /* not used */ 1019f46080cSMatt Helsley msg->len = sizeof(*ev); 102e727ca82SMathias Krause msg->flags = 0; /* not used */ 103ab8ed951SAaron Campbell send_msg(msg); 1049f46080cSMatt Helsley } 1059f46080cSMatt Helsley 1069f46080cSMatt Helsley void proc_exec_connector(struct task_struct *task) 1079f46080cSMatt Helsley { 1089f46080cSMatt Helsley struct cn_msg *msg; 1099f46080cSMatt Helsley struct proc_event *ev; 1101ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 1119f46080cSMatt Helsley 1129f46080cSMatt Helsley if (atomic_read(&proc_event_num_listeners) < 1) 1139f46080cSMatt Helsley return; 1149f46080cSMatt Helsley 1151ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 1169f46080cSMatt Helsley ev = (struct proc_event *)msg->data; 117e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 1189e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 1199f46080cSMatt Helsley ev->what = PROC_EVENT_EXEC; 1209f46080cSMatt Helsley ev->event_data.exec.process_pid = task->pid; 1219f46080cSMatt Helsley ev->event_data.exec.process_tgid = task->tgid; 1229f46080cSMatt Helsley 1239f46080cSMatt Helsley memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 1249f46080cSMatt Helsley msg->ack = 0; /* not used */ 1259f46080cSMatt Helsley msg->len = sizeof(*ev); 126e727ca82SMathias Krause msg->flags = 0; /* not used */ 127ab8ed951SAaron Campbell send_msg(msg); 1289f46080cSMatt Helsley } 1299f46080cSMatt Helsley 1309f46080cSMatt Helsley void proc_id_connector(struct task_struct *task, int which_id) 1319f46080cSMatt Helsley { 1329f46080cSMatt Helsley struct cn_msg *msg; 1339f46080cSMatt Helsley struct proc_event *ev; 1341ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 135c69e8d9cSDavid Howells const struct cred *cred; 1369f46080cSMatt Helsley 1379f46080cSMatt Helsley if (atomic_read(&proc_event_num_listeners) < 1) 1389f46080cSMatt Helsley return; 1399f46080cSMatt Helsley 1401ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 1419f46080cSMatt Helsley ev = (struct proc_event *)msg->data; 142e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 1439f46080cSMatt Helsley ev->what = which_id; 1449f46080cSMatt Helsley ev->event_data.id.process_pid = task->pid; 1459f46080cSMatt Helsley ev->event_data.id.process_tgid = task->tgid; 146c69e8d9cSDavid Howells rcu_read_lock(); 147c69e8d9cSDavid Howells cred = __task_cred(task); 1489f46080cSMatt Helsley if (which_id == PROC_EVENT_UID) { 1499582d901SEric W. Biederman ev->event_data.id.r.ruid = from_kuid_munged(&init_user_ns, cred->uid); 1509582d901SEric W. Biederman ev->event_data.id.e.euid = from_kuid_munged(&init_user_ns, cred->euid); 1519f46080cSMatt Helsley } else if (which_id == PROC_EVENT_GID) { 1529582d901SEric W. Biederman ev->event_data.id.r.rgid = from_kgid_munged(&init_user_ns, cred->gid); 1539582d901SEric W. Biederman ev->event_data.id.e.egid = from_kgid_munged(&init_user_ns, cred->egid); 154c69e8d9cSDavid Howells } else { 155c69e8d9cSDavid Howells rcu_read_unlock(); 1569f46080cSMatt Helsley return; 157c69e8d9cSDavid Howells } 158c69e8d9cSDavid Howells rcu_read_unlock(); 1599e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 1609f46080cSMatt Helsley 1619f46080cSMatt Helsley memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 1629f46080cSMatt Helsley msg->ack = 0; /* not used */ 1639f46080cSMatt Helsley msg->len = sizeof(*ev); 164e727ca82SMathias Krause msg->flags = 0; /* not used */ 165ab8ed951SAaron Campbell send_msg(msg); 1669f46080cSMatt Helsley } 1679f46080cSMatt Helsley 16802b51df1SScott James Remnant void proc_sid_connector(struct task_struct *task) 16902b51df1SScott James Remnant { 17002b51df1SScott James Remnant struct cn_msg *msg; 17102b51df1SScott James Remnant struct proc_event *ev; 1721ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 17302b51df1SScott James Remnant 17402b51df1SScott James Remnant if (atomic_read(&proc_event_num_listeners) < 1) 17502b51df1SScott James Remnant return; 17602b51df1SScott James Remnant 1771ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 17802b51df1SScott James Remnant ev = (struct proc_event *)msg->data; 179e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 1809e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 18102b51df1SScott James Remnant ev->what = PROC_EVENT_SID; 18202b51df1SScott James Remnant ev->event_data.sid.process_pid = task->pid; 18302b51df1SScott James Remnant ev->event_data.sid.process_tgid = task->tgid; 18402b51df1SScott James Remnant 18502b51df1SScott James Remnant memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 18602b51df1SScott James Remnant msg->ack = 0; /* not used */ 18702b51df1SScott James Remnant msg->len = sizeof(*ev); 188e727ca82SMathias Krause msg->flags = 0; /* not used */ 189ab8ed951SAaron Campbell send_msg(msg); 19002b51df1SScott James Remnant } 19102b51df1SScott James Remnant 192f701e5b7SVladimir Zapolskiy void proc_ptrace_connector(struct task_struct *task, int ptrace_id) 193f701e5b7SVladimir Zapolskiy { 194f701e5b7SVladimir Zapolskiy struct cn_msg *msg; 195f701e5b7SVladimir Zapolskiy struct proc_event *ev; 1961ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 197f701e5b7SVladimir Zapolskiy 198f701e5b7SVladimir Zapolskiy if (atomic_read(&proc_event_num_listeners) < 1) 199f701e5b7SVladimir Zapolskiy return; 200f701e5b7SVladimir Zapolskiy 2011ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 202f701e5b7SVladimir Zapolskiy ev = (struct proc_event *)msg->data; 203e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 2049e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 205f701e5b7SVladimir Zapolskiy ev->what = PROC_EVENT_PTRACE; 206f701e5b7SVladimir Zapolskiy ev->event_data.ptrace.process_pid = task->pid; 207f701e5b7SVladimir Zapolskiy ev->event_data.ptrace.process_tgid = task->tgid; 208f701e5b7SVladimir Zapolskiy if (ptrace_id == PTRACE_ATTACH) { 209f701e5b7SVladimir Zapolskiy ev->event_data.ptrace.tracer_pid = current->pid; 210f701e5b7SVladimir Zapolskiy ev->event_data.ptrace.tracer_tgid = current->tgid; 211f701e5b7SVladimir Zapolskiy } else if (ptrace_id == PTRACE_DETACH) { 212f701e5b7SVladimir Zapolskiy ev->event_data.ptrace.tracer_pid = 0; 213f701e5b7SVladimir Zapolskiy ev->event_data.ptrace.tracer_tgid = 0; 214f701e5b7SVladimir Zapolskiy } else 215f701e5b7SVladimir Zapolskiy return; 216f701e5b7SVladimir Zapolskiy 217f701e5b7SVladimir Zapolskiy memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 218f701e5b7SVladimir Zapolskiy msg->ack = 0; /* not used */ 219f701e5b7SVladimir Zapolskiy msg->len = sizeof(*ev); 220e727ca82SMathias Krause msg->flags = 0; /* not used */ 221ab8ed951SAaron Campbell send_msg(msg); 222f701e5b7SVladimir Zapolskiy } 223f701e5b7SVladimir Zapolskiy 224f786ecbaSVladimir Zapolskiy void proc_comm_connector(struct task_struct *task) 225f786ecbaSVladimir Zapolskiy { 226f786ecbaSVladimir Zapolskiy struct cn_msg *msg; 227f786ecbaSVladimir Zapolskiy struct proc_event *ev; 2281ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 229f786ecbaSVladimir Zapolskiy 230f786ecbaSVladimir Zapolskiy if (atomic_read(&proc_event_num_listeners) < 1) 231f786ecbaSVladimir Zapolskiy return; 232f786ecbaSVladimir Zapolskiy 2331ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 234f786ecbaSVladimir Zapolskiy ev = (struct proc_event *)msg->data; 235e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 2369e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 237f786ecbaSVladimir Zapolskiy ev->what = PROC_EVENT_COMM; 238f786ecbaSVladimir Zapolskiy ev->event_data.comm.process_pid = task->pid; 239f786ecbaSVladimir Zapolskiy ev->event_data.comm.process_tgid = task->tgid; 240f786ecbaSVladimir Zapolskiy get_task_comm(ev->event_data.comm.comm, task); 241f786ecbaSVladimir Zapolskiy 242f786ecbaSVladimir Zapolskiy memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 243f786ecbaSVladimir Zapolskiy msg->ack = 0; /* not used */ 244f786ecbaSVladimir Zapolskiy msg->len = sizeof(*ev); 245e727ca82SMathias Krause msg->flags = 0; /* not used */ 246ab8ed951SAaron Campbell send_msg(msg); 247f786ecbaSVladimir Zapolskiy } 248f786ecbaSVladimir Zapolskiy 2492b5faa4cSJesper Derehag void proc_coredump_connector(struct task_struct *task) 2502b5faa4cSJesper Derehag { 2512b5faa4cSJesper Derehag struct cn_msg *msg; 2522b5faa4cSJesper Derehag struct proc_event *ev; 2536d2b0f02SLi RongQing struct task_struct *parent; 2541ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 2552b5faa4cSJesper Derehag 2562b5faa4cSJesper Derehag if (atomic_read(&proc_event_num_listeners) < 1) 2572b5faa4cSJesper Derehag return; 2582b5faa4cSJesper Derehag 2591ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 2602b5faa4cSJesper Derehag ev = (struct proc_event *)msg->data; 261e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 2629e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 2632b5faa4cSJesper Derehag ev->what = PROC_EVENT_COREDUMP; 2642b5faa4cSJesper Derehag ev->event_data.coredump.process_pid = task->pid; 2652b5faa4cSJesper Derehag ev->event_data.coredump.process_tgid = task->tgid; 2666d2b0f02SLi RongQing 2676d2b0f02SLi RongQing rcu_read_lock(); 2686d2b0f02SLi RongQing if (pid_alive(task)) { 2696d2b0f02SLi RongQing parent = rcu_dereference(task->real_parent); 2706d2b0f02SLi RongQing ev->event_data.coredump.parent_pid = parent->pid; 2716d2b0f02SLi RongQing ev->event_data.coredump.parent_tgid = parent->tgid; 2726d2b0f02SLi RongQing } 2736d2b0f02SLi RongQing rcu_read_unlock(); 2742b5faa4cSJesper Derehag 2752b5faa4cSJesper Derehag memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 2762b5faa4cSJesper Derehag msg->ack = 0; /* not used */ 2772b5faa4cSJesper Derehag msg->len = sizeof(*ev); 278e727ca82SMathias Krause msg->flags = 0; /* not used */ 279ab8ed951SAaron Campbell send_msg(msg); 2802b5faa4cSJesper Derehag } 2812b5faa4cSJesper Derehag 2829f46080cSMatt Helsley void proc_exit_connector(struct task_struct *task) 2839f46080cSMatt Helsley { 2849f46080cSMatt Helsley struct cn_msg *msg; 2859f46080cSMatt Helsley struct proc_event *ev; 2866d2b0f02SLi RongQing struct task_struct *parent; 2871ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 2889f46080cSMatt Helsley 2899f46080cSMatt Helsley if (atomic_read(&proc_event_num_listeners) < 1) 2909f46080cSMatt Helsley return; 2919f46080cSMatt Helsley 2921ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 2939f46080cSMatt Helsley ev = (struct proc_event *)msg->data; 294e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 2959e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 2969f46080cSMatt Helsley ev->what = PROC_EVENT_EXIT; 2979f46080cSMatt Helsley ev->event_data.exit.process_pid = task->pid; 2989f46080cSMatt Helsley ev->event_data.exit.process_tgid = task->tgid; 2999f46080cSMatt Helsley ev->event_data.exit.exit_code = task->exit_code; 3009f46080cSMatt Helsley ev->event_data.exit.exit_signal = task->exit_signal; 3016d2b0f02SLi RongQing 3026d2b0f02SLi RongQing rcu_read_lock(); 3036d2b0f02SLi RongQing if (pid_alive(task)) { 3046d2b0f02SLi RongQing parent = rcu_dereference(task->real_parent); 3056d2b0f02SLi RongQing ev->event_data.exit.parent_pid = parent->pid; 3066d2b0f02SLi RongQing ev->event_data.exit.parent_tgid = parent->tgid; 3076d2b0f02SLi RongQing } 3086d2b0f02SLi RongQing rcu_read_unlock(); 3099f46080cSMatt Helsley 3109f46080cSMatt Helsley memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 3119f46080cSMatt Helsley msg->ack = 0; /* not used */ 3129f46080cSMatt Helsley msg->len = sizeof(*ev); 313e727ca82SMathias Krause msg->flags = 0; /* not used */ 314ab8ed951SAaron Campbell send_msg(msg); 3159f46080cSMatt Helsley } 3169f46080cSMatt Helsley 3179f46080cSMatt Helsley /* 3189f46080cSMatt Helsley * Send an acknowledgement message to userspace 3199f46080cSMatt Helsley * 3209f46080cSMatt Helsley * Use 0 for success, EFOO otherwise. 3219f46080cSMatt Helsley * Note: this is the negative of conventional kernel error 3229f46080cSMatt Helsley * values because it's not being returned via syscall return 3239f46080cSMatt Helsley * mechanisms. 3249f46080cSMatt Helsley */ 3259f46080cSMatt Helsley static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) 3269f46080cSMatt Helsley { 3279f46080cSMatt Helsley struct cn_msg *msg; 3289f46080cSMatt Helsley struct proc_event *ev; 3291ca1a4cfSChris Metcalf __u8 buffer[CN_PROC_MSG_SIZE] __aligned(8); 3309f46080cSMatt Helsley 3319f46080cSMatt Helsley if (atomic_read(&proc_event_num_listeners) < 1) 3329f46080cSMatt Helsley return; 3339f46080cSMatt Helsley 3341ca1a4cfSChris Metcalf msg = buffer_to_cn_msg(buffer); 3359f46080cSMatt Helsley ev = (struct proc_event *)msg->data; 336e727ca82SMathias Krause memset(&ev->event_data, 0, sizeof(ev->event_data)); 3379f46080cSMatt Helsley msg->seq = rcvd_seq; 3389e93f21bSThomas Gleixner ev->timestamp_ns = ktime_get_ns(); 3399f46080cSMatt Helsley ev->cpu = -1; 3409f46080cSMatt Helsley ev->what = PROC_EVENT_NONE; 3419f46080cSMatt Helsley ev->event_data.ack.err = err; 3429f46080cSMatt Helsley memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id)); 3439f46080cSMatt Helsley msg->ack = rcvd_ack + 1; 3449f46080cSMatt Helsley msg->len = sizeof(*ev); 345e727ca82SMathias Krause msg->flags = 0; /* not used */ 346ab8ed951SAaron Campbell send_msg(msg); 3479f46080cSMatt Helsley } 3489f46080cSMatt Helsley 3499f46080cSMatt Helsley /** 3509f46080cSMatt Helsley * cn_proc_mcast_ctl 3519f46080cSMatt Helsley * @data: message sent from userspace via the connector 3529f46080cSMatt Helsley */ 353f0b25932SStephen Boyd static void cn_proc_mcast_ctl(struct cn_msg *msg, 354f0b25932SStephen Boyd struct netlink_skb_parms *nsp) 3559f46080cSMatt Helsley { 3569f46080cSMatt Helsley enum proc_cn_mcast_op *mc_op = NULL; 3579f46080cSMatt Helsley int err = 0; 3589f46080cSMatt Helsley 3599f46080cSMatt Helsley if (msg->len != sizeof(*mc_op)) 3609f46080cSMatt Helsley return; 3619f46080cSMatt Helsley 3629582d901SEric W. Biederman /* 3639582d901SEric W. Biederman * Events are reported with respect to the initial pid 3649582d901SEric W. Biederman * and user namespaces so ignore requestors from 3659582d901SEric W. Biederman * other namespaces. 3669582d901SEric W. Biederman */ 3679582d901SEric W. Biederman if ((current_user_ns() != &init_user_ns) || 3689582d901SEric W. Biederman (task_active_pid_ns(current) != &init_pid_ns)) 3699582d901SEric W. Biederman return; 3709582d901SEric W. Biederman 371e70ab977SKees Cook /* Can only change if privileged. */ 37290f62cf3SEric W. Biederman if (!__netlink_ns_capable(nsp, &init_user_ns, CAP_NET_ADMIN)) { 373e70ab977SKees Cook err = EPERM; 374e70ab977SKees Cook goto out; 375e70ab977SKees Cook } 376e70ab977SKees Cook 3779f46080cSMatt Helsley mc_op = (enum proc_cn_mcast_op *)msg->data; 3789f46080cSMatt Helsley switch (*mc_op) { 3799f46080cSMatt Helsley case PROC_CN_MCAST_LISTEN: 3809f46080cSMatt Helsley atomic_inc(&proc_event_num_listeners); 3819f46080cSMatt Helsley break; 3829f46080cSMatt Helsley case PROC_CN_MCAST_IGNORE: 3839f46080cSMatt Helsley atomic_dec(&proc_event_num_listeners); 3849f46080cSMatt Helsley break; 3859f46080cSMatt Helsley default: 3869f46080cSMatt Helsley err = EINVAL; 3879f46080cSMatt Helsley break; 3889f46080cSMatt Helsley } 389e70ab977SKees Cook 390e70ab977SKees Cook out: 3919f46080cSMatt Helsley cn_proc_ack(err, msg->seq, msg->ack); 3929f46080cSMatt Helsley } 3939f46080cSMatt Helsley 3949f46080cSMatt Helsley /* 3959f46080cSMatt Helsley * cn_proc_init - initialization entry point 3969f46080cSMatt Helsley * 3979f46080cSMatt Helsley * Adds the connector callback to the connector driver. 3989f46080cSMatt Helsley */ 3999f46080cSMatt Helsley static int __init cn_proc_init(void) 4009f46080cSMatt Helsley { 401f3c48eccSValentin Ilie int err = cn_add_callback(&cn_proc_event_id, 402f3c48eccSValentin Ilie "cn_proc", 403f3c48eccSValentin Ilie &cn_proc_mcast_ctl); 404f3c48eccSValentin Ilie if (err) { 405f3c48eccSValentin Ilie pr_warn("cn_proc failed to register\n"); 4069f46080cSMatt Helsley return err; 4079f46080cSMatt Helsley } 4089f46080cSMatt Helsley return 0; 4099f46080cSMatt Helsley } 4108297f2d9SPaul Gortmaker device_initcall(cn_proc_init); 411