-
Notifications
You must be signed in to change notification settings - Fork 52.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This patch adds a connector that reports fork, exec, id change, and exit events for all processes to userspace. It replaces the fork_advisor patch that ELSA is currently using. Applications that may find these events useful include accounting/auditing (e.g. ELSA), system activity monitoring (e.g. top), security, and resource management (e.g. CKRM). Signed-off-by: Matt Helsley <matthltc@us.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
- Loading branch information
Matt Helsley
authored and
Linus Torvalds
committed
Nov 7, 2005
1 parent
49364ce
commit 9f46080
Showing
9 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
obj-$(CONFIG_CONNECTOR) += cn.o | ||
obj-$(CONFIG_PROC_EVENTS) += cn_proc.o | ||
|
||
cn-y += cn_queue.o connector.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
/* | ||
* 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> | ||
#include <linux/init.h> | ||
#include <asm/atomic.h> | ||
|
||
#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 }; | ||
|
||
/* proc_counts is used as the sequence number of the netlink message */ | ||
static DEFINE_PER_CPU(__u32, proc_event_counts) = { 0 }; | ||
|
||
static inline void get_seq(__u32 *ts, int *cpu) | ||
{ | ||
*ts = get_cpu_var(proc_event_counts)++; | ||
*cpu = smp_processor_id(); | ||
put_cpu_var(proc_counts); | ||
} | ||
|
||
void proc_fork_connector(struct task_struct *task) | ||
{ | ||
struct cn_msg *msg; | ||
struct proc_event *ev; | ||
__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); | ||
ev->what = PROC_EVENT_FORK; | ||
ev->event_data.fork.parent_pid = task->real_parent->pid; | ||
ev->event_data.fork.parent_tgid = task->real_parent->tgid; | ||
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; | ||
__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); | ||
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]; | ||
|
||
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; | ||
if (which_id == PROC_EVENT_UID) { | ||
ev->event_data.id.r.ruid = task->uid; | ||
ev->event_data.id.e.euid = task->euid; | ||
} else if (which_id == PROC_EVENT_GID) { | ||
ev->event_data.id.r.rgid = task->gid; | ||
ev->event_data.id.e.egid = task->egid; | ||
} else | ||
return; | ||
get_seq(&msg->seq, &ev->cpu); | ||
|
||
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_exit_connector(struct task_struct *task) | ||
{ | ||
struct cn_msg *msg; | ||
struct proc_event *ev; | ||
__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); | ||
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]; | ||
|
||
if (atomic_read(&proc_event_num_listeners) < 1) | ||
return; | ||
|
||
msg = (struct cn_msg*)buffer; | ||
ev = (struct proc_event*)msg->data; | ||
msg->seq = rcvd_seq; | ||
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 | ||
*/ | ||
static void cn_proc_mcast_ctl(void *data) | ||
{ | ||
struct cn_msg *msg = data; | ||
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\n"); | ||
return err; | ||
} | ||
return 0; | ||
} | ||
|
||
module_init(cn_proc_init); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
/* | ||
* cn_proc.h - process events connector | ||
* | ||
* Copyright (C) Matt Helsley, IBM Corp. 2005 | ||
* Based on cn_fork.h by Nguyen Anh Quynh and Guillaume Thouvenin | ||
* Original copyright notice follows: | ||
* Copyright (C) 2005 Nguyen Anh Quynh <aquynh@gmail.com> | ||
* Copyright (C) 2005 Guillaume Thouvenin <guillaume.thouvenin@bull.net> | ||
* | ||
* 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 | ||
*/ | ||
|
||
#ifndef CN_PROC_H | ||
#define CN_PROC_H | ||
|
||
#include <linux/types.h> | ||
#include <linux/connector.h> | ||
|
||
/* | ||
* Userspace sends this enum to register with the kernel that it is listening | ||
* for events on the connector. | ||
*/ | ||
enum proc_cn_mcast_op { | ||
PROC_CN_MCAST_LISTEN = 1, | ||
PROC_CN_MCAST_IGNORE = 2 | ||
}; | ||
|
||
/* | ||
* From the user's point of view, the process | ||
* ID is the thread group ID and thread ID is the internal | ||
* kernel "pid". So, fields are assigned as follow: | ||
* | ||
* In user space - In kernel space | ||
* | ||
* parent process ID = parent->tgid | ||
* parent thread ID = parent->pid | ||
* child process ID = child->tgid | ||
* child thread ID = child->pid | ||
*/ | ||
|
||
struct proc_event { | ||
enum what { | ||
/* Use successive bits so the enums can be used to record | ||
* sets of events as well | ||
*/ | ||
PROC_EVENT_NONE = 0x00000000, | ||
PROC_EVENT_FORK = 0x00000001, | ||
PROC_EVENT_EXEC = 0x00000002, | ||
PROC_EVENT_UID = 0x00000004, | ||
PROC_EVENT_GID = 0x00000040, | ||
/* "next" should be 0x00000400 */ | ||
/* "last" is the last process event: exit */ | ||
PROC_EVENT_EXIT = 0x80000000 | ||
} what; | ||
__u32 cpu; | ||
union { /* must be last field of proc_event struct */ | ||
struct { | ||
__u32 err; | ||
} ack; | ||
|
||
struct fork_proc_event { | ||
pid_t parent_pid; | ||
pid_t parent_tgid; | ||
pid_t child_pid; | ||
pid_t child_tgid; | ||
} fork; | ||
|
||
struct exec_proc_event { | ||
pid_t process_pid; | ||
pid_t process_tgid; | ||
} exec; | ||
|
||
struct id_proc_event { | ||
pid_t process_pid; | ||
pid_t process_tgid; | ||
union { | ||
uid_t ruid; /* current->uid */ | ||
gid_t rgid; /* current->gid */ | ||
} r; | ||
union { | ||
uid_t euid; | ||
gid_t egid; | ||
} e; | ||
} id; | ||
|
||
struct exit_proc_event { | ||
pid_t process_pid; | ||
pid_t process_tgid; | ||
__u32 exit_code, exit_signal; | ||
} exit; | ||
} event_data; | ||
}; | ||
|
||
#ifdef __KERNEL__ | ||
#ifdef CONFIG_PROC_EVENTS | ||
void proc_fork_connector(struct task_struct *task); | ||
void proc_exec_connector(struct task_struct *task); | ||
void proc_id_connector(struct task_struct *task, int which_id); | ||
void proc_exit_connector(struct task_struct *task); | ||
#else | ||
static inline void proc_fork_connector(struct task_struct *task) | ||
{} | ||
|
||
static inline void proc_exec_connector(struct task_struct *task) | ||
{} | ||
|
||
static inline void proc_id_connector(struct task_struct *task, | ||
int which_id) | ||
{} | ||
|
||
static inline void proc_exit_connector(struct task_struct *task) | ||
{} | ||
#endif /* CONFIG_PROC_EVENTS */ | ||
#endif /* __KERNEL__ */ | ||
#endif /* CN_PROC_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.