From: Guillaume T. <gui...@bu...> - 2004-12-17 14:59:18
|
Hello, Here is the fork historic module. This module keeps the historic about the creation of processes and it gives this information to a user space application if one is registered. Currently, only one application can use it. If needed it could be extended to several applications. Here is how it works: The module registers itself to the kernel via a LSM hook in order to receive a signal when a fork occurs in the kernel. We are using the "task_alloc_security" security hook. When a fork occurs, information is following up to a registered application. When an application registers itself, it gives to the fork historic driver a RT signal that will be used to pass the information. The application registers to this driver by using ioctl command on the /dev/fh interface. This driver is used by the daemon part of ELSA project. The daemon manages groups of processes called jobs in order to do per-group of processes accounting. I tested the module with kernel 2.6.9 and also with 2.6.10-rc3-mm1 and I was able to manage jobs in user space by using the job daemon which is a part of the Enhanced Linux System Accounting. ELSA can be downloaded from http://elsa.sf.net Andrew, do you think that this module can be integrated in your development tree? I hope that it can be useful for someone else. Any comments and suggestions are welcome. Guillaume drivers/char/Kconfig | 23 ++++ drivers/char/Makefile | 2 drivers/char/fork_historic.c | 211 ++++++++++++++++++++++++++++... include/linux/fork_historic.h | 36 +++++++ 4 files changed, 272 insertions(+) Signed-off-by: Guillaume Thouvenin <gui...@bu...> diff -uprN -X dontdiff linux-2.6.10-rc3-mm1/drivers/char/fork_historic.c linux-2.6.10-rc3-mm1+fh/drivers/char/fork_historic.c --- linux-2.6.10-rc3-mm1/drivers/char/fork_historic.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-rc3-mm1+fh/drivers/char/fork_historic.c 2004-12-17 14:03:46.147439208 +0100 @@ -0,0 +1,211 @@ +/* + * fork_historic.c - fork historic interface + * + * Author: Guillaume Thouvenin <gui...@bu...> + * + * This driver allows to keep the historic about the creation of + * processes and it gives this information to a user space application. + * Currently, only one application can use it. If needed it could be + * extended to several applications. + * + * It registers itself to the kernel via a LSM hook in order to receive + * a signal when a fork occurs in the kernel. When a fork occurs, it + * follows up the information to an application if one is registered. When + * an application registers itself, it gives to the driver a RT signal + * that will be used to pass the information. The application communicates to + * this driver by using ioctl command on the /dev/fh interface. + * + * + * 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, version 2. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include <linux/module.h> /* for all modules */ +#include <linux/kernel.h> /* for KERN_ALERT */ +#include <linux/init.h> /* for the macros */ +#include <linux/spinlock.h> /* for spinlock */ +#include <linux/sched.h> /* for task_struct */ +#include <linux/fs.h> /* for register_chrdev */ +#include <linux/security.h> /* for LSM hook */ +#include <linux/fork_historic.h> + +#include <asm/errno.h> /* used to set ernno */ +#include <asm/uaccess.h> /* used to copy from user */ + +static int fh_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int fh_task_alloc_security(struct task_struct *p); + +/* fh_lock protects fh_pid and fh_sig */ +static spinlock_t fh_lock = SPIN_LOCK_UNLOCKED; +static int fh_pid; +static int fh_sig; + + +/* this is the major number dynamically got when registered */ +static int fh_major; + +struct security_operations fh_sops = { + .task_alloc_security = fh_task_alloc_security, +}; + +static struct file_operations fh_fops = { + .owner = THIS_MODULE, + .ioctl = fh_ioctl, +}; + +static int +fh_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct fh_ioctl_parm iarg; + int retval = 0; + + /* We can make some checks */ + if (_IOC_TYPE(cmd) != FH_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > FH_MAXNR) + return -ENOTTY; + if ((cmd != FH_REGISTER) && (cmd != FH_UNREGISTER)) + return -ENOTTY; + + /* Recover ioctl parameters */ + if (copy_from_user(&iarg, (void __user *) arg, + sizeof(struct fh_ioctl_parm))) + return -EFAULT; + + switch (cmd) { + case FH_REGISTER: + spin_lock_irq(&fh_lock); + if (fh_pid == 0) { + /* There is no application already registered */ + fh_pid = iarg.pid; + fh_sig = iarg.sig; + } else + /* Someone uses this module */ + retval = -EUSERS; + spin_unlock_irq(&fh_lock); + break; + case FH_UNREGISTER: + spin_lock_irq(&fh_lock); + fh_pid = 0; + fh_sig = 0; + spin_unlock_irq(&fh_lock); + break; + default: + /* + * The POSIX standard, states that if an inappropriate ioctl + * command has been issued, then -ENOTTY should be returned. + */ + retval = -ENOTTY; + }; + + return retval; +} + +/** + * fh_task_alloc_security - send SIGRTFORK signal to a register process + * @ppid: parent ID + * @cpid: child ID + * + * This routine send a SIGRTFORK to a register process if there is one. We use + * a real time signal because we don't want to loose information. With non real + * time signals, additional signals of that same type that arrive in the + * meantime might be discarded. + * + */ +static int fh_task_alloc_security(struct task_struct *p) +{ + struct siginfo sinfo; + struct task_struct *fh_p; + + /* + * We need to be sure that fh_pid is not modified when sending + * fork information. As we check if the process still exists and + * if not, we change the global fh_pid, we protect this part. + * A process can be killed and still registered... + */ + spin_lock_irq(&fh_lock); + if (fh_pid) { + read_lock(&tasklist_lock); + fh_p = find_task_by_pid(fh_pid); + if (fh_p) { + sinfo.si_signo = fh_sig; + sinfo.si_errno = 0; + sinfo.si_code = SI_ASYNCIO; + /* + * should be the sender ID but in our case, it is set + * to the pid of the process that initiates the fork. + */ + sinfo.si_pid = current->pid; + /* + * process created during the fork. This information + * is needed to keep jobs coherent. + */ + sinfo.si_value.sival_int = p->pid; + + send_sig_info(fh_sig, &sinfo, fh_p); + } else { + /* + * process #fh_pid doesn't exist so we don't need to + * check that each time and we reset the values. + */ + fh_pid = 0; + fh_sig = 0; + } + read_unlock(&tasklist_lock); + } + spin_unlock_irq(&fh_lock); + + return 0; +} + +/** + * fh_init - called when module is loaded + * + * Register the character device. It aslo register an LSM hook + * in order to be inform by the creation of a new process. + */ +static int __init fh_init(void) +{ + fh_major = register_chrdev(0, "fh", &fh_fops); + if (!fh_major) { + printk(KERN_ERR "fh: failed to register fh device\n"); + return -EIO; + } + + if (register_security(&fh_sops)) { + printk(KERN_ERR "fh: failed to set the fork hook \n"); + return -EIO; + } + + printk(KERN_INFO "fh: fork historic started\n"); + return 0; +} + +/** + * fh_exit - called when module is unloaded + * + * Un-register the character device and the LSM hook. + */ +static void __exit fh_exit(void) +{ + if (unregister_security(&fh_sops)) + printk(KERN_ERR "fh: Unable to register with kernel\n"); + + unregister_chrdev(fh_major, "fh"); + + printk(KERN_INFO "fh: fork historic ended\n"); +} + +module_init(fh_init); +module_exit(fh_exit); + +MODULE_AUTHOR("Guillaume Thouvenin <gui...@bu...>"); +MODULE_DESCRIPTION("Fork Historic Module"); +MODULE_LICENSE("GPL"); diff -uprN -X dontdiff linux-2.6.10-rc3-mm1/drivers/char/Kconfig linux-2.6.10-rc3-mm1+fh/drivers/char/Kconfig --- linux-2.6.10-rc3-mm1/drivers/char/Kconfig 2004-12-03 22:52:14.000000000 +0100 +++ linux-2.6.10-rc3-mm1+fh/drivers/char/Kconfig 2004-12-17 14:04:08.753002640 +0100 @@ -4,6 +4,29 @@ menu "Character devices" +config FORK_HISTORIC + tristate "Fork historic" + depends on SECURITY + default n + ---help--- + This driver allows to keep the historic about the creation of + processes and it gives this information to a user space + application. Currently, only one application can use it. If + needed it could be extended to several applications. + + It registers itself to the kernel via a LSM hook in order to + receive a signal when a fork occurs in the kernel. When a fork + occures, it follows up the information to an application if one + is registered. When an application registers itself, it gives to + the driver a RT signal that will be used to pass the information. + + The application communicates to this driver by using ioctl command + on the "/dev/fh" interface. So, to be able to use it you need to + create the "/dev/fh" character device with the correct major number + that can be found by looking into the "/proc/devices". + + If unsure, say N. + config VT bool "Virtual terminal" if EMBEDDED select INPUT diff -uprN -X dontdiff linux-2.6.10-rc3-mm1/drivers/char/Makefile linux-2.6.10-rc3-mm1+fh/drivers/char/Makefile --- linux-2.6.10-rc3-mm1/drivers/char/Makefile 2004-12-03 22:54:50.000000000 +0100 +++ linux-2.6.10-rc3-mm1+fh/drivers/char/Makefile 2004-12-17 09:59:22.000000000 +0100 @@ -91,6 +91,8 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi/ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o +obj-$(CONFIG_FORK_HISTORIC) += fork_historic.o + # Files generated that shall be removed upon make clean clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c diff -uprN -X dontdiff linux-2.6.10-rc3-mm1/include/linux/fork_historic.h linux-2.6.10-rc3-mm1+fh/include/linux/fork_historic.h --- linux-2.6.10-rc3-mm1/include/linux/fork_historic.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.10-rc3-mm1+fh/include/linux/fork_historic.h 2004-12-17 09:58:21.000000000 +0100 @@ -0,0 +1,36 @@ +/* + * fork_historic.h - fork historic interface header file + * + * Author: Guillaume Thouvenin <gui...@bu...> + * + * 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, version 2. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef FORK_HISTORIC_H +#define FORK_HISTORIC_H + +#include <linux/ioctl.h> + +/* Information given by the registered application */ +struct fh_ioctl_parm { + int pid; + int sig; +}; + +#define FH_ERRNO 38 + +/* IOCTL numbers */ +/* If you add a new IOCTL number don't forget to update FH_MAXNR */ +#define FH_MAGIC 0x35 +#define FH_REGISTER _IO(FH_MAGIC,0) +#define FH_UNREGISTER _IO(FH_MAGIC,1) + +#define FH_MAXNR 1 + +#endif /* !(FORK_HISTORIC_H) */ |
From: Andi K. <ak...@su...> - 2004-12-17 15:11:20
|
> +/* IOCTL numbers */ > +/* If you add a new IOCTL number don't forget to update FH_MAXNR */ > +#define FH_MAGIC 0x35 > +#define FH_REGISTER _IO(FH_MAGIC,0) > +#define FH_UNREGISTER _IO(FH_MAGIC,1) Is this really unique? 32bit emulation currently needs unique ioctl numbers. -Andi |
From: David V. <dv...@ca...> - 2004-12-17 15:25:25
|
Guillaume Thouvenin wrote: > Hello, > > Here is the fork historic module. This module keeps the historic about Shouldn't it be "history" (noun) instead of "historic" (adjective)? It's kinda confusing as is. David Vrabel |
From: Randy.Dunlap <rdd...@os...> - 2004-12-17 17:11:40
|
David Vrabel wrote: > Guillaume Thouvenin wrote: > >> Hello, >> >> Here is the fork historic module. This module keeps the historic about > > > Shouldn't it be "history" (noun) instead of "historic" (adjective)? It's > kinda confusing as is. Yes, there are several typo-like corrections needed in the Help text also, if this is merged... -- ~Randy |
From: Erich F. <ef...@hp...> - 2004-12-17 17:40:13
|
On Friday 17 December 2004 15:58, Guillaume Thouvenin wrote: > Here is the fork historic module. This module keeps the historic about > the creation of processes and it gives this information to a user space > application if one is registered. Currently, only one application can > use it. If needed it could be extended to several applications. This sounds very useful for a lot of interesting stuff. Though in the current form maybe the name is not appropriate: the module doesn't keep track of the fork history, this would be done in user-space. The module is more like a relay for fork monitoring. If you plan to extend this to multiple registered user space processes it would be great to have per process reporting policies, for example: - all forks, - only forks of descendants (children, etc). Erich |