diff -urNp linux-2.4.21/Documentation/Configure.help linux-2.4.21.SuSE/Documentation/Configure.help --- linux-2.4.21/Documentation/Configure.help 2003-08-01 17:15:02.000000000 +0200 +++ linux-2.4.21.SuSE/Documentation/Configure.help 2003-08-01 17:16:44.000000000 +0200 @@ -29765,4 +29765,20 @@ CONFIG_SENSORS_EEPROM in the lm_sensors package, which you can download at http://www.lm-sensors.nu +Support Resource Management Modules +CONFIG_RMGT_SUPPORT + If you say yes here you will enable kernel hooks that notify + registered resource management modules of kernel events through + their registered callback functions. Some kernel events, such as + forks and execs, may be vetoed by resource managers if desired. + These hooks and the ability to veto certain events permit greater + resource management control. Remember to select the specific type + of kernel hooks you wish to enable. + +Support "Process" Resource Management Modules +CONFIG_RMGT_PROC + If you say yes here you will enable kernel hooks that notify + registered resource management modules of process related kernel + events. + # End: diff -urNp linux-2.4.21/Makefile linux-2.4.21.SuSE/Makefile --- linux-2.4.21/Makefile 2003-08-01 17:15:02.000000000 +0200 +++ linux-2.4.21.SuSE/Makefile 2003-08-01 17:15:33.000000000 +0200 @@ -150,8 +150,9 @@ CORE_FILES =kernel/kernel.o mm/mm.o fs/f NETWORKS =net/network.o CRYPTO =crypto/crypto.o ABI =abi/abi.o +RMGT =rmgt/rmgt.o LIBS =$(TOPDIR)/lib/lib.a -SUBDIRS =kernel drivers mm fs net ipc lib abi sound crypto +SUBDIRS =kernel drivers mm fs net ipc lib abi sound crypto rmgt ifeq ($(CONFIG_KDB),y) CORE_FILES += kdb/kdb.o @@ -330,6 +331,7 @@ LD_VMLINUX := $(LD) $(LINKFLAGS) $(HEAD) $(NETWORKS) \ $(CRYPTO) \ $(ABI) \ + $(RMGT) \ $(LIBS) \ --end-group ifeq ($(CONFIG_KALLSYMS),y) diff -urNp linux-2.4.21/arch/i386/config.in linux-2.4.21.SuSE/arch/i386/config.in --- linux-2.4.21/arch/i386/config.in 2003-08-01 17:15:02.000000000 +0200 +++ linux-2.4.21.SuSE/arch/i386/config.in 2003-08-01 17:15:33.000000000 +0200 @@ -613,4 +613,6 @@ comment 'Plug In CPU Schedulers' bool 'Plug In CPU Schedulers' CONFIG_PLUGIN_SCHED endmenu +source rmgt/Config.in + source Config.in diff -urNp linux-2.4.21/fs/exec.c linux-2.4.21.SuSE/fs/exec.c --- linux-2.4.21/fs/exec.c 2003-08-01 17:15:02.000000000 +0200 +++ linux-2.4.21.SuSE/fs/exec.c 2003-08-01 17:15:33.000000000 +0200 @@ -38,6 +38,7 @@ #include #include #include +#include #define __NO_VERSION__ #include #include @@ -922,7 +923,7 @@ int do_execve(char * filename, char ** a struct linux_binprm bprm; struct file *file; int retval; - int i; + unsigned long i; file = open_exec(filename); @@ -964,10 +965,12 @@ int do_execve(char * filename, char ** a if (retval < 0) goto out; + RMGT_PROC_SET_STRING_POSITION(i, bprm.p); retval = copy_strings(bprm.argc, argv, &bprm); if (retval < 0) goto out; + RMGT_PROC_EXEC(current, file, argv, envp, i, bprm); retval = search_binary_handler(&bprm,regs); if (retval >= 0) { RAS_HOOK(exec_hook, file->f_dentry->d_name.len, diff -urNp linux-2.4.21/include/linux/rmgt_proc.h linux-2.4.21.SuSE/include/linux/rmgt_proc.h --- linux-2.4.21/include/linux/rmgt_proc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.21.SuSE/include/linux/rmgt_proc.h 2003-08-01 17:17:47.000000000 +0200 @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2000-2002 Aurema Pty. Ltd., support@aurema.com + * + * 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 __LINUX_RMGT_PROC_H +#define __LINUX_RMGT_PROC_H + +#define RMGT_PROC_INTERFACE_VERSION 1 + +/* + * Policy managers specify the callbacks they want to be invoked + * whenever process related events occur by using rmgt_proc_ops. + */ +typedef struct rmgt_proc_ops { + const int interface_version; + const char *policy_name; + struct rmgt_proc_ops *next; + + int (*newproc_vetoed)(pid_t, uid_t, gid_t, pid_t); + void (*newproc_cancel)(pid_t, uid_t, gid_t, pid_t); + void (*newproc_commit)(pid_t, uid_t, gid_t, pid_t); + + int (*exec_vetoed)(pid_t, dev_t, ino_t, int, void *, int, void *); + void (*exec_cancel)(pid_t, dev_t, ino_t, int, void *, int, void *); + void (*exec_commit)(pid_t, dev_t, ino_t, int, void *, int, void *); + + int (*setruid_vetoed)(pid_t, uid_t, uid_t); + void (*setruid_cancel)(pid_t, uid_t, uid_t); + void (*setruid_commit)(pid_t, uid_t, uid_t); + + int (*setrgid_vetoed)(pid_t, gid_t, gid_t); + void (*setrgid_cancel)(pid_t, gid_t, gid_t); + void (*setrgid_commit)(pid_t, gid_t, gid_t); + + void (*exit)(pid_t); +} rmgt_proc_ops_t; + +/* + * A policy manager may register with the register_rmgt_proc call to + * be notified of process related events. + */ +extern int register_rmgt_proc(rmgt_proc_ops_t *ops); + +/* + * Deregistration occurs when a registered policy manager invokes the + * unregister_rmgt_proc function. + */ +extern int unregister_rmgt_proc(rmgt_proc_ops_t *ops); + +#endif /* __LINUX_RMGT_PROC_H */ diff -urNp linux-2.4.21/include/linux/rmgt_proc_kern.h linux-2.4.21.SuSE/include/linux/rmgt_proc_kern.h --- linux-2.4.21/include/linux/rmgt_proc_kern.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.21.SuSE/include/linux/rmgt_proc_kern.h 2003-08-01 17:18:14.000000000 +0200 @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2000-2002 Aurema Pty. Ltd., support@aurema.com + * + * 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 __LINUX_RMGT_PROC_KERN_H +#define __LINUX_RMGT_PROC_KERN_H + +#include + +#ifdef CONFIG_RMGT_PROC +/* + * List of registered process management operations by all registered + * managers. + */ +extern rmgt_proc_ops_t *rmgt_proc_ops; + +/* + * When a new task is to be forked, rmgt_proc_newproc is called + * to inform registered policy managers. This is achieved by invoking + * the newproc_* callbacks of all managers. + * + * Policy managers may choose to veto this fork operation. If any of + * the policy managers veto the operation, it will fail with a + * non-zero error code returned. + */ +extern int __rmgt_proc_newproc(struct task_struct *, struct task_struct *); + +static inline int rmgt_proc_newproc(struct task_struct *task, + struct task_struct *parent) +{ + if (unlikely(rmgt_proc_ops != NULL)) + return __rmgt_proc_newproc(task, parent); + return 0; +} + +/* + * The function rmgt_proc_exec is called whenever a task is to be + * execed. It notifies registered policy managers of this exec + * operation by invoking their exec_* callbacks. + * + * Policy managers may choose to veto this exec operation. If any of + * the policy managers veto the operation, it will fail with a + * non-zero error code returned. + */ +extern int __rmgt_proc_exec(struct task_struct *, dev_t, ino_t, int, void *, + int, void *); + +static inline int rmgt_proc_exec(struct task_struct *task, dev_t dev, + ino_t ino, int argsize, void *argptr, + int envsize, void *envptr) +{ + if (unlikely(rmgt_proc_ops != NULL)) + return __rmgt_proc_exec(task, dev, ino, argsize, argptr, + envsize, envptr); + return 0; +} + +/* + * The function rmgt_proc_setruid is called whenever the real uid + * of a task is to be changed. Registered policy managers are + * notified of this change by invoking their setruid_* callbacks. + * + * Policy managers may choose to veto this operation. If any of the + * policy managers veto the operation, it will fail with a non-zero + * error code returned. + */ +extern int __rmgt_proc_setruid(struct task_struct *, uid_t, uid_t); + +static inline int rmgt_proc_setruid(struct task_struct *task, uid_t oldruid, + uid_t newruid) +{ + if (unlikely(rmgt_proc_ops != NULL)) + return __rmgt_proc_setruid(task, oldruid, newruid); + return 0; +} + +/* + * The function rmgt_proc_setrgid is called whenever the real gid + * of a task is to be changed. Registered policy managers are + * notified of this change by invoking their setrgid_* callbacks. + * + * Policy managers may choose to veto this operation. If any of the + * policy managers veto the operation, it will fail with a non-zero + * error code returned. + */ +extern int __rmgt_proc_setrgid(struct task_struct *, gid_t, gid_t); + +static inline int rmgt_proc_setrgid(struct task_struct *task, gid_t oldrgid, + gid_t newrgid) +{ + if (unlikely(rmgt_proc_ops != NULL)) + return __rmgt_proc_setrgid(task, oldrgid, newrgid); + return 0; +} + +/* + * When a task is about to exit, the function rmgt_proc_exit is + * called to inform registered policy managers of the event. All + * managers have their exit callback invoked. + */ +extern void __rmgt_proc_exit(struct task_struct *); + +static inline void rmgt_proc_exit(struct task_struct *task) +{ + if (unlikely(rmgt_proc_ops != NULL)) + __rmgt_proc_exit(task); +} + +/* + * Macros to invoke the inlined process management functions. + */ +#define RMGT_PROC_NEWPROC(task, parent) \ +do { \ + if (rmgt_proc_newproc(task, parent)) \ + goto bad_fork_cleanup; \ +} while (0) + +#define RMGT_PROC_SET_STRING_POSITION(offset, position) \ +do { \ + offset = position; \ +} while (0) + +#define RMGT_PROC_EXEC(task, file, argv, envp, offset, bprm) \ +do { \ + int argsize = (int)(offset - (bprm).p); \ + int envsize = (int)((bprm).exec - offset); \ +\ + if (rmgt_proc_exec(task, (file)->f_dentry->d_inode->i_dev, \ + (file)->f_dentry->d_inode->i_ino, argsize, \ + (void *)argv, envsize, (void *)envp)) { \ + retval = -EACCES; \ + goto out; \ + } \ +} while (0) + +#define RMGT_PROC_SETRUID(task, oldruid, newruid, newuser) \ +do { \ + if (rmgt_proc_setruid(task, oldruid, newruid)) { \ + free_uid(newuser); \ + return -EPERM; \ + } \ +} while (0) + +#define RMGT_PROC_SETRGID(task, oldrgid, newrgid) \ +do { \ + if ((newrgid != oldrgid) && \ + rmgt_proc_setrgid(task, oldrgid, newrgid)) \ + return -EPERM; \ +} while (0) + +#define RMGT_PROC_EXIT(task) rmgt_proc_exit(task) + +#else /* CONFIG_RMGT_PROC */ + +#define RMGT_PROC_NEWPROC(task, parent) do {} while (0) +#define RMGT_PROC_SET_STRING_POSITION(offset, position) do {} while (0) +#define RMGT_PROC_EXEC(task, file, argv, envp, offset, bprm) do {} while (0) +#define RMGT_PROC_SETRUID(task, oldruid, newruid, newuser) do {} while (0) +#define RMGT_PROC_SETRGID(task, oldrgid, newrgid) do {} while (0) +#define RMGT_PROC_EXIT(task) do {} while (0) + +#endif /* CONFIG_RMGT_PROC */ + +#endif /* __LINUX_RMGT_PROC_KERN_H */ diff -urNp linux-2.4.21/kernel/exit.c linux-2.4.21.SuSE/kernel/exit.c --- linux-2.4.21/kernel/exit.c 2003-08-01 17:15:02.000000000 +0200 +++ linux-2.4.21.SuSE/kernel/exit.c 2003-08-01 17:15:33.000000000 +0200 @@ -26,6 +26,7 @@ #include #include +#include extern void sem_exit (void); extern struct task_struct *child_reaper; @@ -52,6 +53,7 @@ static void release_task(struct task_str current->cnswap += p->nswap + p->cnswap; sched_exit(p); PLUGIN_SCHED_EXIT(p); + RMGT_PROC_EXIT(p); p->pid = 0; free_task_struct(p); } diff -urNp linux-2.4.21/kernel/fork.c linux-2.4.21.SuSE/kernel/fork.c --- linux-2.4.21/kernel/fork.c 2003-08-01 17:15:02.000000000 +0200 +++ linux-2.4.21.SuSE/kernel/fork.c 2003-08-01 17:15:33.000000000 +0200 @@ -30,6 +30,7 @@ #include #include +#include /* tng related changes */ int (*tng_forkfunc)(struct task_struct *) = NULL ; @@ -827,10 +828,11 @@ int do_fork(unsigned long clone_flags, u if (p->local_page.page) BUG(); + RMGT_PROC_NEWPROC(p, current); retval = -ENOMEM; /* copy all the process information */ if (copy_files(clone_flags, p)) - goto bad_fork_cleanup; + goto bad_fork_cleanup_rmgt; if (copy_fs(clone_flags, p)) goto bad_fork_cleanup_files; if (copy_sighand(clone_flags, p)) @@ -958,6 +960,8 @@ bad_fork_cleanup_fs: exit_fs(p); /* blocking */ bad_fork_cleanup_files: exit_files(p); /* blocking */ +bad_fork_cleanup_rmgt: + RMGT_PROC_EXIT(p); bad_fork_cleanup: up(&getpid_mutex); put_exec_domain(p->exec_domain); diff -urNp linux-2.4.21/kernel/ksyms.c linux-2.4.21.SuSE/kernel/ksyms.c --- linux-2.4.21/kernel/ksyms.c 2003-08-01 17:15:02.000000000 +0200 +++ linux-2.4.21.SuSE/kernel/ksyms.c 2003-08-01 17:15:33.000000000 +0200 @@ -71,6 +71,10 @@ #include #endif /* CONFIG_PLUGIN_SCHED */ +#ifdef CONFIG_RMGT_PROC +#include +#endif /* CONFIG_RMGT_PROC */ + extern void set_device_ro(kdev_t dev,int flag); extern void *sys_call_table; @@ -732,3 +736,13 @@ EXPORT_SYMBOL(runqueues); EXPORT_SYMBOL(cache_decay_ticks); #endif #endif /* CONFIG_PLUGIN_SCHED */ + + +/* Resource Management Interfaces */ + +/* Process Management Interface */ +#ifdef CONFIG_RMGT_PROC +EXPORT_SYMBOL(register_rmgt_proc); +EXPORT_SYMBOL(unregister_rmgt_proc); +#endif /* CONFIG_RMGT_PROC */ + diff -urNp linux-2.4.21/kernel/sys.c linux-2.4.21.SuSE/kernel/sys.c --- linux-2.4.21/kernel/sys.c 2003-08-01 17:15:02.000000000 +0200 +++ linux-2.4.21.SuSE/kernel/sys.c 2003-08-01 17:15:33.000000000 +0200 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #ifndef SET_UNALIGN_CTL # define SET_UNALIGN_CTL(a,b) (-EINVAL) @@ -496,6 +498,7 @@ asmlinkage long sys_setregid(gid_t rgid, return -EPERM; } } + RMGT_PROC_SETRGID(current, old_rgid, new_rgid); if (new_egid != old_egid) { current->mm->dumpable = 0; @@ -521,6 +524,7 @@ asmlinkage long sys_setgid(gid_t gid) if (capable(CAP_SETGID)) { + RMGT_PROC_SETRGID(current, current->gid, gid); if(old_egid != gid) { current->mm->dumpable=0; @@ -600,6 +604,7 @@ static int set_user(uid_t new_ruid, int new_user = alloc_uid(new_ruid); if (!new_user) return -EAGAIN; + RMGT_PROC_SETRUID(current, current->uid, new_ruid, new_user); old_user = current->user; atomic_dec(&old_user->processes); atomic_inc(&new_user->processes); @@ -632,7 +637,7 @@ static int set_user(uid_t new_ruid, int */ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) { - int old_ruid, old_euid, old_suid, new_ruid, new_euid; + int old_ruid, old_euid, old_suid, new_ruid, new_euid, result; new_ruid = old_ruid = current->uid; new_euid = old_euid = current->euid; @@ -655,8 +660,9 @@ asmlinkage long sys_setreuid(uid_t ruid, return -EPERM; } - if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) - return -EAGAIN; + if ((new_ruid != old_ruid) && + ((result = set_user(new_ruid, new_euid != old_euid)) < 0)) + return result; if (new_euid != old_euid) { @@ -692,15 +698,16 @@ asmlinkage long sys_setreuid(uid_t ruid, asmlinkage long sys_setuid(uid_t uid) { int old_euid = current->euid; - int old_ruid, old_suid, new_ruid, new_suid; + int old_ruid, old_suid, new_ruid, new_suid, result; old_ruid = new_ruid = current->uid; old_suid = current->suid; new_suid = old_suid; if (capable(CAP_SETUID)) { - if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) - return -EAGAIN; + if ((uid != old_ruid) && + ((result = set_user(uid, old_euid != uid)) < 0)) + return result; new_suid = uid; } else if ((uid != current->uid) && (uid != new_suid)) return -EPERM; @@ -730,6 +737,7 @@ asmlinkage long sys_setresuid(uid_t ruid int old_ruid = current->uid; int old_euid = current->euid; int old_suid = current->suid; + int result; if (!capable(CAP_SETUID)) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && @@ -743,8 +751,9 @@ asmlinkage long sys_setresuid(uid_t ruid return -EPERM; } if (ruid != (uid_t) -1) { - if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) - return -EAGAIN; + if ((ruid != current->uid) && + ((result = set_user(ruid, euid != current->euid)) < 0)) + return result; } if (euid != (uid_t) -1) { if (euid != current->euid) @@ -792,6 +801,7 @@ asmlinkage long sys_setresgid(gid_t rgid (sgid != current->egid) && (sgid != current->sgid)) return -EPERM; } + RMGT_PROC_SETRGID(current, current->gid, rgid); if (egid != (gid_t) -1) { if (egid != current->egid) { diff -urNp linux-2.4.21/rmgt/Config.in linux-2.4.21.SuSE/rmgt/Config.in --- linux-2.4.21/rmgt/Config.in 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.21.SuSE/rmgt/Config.in 2003-08-01 17:15:33.000000000 +0200 @@ -0,0 +1,7 @@ +mainmenu_option next_comment +comment 'Support Resource Management Modules' +bool 'Support Resource Management Modules' CONFIG_RMGT_SUPPORT + if [ "$CONFIG_RMGT_SUPPORT" = "y" ]; then + bool 'Support ""Process"" Resource Management Modules' CONFIG_RMGT_PROC + fi +endmenu diff -urNp linux-2.4.21/rmgt/Makefile linux-2.4.21.SuSE/rmgt/Makefile --- linux-2.4.21/rmgt/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.21.SuSE/rmgt/Makefile 2003-08-01 17:15:33.000000000 +0200 @@ -0,0 +1,11 @@ +# +# RMGT Kernel Interface Makefile +# +# requires GNU make +# +O_TARGET := rmgt.o +obj-$(CONFIG_RMGT_PROC) += rmgt_proc.o + +include $(TOPDIR)/Rules.make + + diff -urNp linux-2.4.21/rmgt/rmgt_proc.c linux-2.4.21.SuSE/rmgt/rmgt_proc.c --- linux-2.4.21/rmgt/rmgt_proc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.21.SuSE/rmgt/rmgt_proc.c 2003-08-01 17:18:41.000000000 +0200 @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2000-2002 Aurema Pty. Ltd., support@aurema.com + * + * 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 +#include +#include +#include +#include + +/* + * List of registered process management callbacks. + */ +rmgt_proc_ops_t *rmgt_proc_ops __cacheline_aligned = NULL; + +/* + * Semaphore to prevent unwanted race conditions between registration, + * deregistration, and callbacks. + */ +static DECLARE_RWSEM(rmgt_proc_rwsem); + +/* + * Register the callbacks required by a policy manager. + */ +int register_rmgt_proc(rmgt_proc_ops_t *ops) +{ +#define PID_BITMAP_SIZE ((((PID_NR + 7)/8) + sizeof(long) - 1)/(sizeof(long))) + unsigned long pid_bitmap[PID_BITMAP_SIZE]; + struct task_struct *p; + rmgt_proc_ops_t *op; + int nr_processes; + pid_t pid; + + if (!ops || (ops->interface_version != RMGT_PROC_INTERFACE_VERSION) || + (ops->policy_name == NULL)) + return -EINVAL; + + down_write(&rmgt_proc_rwsem); + for (op = rmgt_proc_ops; op; op = op->next) + if ((ops == op) || + !strcmp(op->policy_name, ops->policy_name)) { + up_write(&rmgt_proc_rwsem); + return -EINVAL; + } + ops->next = rmgt_proc_ops; + rmgt_proc_ops = ops; + + if (ops->newproc_commit) { + /* + * Cache snapshot of processes in system to register + * later. The 'newproc_commit' callback cannot be + * invoked with the tasklist_lock taken since it may + * block. + */ + memset(pid_bitmap, 0, sizeof(pid_bitmap)); + read_lock(&tasklist_lock); + for_each_task(p) + __set_bit(p->pid, pid_bitmap); + nr_processes = nr_threads; + read_unlock(&tasklist_lock); + + for (pid = 0; nr_processes > 0; nr_processes--) { + pid = find_next_bit(pid_bitmap, PID_NR, pid + 1); + read_lock(&tasklist_lock); + if (likely((p = find_task_by_pid(pid)) != NULL)) + get_task_struct(p); + read_unlock(&tasklist_lock); + if (likely(p != NULL)) { + ops->newproc_commit(p->pid, p->uid, p->gid, + p->p_opptr->pid); + free_task_struct(p); + } + } + } + + up_write(&rmgt_proc_rwsem); + return 0; +} + +/* + * Deregister a registered policy manager. + */ +int unregister_rmgt_proc(rmgt_proc_ops_t *ops) +{ + rmgt_proc_ops_t **opp; + + down_write(&rmgt_proc_rwsem); + for (opp = &rmgt_proc_ops; *opp; opp = &((*opp)->next)) + if (*opp == ops) { + *opp = ops->next; + up_write(&rmgt_proc_rwsem); + return 0; + } + up_write(&rmgt_proc_rwsem); + return -ESRCH; +} + +/* + * Tell all managers someone's trying to fork new task. + */ +int __rmgt_proc_newproc(struct task_struct *task, struct task_struct *parent) +{ + rmgt_proc_ops_t *op, *vop; + int vetoed = 0; + + down_read(&rmgt_proc_rwsem); + for (vop = rmgt_proc_ops; vop != NULL; vop = vop->next) + if (vop->newproc_vetoed) { + vetoed = vop->newproc_vetoed(task->pid, task->uid, + task->gid, parent->pid); + if (unlikely(vetoed)) + break; + } + + if (unlikely(vetoed)) { + for (op = rmgt_proc_ops; op != vop; op = op->next) + if (op->newproc_cancel) + op->newproc_cancel(task->pid, task->uid, + task->gid, parent->pid); + } else { + for (op = rmgt_proc_ops; op != NULL; op = op->next) + if (op->newproc_commit) + op->newproc_commit(task->pid, task->uid, + task->gid, parent->pid); + } + up_read(&rmgt_proc_rwsem); + + if (unlikely(vetoed > 0)) + vetoed = -vetoed; + return vetoed; +} + +/* + * Tell all managers a task is trying to exec. + */ +int __rmgt_proc_exec(struct task_struct *task, dev_t dev, ino_t ino, + int argsize, void *argptr, int envsize, void *envptr) +{ + rmgt_proc_ops_t *op, *vop; + int vetoed = 0; + + down_read(&rmgt_proc_rwsem); + for (vop = rmgt_proc_ops; vop != NULL; vop = vop->next) + if (vop->exec_vetoed) { + vetoed = vop->exec_vetoed(task->pid, dev, ino, argsize, + argptr, envsize, envptr); + if (unlikely(vetoed)) + break; + } + + if (unlikely(vetoed)) { + for (op = rmgt_proc_ops; op != vop; op = op->next) + if (op->exec_cancel) + op->exec_cancel(task->pid, dev, ino, argsize, + argptr, envsize, envptr); + } else { + for (op = rmgt_proc_ops; op != NULL; op = op->next) + if (op->exec_commit) + op->exec_commit(task->pid, dev, ino, argsize, + argptr, envsize, envptr); + } + up_read(&rmgt_proc_rwsem); + + if (unlikely(vetoed > 0)) + vetoed = -vetoed; + return vetoed; +} + +/* + * Tell all managers a task is trying to invoke setuid, setreuid, or + * setresuid. + */ +int __rmgt_proc_setruid(struct task_struct *task, uid_t oldruid, uid_t newruid) +{ + rmgt_proc_ops_t *op, *vop; + int vetoed = 0; + + down_read(&rmgt_proc_rwsem); + for (vop = rmgt_proc_ops; vop != NULL; vop = vop->next) + if (vop->setruid_vetoed) { + vetoed = vop->setruid_vetoed(task->pid, oldruid, + newruid); + if (unlikely(vetoed)) + break; + } + + if (unlikely(vetoed)) { + for (op = rmgt_proc_ops; op != vop; op = op->next) + if (op->setruid_cancel) + op->setruid_cancel(task->pid, oldruid, + newruid); + } else { + for (op = rmgt_proc_ops; op != NULL; op = op->next) + if (op->setruid_commit) + op->setruid_commit(task->pid, oldruid, + newruid); + } + up_read(&rmgt_proc_rwsem); + + if (unlikely(vetoed > 0)) + vetoed = -vetoed; + return vetoed; +} + +/* + * Tell all managers a task is trying to invoke setgid, setregid, or + * setresgid. + */ +int __rmgt_proc_setrgid(struct task_struct *task, gid_t oldrgid, gid_t newrgid) +{ + rmgt_proc_ops_t *op, *vop; + int vetoed = 0; + + down_read(&rmgt_proc_rwsem); + for (vop = rmgt_proc_ops; vop != NULL; vop = vop->next) + if (vop->setrgid_vetoed) { + vetoed = vop->setrgid_vetoed(task->pid, oldrgid, + newrgid); + if (unlikely(vetoed)) + break; + } + + if (unlikely(vetoed)) { + for (op = rmgt_proc_ops; op != vop; op = op->next) + if (op->setrgid_cancel) + op->setrgid_cancel(task->pid, oldrgid, + newrgid); + } else { + for (op = rmgt_proc_ops; op != NULL; op = op->next) + if (op->setrgid_commit) + op->setrgid_commit(task->pid, oldrgid, + newrgid); + } + up_read(&rmgt_proc_rwsem); + + if (unlikely(vetoed > 0)) + vetoed = -vetoed; + return vetoed; +} + +/* + * Tell all managers a task is exiting. + */ +void __rmgt_proc_exit(struct task_struct *task) +{ + rmgt_proc_ops_t *op; + + down_read(&rmgt_proc_rwsem); + for (op = rmgt_proc_ops; op != NULL; op = op->next) + if (op->exit) + op->exit(task->pid); + up_read(&rmgt_proc_rwsem); +}