Since people seem to prefer purely restrictive hooks (and these are sufficient for SELinux), I've changed the authoritative hooks in our LSM patch to be purely restrictive. I also integrated some unrelated changes from the WireX tree and merged with 2.4.6-pre3. I've attached an up-to-date diff between the WireX tree and our tree. As before, I've left the capabilities code untouched until there is a consensus on the right approach for migrating it to a module. -- Stephen D. Smalley, NAI Labs ssmalleyat_private diff -X dontdiff -Nru lsm-wirex/arch/i386/kernel/ioport.c lsm-nailabs/arch/i386/kernel/ioport.c --- lsm-wirex/arch/i386/kernel/ioport.c Mon Jun 18 13:45:59 2001 +++ lsm-nailabs/arch/i386/kernel/ioport.c Mon Jun 18 13:01:53 2001 @@ -64,8 +64,7 @@ if (turn_on && !capable(CAP_SYS_RAWIO)) return -EPERM; - /* check that we have permission to do this */ - retval = security_ops->ioperm(); + retval = security_ops->ioperm(from, num, turn_on); if (retval) { return retval; } @@ -121,9 +120,7 @@ if (!capable(CAP_SYS_RAWIO)) return -EPERM; } - - /* check that we have permission to do this */ - retval = security_ops->ioperm(); + retval = security_ops->iopl(old, level); if (retval) { return retval; } diff -X dontdiff -Nru lsm-wirex/arch/i386/kernel/ptrace.c lsm-nailabs/arch/i386/kernel/ptrace.c --- lsm-wirex/arch/i386/kernel/ptrace.c Mon Jun 18 13:46:00 2001 +++ lsm-nailabs/arch/i386/kernel/ptrace.c Mon Jun 18 14:02:03 2001 @@ -147,7 +147,8 @@ /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if (security_ops->ptrace(current->p_pptr, current)) + ret = security_ops->ptrace(current->p_pptr, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; @@ -167,12 +168,13 @@ if (pid == 1) /* you may not mess with init */ goto out_tsk; - if (security_ops->ptrace(current, child)) - goto out_tsk; - if (request == PTRACE_ATTACH) { if (child == current) goto out_tsk; + ret = security_ops->ptrace(current, child); + if (ret) + goto out_tsk; + ret = -EPERM; if(((current->uid != child->euid) || (current->uid != child->suid) || (current->uid != child->uid) || diff -X dontdiff -Nru lsm-wirex/arch/ia64/ia32/sys_ia32.c lsm-nailabs/arch/ia64/ia32/sys_ia32.c --- lsm-wirex/arch/ia64/ia32/sys_ia32.c Mon Jun 18 13:46:12 2001 +++ lsm-nailabs/arch/ia64/ia32/sys_ia32.c Mon Jun 18 13:33:52 2001 @@ -2577,13 +2577,10 @@ if (!capable(CAP_SYS_RAWIO)) return -EPERM; } - - /* check that we have permission to do this */ - retval = security_ops->ioperm(); + retval = security_ops->iopl(old, level); if (retval) { return retval; } - set_fs(KERNEL_DS); fd = sys_open("/dev/mem", O_SYNC | O_RDWR, 0); set_fs(old_fs); diff -X dontdiff -Nru lsm-wirex/arch/ia64/kernel/ptrace.c lsm-nailabs/arch/ia64/kernel/ptrace.c --- lsm-wirex/arch/ia64/kernel/ptrace.c Mon Jun 18 13:46:12 2001 +++ lsm-nailabs/arch/ia64/kernel/ptrace.c Mon Jun 18 14:02:03 2001 @@ -749,7 +749,8 @@ /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if (security_ops->ptrace(current->p_pptr, current)) + ret = security_ops->ptrace(current->p_pptr, current); + if (ret) goto out; current->ptrace |= PT_PTRACED; ret = 0; @@ -770,12 +771,13 @@ if (pid == 1) /* no messing around with init! */ goto out_tsk; - if (security_ops->ptrace(current, child)) - goto out_tsk; - if (request == PTRACE_ATTACH) { if (child == current) goto out_tsk; + ret = security_ops->ptrace(current, child); + if (ret) + goto out_tsk; + ret = -EPERM; if ((!child->dumpable || (current->uid != child->euid) || (current->uid != child->suid) || diff -X dontdiff -Nru lsm-wirex/drivers/char/tty_io.c lsm-nailabs/drivers/char/tty_io.c --- lsm-wirex/drivers/char/tty_io.c Mon Jun 18 13:45:36 2001 +++ lsm-nailabs/drivers/char/tty_io.c Wed Jun 13 12:20:28 2001 @@ -1462,6 +1462,10 @@ if (!waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = 1; if (filp->f_owner.pid == 0) { + retval = security_ops->file_ops->set_fowner(filp); + if (retval) + return retval; + filp->f_owner.pid = (-tty->pgrp) ? : current->pid; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; diff -X dontdiff -Nru lsm-wirex/fs/attr.c lsm-nailabs/fs/attr.c --- lsm-wirex/fs/attr.c Mon Jun 18 13:45:11 2001 +++ lsm-nailabs/fs/attr.c Mon Jun 18 13:06:25 2001 @@ -124,9 +124,9 @@ error = security_ops->inode_ops->setattr(dentry, attr); if (error) goto unlock_and_out; - if (inode->i_op && inode->i_op->setattr) { + if (inode->i_op && inode->i_op->setattr) error = inode->i_op->setattr(dentry, attr); - } else { + else { error = inode_change_ok(inode, attr); if (!error) inode_setattr(inode, attr); diff -X dontdiff -Nru lsm-wirex/fs/binfmt_elf.c lsm-nailabs/fs/binfmt_elf.c --- lsm-wirex/fs/binfmt_elf.c Mon Jun 18 13:45:11 2001 +++ lsm-nailabs/fs/binfmt_elf.c Mon Jun 11 14:19:46 2001 @@ -39,7 +39,6 @@ #define DLINFO_ITEMS 13 #include <linux/elf.h> -#include <linux/security.h> static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_elf_library(struct file*); @@ -655,17 +654,6 @@ elf_brk = k; } set_fs(old_fs); - - /* Shell scripts get checked in binfmt_script.c */ - if (!bprm->sh_bang) { - retval = security_ops->file_ops->permission (bprm->file, MAY_EXEC); - if (retval) { - kfree(elf_interpreter); - kfree(elf_phdata); - send_sig(SIGKILL, current, 0); - return retval; - } - } elf_entry += load_bias; elf_bss += load_bias; diff -X dontdiff -Nru lsm-wirex/fs/dnotify.c lsm-nailabs/fs/dnotify.c --- lsm-wirex/fs/dnotify.c Mon Jun 18 13:45:12 2001 +++ lsm-nailabs/fs/dnotify.c Wed Jun 13 12:20:28 2001 @@ -45,6 +45,7 @@ struct dnotify_struct **prev; struct inode *inode; int turning_off = (arg & ~DN_MULTISHOT) == 0; + int error; if (!turning_off && !dir_notify_enable) return -EINVAL; @@ -75,6 +76,13 @@ } if (turning_off) goto out; + + error = security_ops->file_ops->set_fowner(filp); + if (error) { + write_unlock(&dn_lock); + return error; + } + filp->f_owner.pid = current->pid; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; diff -X dontdiff -Nru lsm-wirex/fs/exec.c lsm-nailabs/fs/exec.c --- lsm-wirex/fs/exec.c Mon Jun 18 13:45:11 2001 +++ lsm-nailabs/fs/exec.c Mon Jun 18 13:37:14 2001 @@ -36,7 +36,6 @@ #include <linux/spinlock.h> #define __NO_VERSION__ #include <linux/module.h> -#include <linux/security.h> #include <asm/uaccess.h> #include <asm/pgalloc.h> @@ -631,6 +630,28 @@ bprm->e_gid = inode->i_gid; } + /* We don't have VFS support for capabilities yet */ + cap_clear(bprm->cap_inheritable); + cap_clear(bprm->cap_permitted); + cap_clear(bprm->cap_effective); + + /* To support inheritance of root-permissions and suid-root + * executables under compatibility mode, we raise all three + * capability sets for the file. + * + * If only the real uid is 0, we only raise the inheritable + * and permitted sets of the executable file. + */ + + if (!issecure(SECURE_NOROOT)) { + if (bprm->e_uid == 0 || current->uid == 0) { + cap_set_full(bprm->cap_inheritable); + cap_set_full(bprm->cap_permitted); + } + if (bprm->e_uid == 0) + cap_set_full(bprm->cap_effective); + } + /* fill in binprm security blob */ if (security_ops->bprm_ops->alloc_security(bprm)) return -EACCES; /* hmm, is EACCES really right? */ @@ -656,9 +677,6 @@ void compute_creds(struct linux_binprm *bprm) { - security_ops->bprm_ops->compute_creds(bprm); - -#if 0 /* pushed into security module */ kernel_cap_t new_permitted, working; int do_unlock = 0; @@ -706,7 +724,8 @@ if(do_unlock) unlock_kernel(); current->keep_capabilities = 0; -#endif + + security_ops->bprm_ops->compute_creds(bprm); } diff -X dontdiff -Nru lsm-wirex/fs/fcntl.c lsm-nailabs/fs/fcntl.c --- lsm-wirex/fs/fcntl.c Mon Jun 18 13:45:11 2001 +++ lsm-nailabs/fs/fcntl.c Mon Jun 18 13:12:40 2001 @@ -273,15 +273,19 @@ break; case F_SETOWN: lock_kernel(); + + err = security_ops->file_ops->set_fowner(filp); + if (err) { + unlock_kernel(); + break; + } + filp->f_owner.pid = arg; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; err = 0; if (S_ISSOCK (filp->f_dentry->d_inode->i_mode)) err = sock_fcntl (filp, F_SETOWN, arg); - - if (!err) - err = security_ops->fown_ops->alloc_security(&filp->f_owner); unlock_kernel(); break; case F_GETSIG: @@ -396,7 +400,7 @@ (fown->uid ^ p->suid) && (fown->uid ^ p->uid)) return; - if (security_ops->fown_ops->send_sigiotask(p, fown, fd, reason)) + if (security_ops->file_ops->send_sigiotask(p, fown, fd, reason)) return; switch (fown->signum) { diff -X dontdiff -Nru lsm-wirex/fs/file_table.c lsm-nailabs/fs/file_table.c --- lsm-wirex/fs/file_table.c Mon Jun 18 13:45:11 2001 +++ lsm-nailabs/fs/file_table.c Wed Jun 13 12:20:28 2001 @@ -41,6 +41,12 @@ list_del(&f->f_list); files_stat.nr_free_files--; new_one: + if (security_ops->file_ops->alloc_security(f)) { + list_add(&f->f_list, &free_list); + files_stat.nr_free_files++; + file_list_unlock(); + return NULL; + } memset(f, 0, sizeof(*f)); atomic_set(&f->f_count,1); f->f_version = ++event; @@ -143,6 +149,7 @@ void put_filp(struct file *file) { if(atomic_dec_and_test(&file->f_count)) { + security_ops->file_ops->free_security(file); file_list_lock(); list_del(&file->f_list); list_add(&file->f_list, &free_list); diff -X dontdiff -Nru lsm-wirex/fs/ioctl.c lsm-nailabs/fs/ioctl.c --- lsm-wirex/fs/ioctl.c Mon Jun 18 13:45:12 2001 +++ lsm-nailabs/fs/ioctl.c Wed Jun 13 11:02:02 2001 @@ -7,6 +7,7 @@ #include <linux/mm.h> #include <linux/smp_lock.h> #include <linux/file.h> +#include <linux/security.h> #include <asm/uaccess.h> #include <asm/ioctls.h> @@ -56,6 +57,14 @@ if (!filp) goto out; error = 0; + + /* Call the Linux Security Module to perform its checks. */ + error = security_ops->file_ops->ioctl(filp, cmd, arg); + if (error) { + fput(filp); + goto out; + } + lock_kernel(); switch (cmd) { case FIOCLEX: diff -X dontdiff -Nru lsm-wirex/fs/locks.c lsm-nailabs/fs/locks.c --- lsm-wirex/fs/locks.c Mon Jun 18 13:45:12 2001 +++ lsm-nailabs/fs/locks.c Wed Jun 13 12:20:28 2001 @@ -1269,6 +1269,11 @@ fl->fl_next = *before; *before = fl; list_add(&fl->fl_link, &file_lock_list); + + error = security_ops->file_ops->set_fowner(filp); + if (error) + goto out_unlock; + filp->f_owner.pid = current->pid; filp->f_owner.uid = current->uid; filp->f_owner.euid = current->euid; diff -X dontdiff -Nru lsm-wirex/fs/namei.c lsm-nailabs/fs/namei.c --- lsm-wirex/fs/namei.c Mon Jun 18 13:45:12 2001 +++ lsm-nailabs/fs/namei.c Mon Jun 18 14:31:29 2001 @@ -183,6 +183,9 @@ if (retval) return retval; + /* Ordinary permission routines do not understand MAY_APPEND. */ + mask &= ~MAY_APPEND; + if (inode->i_op && inode->i_op->permission) { lock_kernel(); retval = inode->i_op->permission(inode, mask); @@ -953,6 +956,11 @@ int count = 0; acc_mode = ACC_MODE(flag); + + /* Allow the LSM permission hook to distinguish append + access from general write access. */ + if (flag & O_APPEND) + acc_mode |= MAY_APPEND; /* * The simplest case - just a plain lookup. diff -X dontdiff -Nru lsm-wirex/fs/open.c lsm-nailabs/fs/open.c --- lsm-wirex/fs/open.c Mon Jun 18 13:45:12 2001 +++ lsm-nailabs/fs/open.c Wed Jun 13 12:20:28 2001 @@ -667,10 +667,6 @@ } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - error = -EACCES; - if (security_ops->file_ops->alloc_security (f)) - goto cleanup_all; - return f; cleanup_all: diff -X dontdiff -Nru lsm-wirex/include/linux/binfmts.h lsm-nailabs/include/linux/binfmts.h --- lsm-wirex/include/linux/binfmts.h Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/include/linux/binfmts.h Mon Jun 18 11:26:43 2001 @@ -4,7 +4,6 @@ #include <linux/ptrace.h> #include <linux/capability.h> - /* * MAX_ARG_PAGES defines the number of pages allocated for arguments * and envelope for the new program. 32 should suffice, this gives @@ -27,7 +26,8 @@ int sh_bang; struct file * file; int e_uid, e_gid; - void *security; /* was cap_inheritable, cap_permitted, cap_effective */ + kernel_cap_t cap_inheritable, cap_permitted, cap_effective; + void *security; int argc, envc; char * filename; /* Name of binary */ unsigned long loader, exec; diff -X dontdiff -Nru lsm-wirex/include/linux/elf.h lsm-nailabs/include/linux/elf.h --- lsm-wirex/include/linux/elf.h Mon Jun 18 13:45:16 2001 +++ lsm-nailabs/include/linux/elf.h Mon Jun 18 11:31:08 2001 @@ -512,7 +512,7 @@ #define SHN_HIRESERVE 0xffff #define SHN_MIPS_ACCOMON 0xff00 -typedef struct elf32_shdr { +typedef struct { Elf32_Word sh_name; Elf32_Word sh_type; Elf32_Word sh_flags; @@ -599,7 +599,6 @@ #define elfhdr elf32_hdr #define elf_phdr elf32_phdr #define elf_note elf32_note -#define elf_shdr elf32_shdr #else @@ -607,7 +606,6 @@ #define elfhdr elf64_hdr #define elf_phdr elf64_phdr #define elf_note elf64_note -#define elf_shdr elf64_shdr #endif diff -X dontdiff -Nru lsm-wirex/include/linux/fs.h lsm-nailabs/include/linux/fs.h --- lsm-wirex/include/linux/fs.h Mon Jun 18 13:45:16 2001 +++ lsm-nailabs/include/linux/fs.h Mon Jun 18 14:27:17 2001 @@ -71,6 +71,7 @@ #define MAY_EXEC 1 #define MAY_WRITE 2 #define MAY_READ 4 +#define MAY_APPEND 8 #define FMODE_READ 1 #define FMODE_WRITE 2 diff -X dontdiff -Nru lsm-wirex/include/linux/ipc.h lsm-nailabs/include/linux/ipc.h --- lsm-wirex/include/linux/ipc.h Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/include/linux/ipc.h Mon Jun 18 11:26:43 2001 @@ -63,6 +63,7 @@ gid_t cgid; mode_t mode; unsigned long seq; + void *security; }; #endif /* __KERNEL__ */ diff -X dontdiff -Nru lsm-wirex/include/linux/sched.h lsm-nailabs/include/linux/sched.h --- lsm-wirex/include/linux/sched.h Mon Jun 18 13:45:16 2001 +++ lsm-nailabs/include/linux/sched.h Mon Jun 18 13:42:38 2001 @@ -694,6 +694,7 @@ * New privilege checks should use this interface, rather than suser() or * fsuser(). See include/linux/capability.h for defined capabilities. */ +/* capable prototype and code moved to security.[hc] */ #include <linux/security.h> #if 0 static inline int capable(int cap) diff -X dontdiff -Nru lsm-wirex/include/linux/security.h lsm-nailabs/include/linux/security.h --- lsm-wirex/include/linux/security.h Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/include/linux/security.h Mon Jun 18 13:39:22 2001 @@ -6,6 +6,10 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * + * 2001_Jun_12 Stephen Smalley <sdsat_private>, NAI Labs, SELinux project + * Changed all non-capable hooks to be authoritative or restrictive. + * Added parameters to several of the hook functions. + * * 2001_Apr_12 greg k-h * created based on original immunix.h code * @@ -23,7 +27,11 @@ #include <linux/fs.h> #include <linux/binfmts.h> #include <linux/signal.h> - +#include <linux/resource.h> +#include <linux/ipc.h> +#include <linux/sem.h> +#include <linux/shm.h> +#include <linux/msg.h> /* Security plug operations */ #define SECURITY_INTERFACE_VERSION 0x00000101 /* change this every time the security_operations structure changes */ @@ -66,7 +74,7 @@ int (* truncate) (struct inode *inode); int (* permission) (struct inode *inode, int mask); int (* revalidate) (struct dentry *dentry); - int (* setattr) (struct dentry *dentry, struct iattr *attr); // CAP_CHOWN + int (* setattr) (struct dentry *dentry, struct iattr *attr); void (* attach_pathlabel)(struct dentry *dentry, struct vfsmount *mnt); // DTE project needs this int (* stat) (struct inode *inode); }; @@ -79,7 +87,7 @@ int (* llseek) (struct file *); int (* read) (struct file *); int (* write) (struct file *); - int (* ioctl) (struct file *); // need more than file* + int (* ioctl) (struct file *, unsigned int cmd, unsigned long arg); int (* mmap) (struct file *, unsigned long, unsigned long); int (* mprotect) (struct vm_area_struct *, unsigned long); int (* lock) (struct file *); @@ -87,25 +95,25 @@ int (* writev) (struct file *); int (* fcntl) (struct file *, unsigned int, unsigned long); int (* fcntl64) (struct file *, unsigned int, unsigned long); -}; - -struct fown_security_ops { - int (* alloc_security) (struct fown_struct *); - void (* free_security) (struct fown_struct *); - int (* send_sigiotask) (struct task_struct *, struct fown_struct *, int, int); + int (* set_fowner) (struct file *file); + int (* send_sigiotask) (struct task_struct *tsk, struct fown_struct *fown, int fd, int reason); }; struct task_security_ops { int (* create) (void); int (* alloc_security) (struct task_struct *p); // create per process security stuff void (* free_security) (struct task_struct *p); // free it - int (* setuid) (void); // CAP_SETUID - int (* setgid) (void); // CAP_SETGID - int (* setgroups) (void); // CAP_SETGID - int (* setnice) (struct task_struct *p, int nice); // CAP_SYS_NICE - int (* setrlimit) (unsigned int resource); // CAP_SYS_RESOURCE - int (* setscheduler) (struct task_struct *p, int policy); // CAP_SYS_NICE - int (* kill) (struct task_struct *p, struct siginfo *info, int sig); // CAP_KILL +#define LSM_SETID_ID 1 /* setuid or setgid, id0 == uid or gid */ +#define LSM_SETID_RE 2 /* setreuid or setregid, id0 == real, id1 == eff */ +#define LSM_SETID_RES 4 /* setresuid or setresgid, id0 == real, id1 == eff, uid2 == saved */ +#define LSM_SETID_FS 8 /* setfsuid or setfsgid, id0 == fsuid or fsgid */ + int (* setuid) (uid_t id0, uid_t id1, uid_t id2, int flags); + int (* setgid) (gid_t id0, gid_t id1, gid_t id2, int flags); + int (* setgroups) (int gidsetsize, gid_t *grouplist); + int (* setnice) (struct task_struct *p, int nice); + int (* setrlimit) (unsigned int resource, struct rlimit *new_rlim); + int (* setscheduler) (struct task_struct *p, int policy); + int (* kill) (struct task_struct *p, struct siginfo *info, int sig); int (* wait) (struct task_struct *p); /* set and (in case of exec failure) unset security label */ @@ -118,48 +126,61 @@ }; struct module_security_ops { - int (* create_module) (const char *name_user, size_t size); // CAP_SYS_MODULE - int (* init_module) (const char *name_user, struct module *mod_user); // CAP_SYS_MODULE - int (* delete_module) (const char *name_user); // CAP_SYS_MODULE + int (* create_module) (const char *name_user, size_t size); + int (* init_module) (const char *name_user, struct module *mod_user); + int (* delete_module) (const char *name_user); +}; + +struct ipc_security_ops { + int (* permission) (struct kern_ipc_perm *ipcp, short flag); + int (* getinfo) (int id, int cmd); }; struct msg_queue_security_ops { int (* create) (key_t key); // can i create - int (* permission) (void); // CAP_SYS_ADMIN - int (* setmaxqbytes) (void); // CAP_SYS_RESOURCE + int (* permission) (void); + int (* setmaxqbytes) (void); int (* setattr) (void); // can i set attributes int (* delete) (void); // can i delete }; struct shm_security_ops { - int (* create) (key_t key); - int (* permission) (void); - int (* setattr) (void); - int (* delete) (void); + int (* alloc_security) (struct shmid_kernel *shp); + void (* free_security) (struct shmid_kernel *shp); + int (* associate) (struct shmid_kernel *shp, int shmid, int shmflg); + int (* shmctl) (struct shmid_kernel *shp, int shmid, int cmd); + int (* shmat) (struct shmid_kernel *shp, int shmid, char *shmaddr, int shmflg); }; +struct sem_security_ops { + int (* alloc_security) (struct sem_array *sma); + void (* free_security) (struct sem_array *sma); + int (* associate) (struct sem_array *sma, int semid, int semflg); + int (* semctl) (struct sem_array *sma, int semid, int cmd); + int (* semop) (struct sem_array *sma, int semid, struct sembuf *sops, unsigned nsops, int alter); +}; struct security_operations { int version; /* syscalls that are checked for permissions */ - int (* sethostname) (void); // CAP_SYS_ADMIN - int (* setdomainname) (void); // CAP_SYS_ADMIN - int (* reboot) (unsigned int cmd); // CAP_SYS_BOOT + int (* sethostname) (char *hostname); + int (* setdomainname) (char *domainname); + int (* reboot) (unsigned int cmd, void *arg); int (* mount) (char * dev_name, struct nameidata *nd, char * type, unsigned long flags, - void * data); // part of CAP_SYS_ADMIN + void * data); int (* add_vfsmnt) (struct nameidata *nd, struct super_block *sb, char *dev_name); - int (* umount) (struct vfsmount *mnt, int flags); // part of CAP_SYS_ADMIN + int (* umount) (struct vfsmount *mnt, int flags); void (* umount_close) (struct vfsmount *mnt); void (* umount_busy) (struct vfsmount *mnt); int (* remount) (struct vfsmount *mnt, unsigned long flags, void *data); void (* post_remount) (struct vfsmount *mnt, unsigned long flags, void *data); - int (* ioperm) (void); // part of CAP_RAWIO - int (* iopl) (void); // part of CAP_RAWIO - int (* ptrace) (struct task_struct *parent, struct task_struct *child); // CAP_PTRACE - int (* setcapability) (void); // CAP_SETPCAP - int (* acct) (void); // CAP_SYS_PACCT + int (* ioperm) (unsigned long from, unsigned long num, int turn_on); + int (* iopl) (unsigned int old, unsigned int level); + int (* ptrace) (struct task_struct *parent, struct task_struct *child); + int (* setcapability) (void); + int (* acct) (struct file *file); /* old capable call, catch all for capabilities. */ int (* capable) (int cap); @@ -167,12 +188,13 @@ struct super_block_security_ops * sb_ops; struct inode_security_ops * inode_ops; struct file_security_ops * file_ops; - struct fown_security_ops * fown_ops; struct task_security_ops * task_ops; struct socket_security_ops * socket_ops; struct module_security_ops * module_ops; + struct ipc_security_ops * ipc_ops; struct msg_queue_security_ops * msg_queue_ops; struct shm_security_ops * shm_ops; + struct sem_security_ops * sem_ops; /* allow module stacking */ int (* register_security) (const char *name, struct security_operations *ops); diff -X dontdiff -Nru lsm-wirex/include/linux/shm.h lsm-nailabs/include/linux/shm.h --- lsm-wirex/include/linux/shm.h Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/include/linux/shm.h Mon Jun 18 11:26:43 2001 @@ -71,6 +71,19 @@ }; #ifdef __KERNEL__ +struct shmid_kernel /* private to the kernel */ +{ + struct kern_ipc_perm shm_perm; + struct file * shm_file; + int id; + unsigned long shm_nattch; + unsigned long shm_segsz; + time_t shm_atim; + time_t shm_dtim; + time_t shm_ctim; + pid_t shm_cprid; + pid_t shm_lprid; +}; /* shm_mode upper byte flags */ #define SHM_DEST 01000 /* segment will be destroyed on last detach */ diff -X dontdiff -Nru lsm-wirex/ipc/sem.c lsm-nailabs/ipc/sem.c --- lsm-wirex/ipc/sem.c Mon Jun 18 13:45:29 2001 +++ lsm-nailabs/ipc/sem.c Mon Jun 18 11:22:05 2001 @@ -60,6 +60,7 @@ #include <linux/spinlock.h> #include <linux/init.h> #include <linux/proc_fs.h> +#include <linux/security.h> #include <asm/uaccess.h> #include "util.h" @@ -112,6 +113,7 @@ static int newary (key_t key, int nsems, int semflg) { int id; + int retval; struct sem_array *sma; int size; @@ -126,6 +128,13 @@ return -ENOMEM; } memset (sma, 0, size); + + retval = security_ops->sem_ops->alloc_security(sma); + if (retval) { + ipc_free(sma, size); + return retval; + } + id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni); if(id == -1) { ipc_free(sma, size); @@ -171,7 +180,8 @@ BUG(); if (nsems > sma->sem_nsems) err = -EINVAL; - else if (ipcperms(&sma->sem_perm, semflg)) + else if (ipcperms(&sma->sem_perm, semflg) || + security_ops->sem_ops->associate(sma, sem_buildid(id, sma->sem_perm.seq), semflg)) err = -EACCES; else err = sem_buildid(id, sma->sem_perm.seq); @@ -384,6 +394,7 @@ int size; sma = sem_rmid(id); + security_ops->sem_ops->free_security(sma); /* Invalidate the existing undo structures for this semaphore set. * (They will be freed without any further action in sem_exit() @@ -438,6 +449,10 @@ struct seminfo seminfo; int max_id; + err = security_ops->ipc_ops->getinfo(semid, cmd); + if (err) + return err; + memset(&seminfo,0,sizeof(seminfo)); seminfo.semmni = sc_semmni; seminfo.semmns = sc_semmns; @@ -479,6 +494,11 @@ err = -EACCES; if (ipcperms (&sma->sem_perm, S_IRUGO)) goto out_unlock; + + err = security_ops->sem_ops->semctl(sma, semid, cmd); + if (err) + goto out_unlock; + id = sem_buildid(semid, sma->sem_perm.seq); kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); @@ -522,6 +542,11 @@ if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO)) goto out_unlock; + err = security_ops->sem_ops->semctl(sma, semid, cmd); + if (err) + goto out_unlock; + + err = -EACCES; switch (cmd) { case GETALL: { @@ -712,6 +737,10 @@ goto out_unlock; } + err = security_ops->sem_ops->semctl(sma, semid, cmd); + if (err) + goto out_unlock; + switch(cmd){ case IPC_RMID: freeary(semid); @@ -869,6 +898,12 @@ error = -EACCES; if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) goto out_unlock_free; + + error = security_ops->sem_ops->semop(sma, semid, sops, nsops, alter); + if (error) + goto out_unlock_free; + error = -EACCES; + if (undos) { /* Make sure we have an undo structure * for this process and this semaphore set. diff -X dontdiff -Nru lsm-wirex/ipc/shm.c lsm-nailabs/ipc/shm.c --- lsm-wirex/ipc/shm.c Mon Jun 18 13:45:29 2001 +++ lsm-nailabs/ipc/shm.c Mon Jun 18 11:22:05 2001 @@ -22,24 +22,11 @@ #include <linux/file.h> #include <linux/mman.h> #include <linux/proc_fs.h> +#include <linux/security.h> #include <asm/uaccess.h> #include "util.h" -struct shmid_kernel /* private to the kernel */ -{ - struct kern_ipc_perm shm_perm; - struct file * shm_file; - int id; - unsigned long shm_nattch; - unsigned long shm_segsz; - time_t shm_atim; - time_t shm_dtim; - time_t shm_ctim; - pid_t shm_cprid; - pid_t shm_lprid; -}; - #define shm_flags shm_perm.mode static struct file_operations shm_file_operations; @@ -191,6 +178,13 @@ shp = (struct shmid_kernel *) kmalloc (sizeof (*shp), GFP_USER); if (!shp) return -ENOMEM; + + error = security_ops->shm_ops->alloc_security(shp); + if (error) { + kfree(shp); + return error; + } + sprintf (name, "SYSV%08x", key); file = shmem_file_setup(name, size); error = PTR_ERR(file); @@ -245,7 +239,8 @@ BUG(); if (shp->shm_segsz < size) err = -EINVAL; - else if (ipcperms(&shp->shm_perm, shmflg)) + else if (ipcperms(&shp->shm_perm, shmflg) || + security_ops->shm_ops->associate(shp, shm_buildid(id, shp->shm_perm.seq), shmflg)) err = -EACCES; else err = shm_buildid(id, shp->shm_perm.seq); @@ -384,6 +379,10 @@ { struct shminfo64 shminfo; + err = security_ops->ipc_ops->getinfo(shmid, cmd); + if (err) + return err; + memset(&shminfo,0,sizeof(shminfo)); shminfo.shmmni = shminfo.shmseg = shm_ctlmni; shminfo.shmmax = shm_ctlmax; @@ -402,6 +401,10 @@ { struct shm_info shm_info; + err = security_ops->ipc_ops->getinfo(shmid, cmd); + if (err) + return err; + memset(&shm_info,0,sizeof(shm_info)); down(&shm_ids.sem); shm_lockall(); @@ -427,6 +430,11 @@ shp = shm_lock(shmid); if(shp==NULL) return -EINVAL; + + err = security_ops->shm_ops->shmctl(shp, shmid, cmd); + if (err) + goto out_unlock; + if(cmd==SHM_STAT) { err = -EINVAL; if (shmid > shm_ids.max_id) @@ -469,6 +477,11 @@ err = shm_checkid(shp,shmid); if(err) goto out_unlock; + + err = security_ops->shm_ops->shmctl(shp, shmid, cmd); + if (err) + goto out_unlock; + if(cmd==SHM_LOCK) { shmem_lock(shp->shm_file, 1); shp->shm_flags |= SHM_LOCKED; @@ -499,6 +512,11 @@ err = shm_checkid(shp, shmid); if(err) goto out_unlock_up; + + err = security_ops->shm_ops->shmctl(shp, shmid, cmd); + if (err) + goto out_unlock_up; + if (current->euid != shp->shm_perm.uid && current->euid != shp->shm_perm.cuid && !capable(CAP_SYS_ADMIN)) { @@ -530,6 +548,11 @@ err = shm_checkid(shp,shmid); if(err) goto out_unlock_up; + + err = security_ops->shm_ops->shmctl(shp, shmid, cmd); + if (err) + goto out_unlock_up; + err=-EPERM; if (current->euid != shp->shm_perm.uid && current->euid != shp->shm_perm.cuid && @@ -610,6 +633,13 @@ shm_unlock(shmid); return -EACCES; } + + err = security_ops->shm_ops->shmat(shp, shmid, shmaddr, shmflg); + if (err) { + shm_unlock(shmid); + return err; + } + file = shp->shm_file; shp->shm_nattch++; shm_unlock(shmid); diff -X dontdiff -Nru lsm-wirex/ipc/util.c lsm-nailabs/ipc/util.c --- lsm-wirex/ipc/util.c Mon Jun 18 13:45:29 2001 +++ lsm-nailabs/ipc/util.c Mon Jun 18 13:14:33 2001 @@ -19,6 +19,7 @@ #include <linux/vmalloc.h> #include <linux/slab.h> #include <linux/highuid.h> +#include <linux/security.h> #if defined(CONFIG_SYSVIPC) @@ -263,7 +264,7 @@ !capable(CAP_IPC_OWNER)) return -1; - return 0; + return security_ops->ipc_ops->permission(ipcp, flag); } /* diff -X dontdiff -Nru lsm-wirex/kernel/Makefile lsm-nailabs/kernel/Makefile --- lsm-wirex/kernel/Makefile Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/Makefile Mon Jun 18 14:12:26 2001 @@ -20,7 +20,6 @@ obj-$(CONFIG_UID16) += uid16.o obj-$(CONFIG_MODULES) += ksyms.o obj-$(CONFIG_PM) += pm.o -obj-$(CONFIG_CAPABILITIES) += capability_plug.o ifneq ($(CONFIG_IA64),y) # According to Alan Modra <alanat_private>, the -fno-omit-frame-pointer is diff -X dontdiff -Nru lsm-wirex/kernel/acct.c lsm-nailabs/kernel/acct.c --- lsm-wirex/kernel/acct.c Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/acct.c Mon Jun 11 16:29:09 2001 @@ -158,8 +158,7 @@ char *tmp; int error; - /* XXX may want to defer this until we have file -cmw */ - if (security_ops->acct()) + if (!capable(CAP_SYS_PACCT)) return -EPERM; if (name) { @@ -182,6 +181,10 @@ if (!file->f_op->write) goto out_err; } + + error = security_ops->acct(file); + if (error) + goto out_err; error = 0; lock_kernel(); diff -X dontdiff -Nru lsm-wirex/kernel/capability_plug.c lsm-nailabs/kernel/capability_plug.c --- lsm-wirex/kernel/capability_plug.c Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/capability_plug.c Wed Dec 31 19:00:00 1969 @@ -1,749 +0,0 @@ -/* - * Capabilities Security plug - * - * 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. - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/security.h> -#include <linux/capability.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/smp_lock.h> -#include <asm/uaccess.h> - -/* #define DEBUG */ - -#ifdef DEBUG -static char *capabilities[] = { "CAP_CHOWN", - "CAP_DAC_OVERRIDE", - "CAP_DAC_READ_SEARCH", - "CAP_FOWNER", - "CAP_FSETID", - "CAP_KILL", - "CAP_SETGID", - "CAP_SETUID", - "CAP_SETPCAP", - "CAP_LINUX_IMMUTABLE", - "CAP_NET_BIND_SERVICE", - "CAP_NET_BROADCAST", - "CAP_NET_ADMIN", - "CAP_NET_RAW", - "CAP_IPC_LOCK", - "CAP_IPC_OWNER", - "CAP_SYS_MODULE", - "CAP_SYS_RAWIO", - "CAP_SYS_CHROOT", - "CAP_SYS_PTRACE", - "CAP_SYS_PACCT", - "CAP_SYS_ADMIN", - "CAP_SYS_BOOT", - "CAP_SYS_NICE", - "CAP_SYS_RESOURCE", - "CAP_SYS_TIME", - "CAP_SYS_TTY_CONFIG", - "CAP_MKNOD", - "CAP_LEASE" }; -#endif /* DEBUG */ - -/* flag to keep track of how we were registered */ -static int secondary; - -struct cap_list { - kernel_cap_t cap_inheritable, cap_permitted, cap_effective; -}; - -static inline int is_capable(int cap) -{ - if (current->security && - cap_raised(((struct cap_list*)(current->security))->cap_effective, cap)) { - current->flags |= PF_SUPERPRIV; -#ifdef DEBUG - printk(KERN_DEBUG " %s(%d) has %s\n", current->comm, - current->pid, capabilities[cap]); -#endif - return 1; - } -#ifdef DEBUG - printk(KERN_DEBUG " %s(%d) does not have %s\n", current->comm, - current->pid, capabilities[cap]); -#endif - return 0; -} - -/* assorted security operations (mostly syscall interposition) */ -static int cap_sethostname(void) -{ - return is_capable(CAP_SYS_ADMIN) ? 0 : -EPERM; -} -static int cap_setdomainname(void) -{ - return is_capable(CAP_SYS_ADMIN) ? 0 : -EPERM; -} -static int cap_reboot(unsigned int cmd) -{ - return is_capable(CAP_SYS_BOOT) ? 0 : -EPERM; -} - -static int cap_mount (char * dev_name, struct nameidata *nd, char * type, unsigned long flags, void * data) {return 0;} -static int cap_add_vfsmnt (struct nameidata *nd, struct super_block *sb, char * dev_name) {return 0;} -static int cap_umount (struct vfsmount *mnt, int flags) {return 0;} -static void cap_umount_close (struct vfsmount *mnt) {return;} -static void cap_umount_busy (struct vfsmount *mnt) {return;} -static int cap_remount (struct vfsmount *mnt, unsigned long flags, void *data) {return 0;} -static void cap_post_remount (struct vfsmount *mnt, unsigned long flags, void *data) {return;} - -static int cap_ioperm(void) -{ - return 0; -} -static int cap_iopl(void) -{ - return 0; -} -static int cap_ptrace(struct task_struct *parent, struct task_struct *child) -{ - if (current == child) /* TRACEME */ - return 0; - return is_capable(CAP_SYS_PTRACE) ? 0 : -EPERM; -} -static int cap_setcapablity(void) -{ - return 0; -} -static int cap_acct(void) -{ - return is_capable(CAP_SYS_PACCT) ? 0 : -EPERM; -} -static int cap_capable(int cap) -{ - return is_capable(cap) ? 0 : -EPERM; -} - -/* binprm security operations */ -static int cap_bprm_alloc_security(struct linux_binprm *bprm) -{ - int rc = -1; - struct cap_list *caps; - caps = (struct cap_list*)kmalloc(sizeof(struct cap_list), GFP_KERNEL); - if (!caps) - goto out; - - rc = 0; - /* from prepare_binprm() */ - /* We don't have VFS support for capabilities yet */ - cap_clear(caps->cap_inheritable); - cap_clear(caps->cap_permitted); - cap_clear(caps->cap_effective); - - /* To support inheritance of root-permissions and suid-root - * executables under compatibility mode, we raise all three - * capability sets for the file. - * - * If only the real uid is 0, we only raise the inheritable - * and permitted sets of the executable file. - */ - - if (!issecure(SECURE_NOROOT)) { - if (bprm->e_uid == 0 || current->uid == 0) { - cap_set_full(caps->cap_inheritable); - cap_set_full(caps->cap_permitted); - } - if (bprm->e_uid == 0) - cap_set_full(caps->cap_effective); - } -out: - bprm->security = (void *)caps; - return rc; -} -static void cap_bprm_free_security(struct linux_binprm *bprm) -{ - if (bprm->security) - kfree(bprm->security); -} - -/* stolen from fs/exec.c needed for compute_creds below */ -static inline int must_not_trace_exec(struct task_struct * p) -{ - /* needs to be converted to use opaque security blob */ - return (p->ptrace & PT_PTRACED) && !cap_raised(p->p_pptr->cap_effective, CAP_SYS_PTRACE); -} -static void cap_bprm_compute_creds(struct linux_binprm *bprm) -{ /* from compute_creds() - * keep_capabilities is still in current - */ - kernel_cap_t new_permitted, working; - int do_unlock = 0; - struct cap_list *bprm_cap = (struct cap_list*)(bprm->security); - struct cap_list *cur_cap = (struct cap_list*)(current->security); - - if (!bprm_cap || !cur_cap) - return; - - new_permitted = cap_intersect(bprm_cap->cap_permitted, cap_bset); - working = cap_intersect(bprm_cap->cap_inheritable, - cur_cap->cap_inheritable); - new_permitted = cap_combine(new_permitted, working); - - if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || - !cap_issubset(new_permitted, cur_cap->cap_permitted)) { - current->dumpable = 0; - - lock_kernel(); - if (must_not_trace_exec(current) - || atomic_read(¤t->fs->count) > 1 - || atomic_read(¤t->files->count) > 1 - || atomic_read(¤t->sig->count) > 1) { - if(!is_capable(CAP_SETUID)) { - bprm->e_uid = current->uid; - bprm->e_gid = current->gid; - } - if(!is_capable(CAP_SETPCAP)) { - new_permitted = cap_intersect(new_permitted, - cur_cap->cap_permitted); - } - } - do_unlock = 1; - } - - - /* For init, we want to retain the capabilities set - * in the init_task struct. Thus we skip the usual - * capability rules */ - if (current->pid != 1) { - cur_cap->cap_permitted = new_permitted; - cur_cap->cap_effective = - cap_intersect(new_permitted, bprm_cap->cap_effective); - } - - /* AUD: Audit candidate if current->cap_effective is set */ - - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; - - if(do_unlock) - unlock_kernel(); - current->keep_capabilities = 0; -} - -/* super_block security operations */ -static int cap_sb_alloc_security(struct super_block *sb) -{ - return 0; -} -static void cap_sb_free_security(struct super_block *sb) -{ - return; -} -static int cap_sb_statfs(struct super_block *sb) -{ - return 0; -} - -/* inode security operations */ -static int cap_inode_alloc_security(struct inode *inode) -{ - return 0; -} -static void cap_inode_free_security(struct inode *inode) -{ - return; -} -static int cap_inode_create(struct inode *inode, struct dentry *dentry, int mask) -{ - return 0; -} -static void cap_inode_post_create(struct inode *inode, struct dentry *dentry, int mask) -{ - return; -} -static int cap_inode_link(struct dentry *old_dentry, struct inode *inode, struct dentry *new_dentry) -{ - return 0; -} -static void cap_inode_post_link(struct dentry *old_dentry, struct inode *inode, struct dentry *new_dentry) -{ - return; -} -static int cap_inode_unlink(struct inode *inode, struct dentry *dentry) -{ - return 0; -} -static int cap_inode_symlink(struct inode *inode, struct dentry *dentry, const char *name) -{ - return 0; -} -static void cap_inode_post_symlink(struct inode *inode, struct dentry *dentry, const char *name) -{ - return; -} -static int cap_inode_mkdir(struct inode *inode, struct dentry *dentry, int mask) -{ - return 0; -} -static void cap_inode_post_mkdir(struct inode *inode, struct dentry *dentry, int mask) -{ - return; -} -static int cap_inode_rmdir(struct inode *inode, struct dentry *dentry) -{ - return 0; -} -static int cap_inode_mknod(struct inode *inode, struct dentry *dentry, int major, dev_t minor) -{ - return 0; -} -static void cap_inode_post_mknod(struct inode *inode, struct dentry *dentry, int major, dev_t minor) -{ - return; -} -static int cap_inode_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry) -{ - return 0; -} -static void cap_inode_post_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry) -{ - return; -} -static int cap_inode_readlink(struct dentry *dentry, char *name, int mask) -{ - return 0; -} -static int cap_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) -{ - return 0; -} -static int cap_inode_truncate(struct inode *inode) -{ - return 0; -} -static int cap_inode_permission(struct inode *inode, int mask) -{ - return 0; -} -static int cap_inode_revalidate(struct dentry *inode) -{ - return 0; -} -static int cap_inode_setattr(struct dentry *dentry, struct iattr *iattr) -{ - return 0; -} -static void cap_inode_attach_pathlabel(struct dentry *dentry, struct vfsmount *mnt) -{ - return; -} -static int cap_inode_stat(struct inode *inode) -{ - return 0; -} - - -/* file security operations */ -static int cap_file_permission(struct file *file, int mask) -{ - return 0; -} -static int cap_file_alloc_security(struct file *file) -{ - return 0; -} -static void cap_file_free_security(struct file *file) -{ - return; -} -static int cap_file_llseek(struct file *file) -{ - return 0; -} -static int cap_file_read(struct file *file) -{ - return 0; -} -static int cap_file_write(struct file *file) -{ - return 0; -} -static int cap_file_ioctl(struct file *file) -{ - return 0; -} -static int cap_file_mmap(struct file *file, unsigned long prot, unsigned long flags) -{ - return 0; -} -static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long prot) -{ - return 0; -} -static int cap_file_lock(struct file *file) -{ - return 0; -} -static int cap_file_readv(struct file *file) -{ - return 0; -} -static int cap_file_writev(struct file *file) -{ - return 0; -} - -static int cap_file_fcntl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - -static int cap_file_fcntl64(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - -/* fown security operations */ -static int cap_fown_alloc_security(struct fown_struct *fown) -{ - return 0; -} - -static void cap_fown_free_security(struct fown_struct *fown) -{ - return; -} - -static int cap_fown_send_sigiotask(struct task_struct *tsk, - struct fown_struct *fown, int fd, - int reason) -{ - return 0; -} - -/* task security operations */ -static int cap_task_create(void) -{ - return 0; -} -static int cap_task_alloc_security(struct task_struct *p) -{ - int rc = -1; - struct cap_list *caps; - caps = (struct cap_list *)kmalloc(sizeof(struct cap_list), GFP_KERNEL); - if (!caps) - goto out; - rc = 0; - if (current->security) - /* inherit from parent, this will break when parent - * has a different security blob - */ - memcpy (caps, current->security, sizeof(struct cap_list)); -out: - p->security = (void *)caps; - return rc; -} -static void cap_task_free_security(struct task_struct *p) -{ - if (p->security) - kfree(p->security); -} -static int cap_task_setuid(void) -{ - return is_capable(CAP_SETUID) ? 0 : -EPERM; -} -static int cap_task_setgid(void) -{ - return is_capable(CAP_SETGID) ? 0 : -EPERM; -} -static int cap_task_setgroups(void) -{ - return is_capable(CAP_SETGID) ? 0 : -EPERM; -} -static int cap_task_setnice(struct task_struct *p, int nice) -{ - return is_capable(CAP_SYS_NICE) ? 0 : -EPERM; -} -static int cap_task_setrlimit(unsigned int resource) -{ - return is_capable(CAP_SYS_RESOURCE) ? 0 : -EPERM; -} -static int cap_task_setscheduler(struct task_struct *p, int policy) -{ - return is_capable(CAP_SYS_NICE) ? 0 : -EPERM; -} -static int cap_task_wait(struct task_struct *p) -{ - return 0; -} -static int cap_task_kill(struct task_struct *p, struct siginfo *info, int sig) -{ - return is_capable(CAP_KILL) ? 0 : -EPERM; -} -static int cap_task_set_label(char *filename) -{ - return 0; -} -static void cap_task_reset_label(void) -{ - return; -} - -/* module security operations */ -static int cap_module_create_module(const char *name_user, size_t size) -{ - return is_capable(CAP_SYS_MODULE) ? 0 : -EPERM; -} -static int cap_module_init_module(const char *name_user, struct module *mod_user) -{ - return is_capable(CAP_SYS_MODULE) ? 0 : -EPERM; -} -static int cap_module_delete_module(const char *name_user) -{ - return is_capable(CAP_SYS_MODULE) ? 0 : -EPERM; -} - -/* message queue security operations */ -static int cap_msg_queue_create(key_t key) -{ - return 0; -} -static int cap_msg_queue_permission(void) -{ - return 0; -} -static int cap_msg_queue_setmaxqbytes(void) -{ - return 0; -} -static int cap_msg_queue_setattr(void) -{ - return 0; -} -static int cap_msg_queue_delete(void) -{ - return 0; -} - -/* shared memory security operations */ -static int cap_shm_create(key_t key) -{ - return 0; -} -static int cap_shm_permission(void) -{ - return 0; -} -static int cap_shm_setattr(void) -{ - return 0; -} -static int cap_shm_delete(void) -{ - return 0; -} - -/* for module stacking */ -int cap_register_security (const char *name, struct security_operations *ops) -{ - return -EPERM; -} -int cap_unregister_security (const char *name, struct security_operations *ops) -{ - return -EPERM; -} - - -static struct binprm_security_ops cap_bprm_ops = { - alloc_security: cap_bprm_alloc_security, - free_security: cap_bprm_free_security, - compute_creds: cap_bprm_compute_creds, -}; -static struct super_block_security_ops cap_sb_ops = { - alloc_security: cap_sb_alloc_security, - free_security: cap_sb_free_security, - statfs: cap_sb_statfs, -}; -static struct inode_security_ops cap_inode_ops = { - alloc_security: cap_inode_alloc_security, - free_security: cap_inode_free_security, - create: cap_inode_create, - post_create: cap_inode_post_create, - link: cap_inode_link, - post_link: cap_inode_post_link, - unlink: cap_inode_unlink, - symlink: cap_inode_symlink, - post_symlink: cap_inode_post_symlink, - mkdir: cap_inode_mkdir, - post_mkdir: cap_inode_post_mkdir, - rmdir: cap_inode_rmdir, - mknod: cap_inode_mknod, - post_mknod: cap_inode_post_mknod, - rename: cap_inode_rename, - post_rename: cap_inode_post_rename, - readlink: cap_inode_readlink, - follow_link: cap_inode_follow_link, - truncate: cap_inode_truncate, - permission: cap_inode_permission, - revalidate: cap_inode_revalidate, - setattr: cap_inode_setattr, - attach_pathlabel:cap_inode_attach_pathlabel, - stat: cap_inode_stat, -}; - -static struct file_security_ops cap_file_ops = { - permission: cap_file_permission, - alloc_security: cap_file_alloc_security, - free_security: cap_file_free_security, - llseek: cap_file_llseek, - read: cap_file_read, - write: cap_file_write, - ioctl: cap_file_ioctl, - mmap: cap_file_mmap, - mprotect: cap_file_mprotect, - lock: cap_file_lock, - readv: cap_file_readv, - writev: cap_file_writev, - fcntl: cap_file_fcntl, - fcntl64: cap_file_fcntl64, -}; - -static struct fown_security_ops cap_fown_ops = { - alloc_security: cap_fown_alloc_security, - free_security: cap_fown_free_security, - send_sigiotask: cap_fown_send_sigiotask, -}; - -static struct task_security_ops cap_task_ops = { - create: cap_task_create, - alloc_security: cap_task_alloc_security, - free_security: cap_task_free_security, - setuid: cap_task_setuid, - setgid: cap_task_setgid, - setgroups: cap_task_setgroups, - setnice: cap_task_setnice, - setrlimit: cap_task_setrlimit, - setscheduler: cap_task_setscheduler, - wait: cap_task_wait, - kill: cap_task_kill, - set_label: cap_task_set_label, - reset_label: cap_task_reset_label, -}; - -static struct socket_security_ops cap_socket_ops = {}; - -static struct module_security_ops cap_module_ops = { - create_module: cap_module_create_module, - init_module: cap_module_init_module, - delete_module: cap_module_delete_module, - -}; - -static struct msg_queue_security_ops cap_msg_queue_ops = { - create: cap_msg_queue_create, - permission: cap_msg_queue_permission, - setmaxqbytes: cap_msg_queue_setmaxqbytes, - setattr: cap_msg_queue_setattr, - delete: cap_msg_queue_delete, -}; - -static struct shm_security_ops cap_shm_ops = { - create: cap_shm_create, - permission: cap_shm_permission, - setattr: cap_shm_setattr, - delete: cap_shm_delete, -}; - -struct security_operations capability_ops = { - version: SECURITY_INTERFACE_VERSION, - - sethostname: cap_sethostname, - setdomainname: cap_setdomainname, - reboot: cap_reboot, - mount: cap_mount, - add_vfsmnt: cap_add_vfsmnt, - umount: cap_umount, - umount_close: cap_umount_close, - umount_busy: cap_umount_busy, - remount: cap_remount, - post_remount: cap_post_remount, - ioperm: cap_ioperm, - iopl: cap_iopl, - ptrace: cap_ptrace, - setcapability: cap_setcapablity, - acct: cap_acct, - capable: cap_capable, - - bprm_ops: &cap_bprm_ops, - sb_ops: &cap_sb_ops, - inode_ops: &cap_inode_ops, - file_ops: &cap_file_ops, - fown_ops: &cap_fown_ops, - task_ops: &cap_task_ops, - socket_ops: &cap_socket_ops, - module_ops: &cap_module_ops, - msg_queue_ops: &cap_msg_queue_ops, - shm_ops: &cap_shm_ops, - - register_security: &cap_register_security, - unregister_security: &cap_unregister_security, -}; - -#define MY_NAME THIS_MODULE->name -static int __init capability_plug_init (void) -{ - /* register ourselves with the security framework */ - if (register_security (&capability_ops)) { - printk (KERN_INFO "Failure registering capabilities with the kernel\n"); - /* try registering with primary module */ - if (mod_reg_security(MY_NAME, &capability_ops)) { - printk (KERN_INFO "Failure registering capbilities " - "with primary security module.\n"); - return -EINVAL; - } - secondary = 1; - } -#if defined(CONFIG_CAPABILITIES) && !defined(CONFIG_CAPABILITIES_MODULE) - /* hack to make this work when compiled in to kernel */ - if (current->pid == 1) { - struct cap_list *cap; - if (cap_task_alloc_security(current)) - panic("Couldn't allocate initial task security blob\n"); - cap = (struct cap_list *)current->security; - cap->cap_effective = CAP_INIT_EFF_SET; - cap->cap_inheritable = CAP_INIT_INH_SET; - cap->cap_permitted = CAP_FULL_SET; - } -#endif /* CONFIG_CAPABILITIES && !CONFIG_CAPABILITIES_MODULE */ - printk(KERN_INFO "Capability Plug initialized\n"); - return 0; -} - - -static void __exit capability_plug_exit (void) -{ - /* remove ourselves from the security framework */ - if (secondary) { - if (mod_unreg_security (MY_NAME, &capability_ops)) - printk (KERN_INFO "Failure unregistering capabilities " - "with primary module.\n"); - return; - } - - if (unregister_security (&capability_ops)) { - printk (KERN_INFO "Failure unregistering capabilities with the kernel\n"); - } -} - - -module_init (capability_plug_init); -module_exit (capability_plug_exit); - -EXPORT_SYMBOL(capability_ops); - diff -X dontdiff -Nru lsm-wirex/kernel/module.c lsm-nailabs/kernel/module.c --- lsm-wirex/kernel/module.c Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/module.c Mon Jun 11 16:29:09 2001 @@ -298,6 +298,8 @@ struct module *mod; unsigned long flags; + if (!capable(CAP_SYS_MODULE)) + return -EPERM; lock_kernel(); if ((namelen = get_mod_name(name_user, &name)) < 0) { error = namelen; @@ -357,6 +359,8 @@ unsigned long mod_user_size; struct module_ref *dep; + if (!capable(CAP_SYS_MODULE)) + return -EPERM; lock_kernel(); if ((namelen = get_mod_name(name_user, &name)) < 0) { error = namelen; @@ -614,6 +618,9 @@ char *name; long error; int something_changed; + + if (!capable(CAP_SYS_MODULE)) + return -EPERM; lock_kernel(); if (name_user) { diff -X dontdiff -Nru lsm-wirex/kernel/sched.c lsm-nailabs/kernel/sched.c --- lsm-wirex/kernel/sched.c Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/sched.c Mon Jun 18 14:27:17 2001 @@ -842,14 +842,19 @@ asmlinkage long sys_nice(int increment) { long newprio; + int retval; /* * Setpriority might change our priority at the same moment. * We don't have to worry. Conceptually one call occurs first * and we have a single winner. */ - if (increment < -40) - increment = -40; + if (increment < 0) { + if (!capable(CAP_SYS_NICE)) + return -EPERM; + if (increment < -40) + increment = -40; + } if (increment > 40) increment = 40; @@ -858,10 +863,11 @@ newprio = -20; if (newprio > 19) newprio = 19; - if (increment < 0) { - if (security_ops->task_ops->setnice(current, newprio)) - return -EPERM; - } + + retval = security_ops->task_ops->setnice(current, newprio); + if (retval) + return retval; + current->nice = newprio; return 0; } @@ -883,7 +889,6 @@ struct sched_param lp; struct task_struct *p; int retval; - int no_sched; retval = -EINVAL; if (!param || pid < 0) @@ -924,13 +929,16 @@ if ((policy == SCHED_OTHER) != (lp.sched_priority == 0)) goto out_unlock; + retval = security_ops->task_ops->setscheduler(p, policy); + if (retval) + goto out_unlock; + retval = -EPERM; - no_sched = security_ops->task_ops->setscheduler(p, policy); if ((policy == SCHED_FIFO || policy == SCHED_RR) && - no_sched) + !capable(CAP_SYS_NICE)) goto out_unlock; if ((current->euid != p->euid) && (current->euid != p->uid) && - no_sched) + !capable(CAP_SYS_NICE)) goto out_unlock; retval = 0; diff -X dontdiff -Nru lsm-wirex/kernel/security.c lsm-nailabs/kernel/security.c --- lsm-wirex/kernel/security.c Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/security.c Mon Jun 18 14:02:03 2001 @@ -6,6 +6,10 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * + * 2001_Jun_12 Stephen Smalley <sdsat_private>, NAI Labs, SELinux project + * Changed all non-capable hooks to be authoritative or restrictive. + * Added parameters to several of the hook functions. + * * 2001_Apr_18 greg k-h * fleshed out with current security.h stubs * @@ -32,9 +36,9 @@ /* Stub functions for the default security function pointers in case no security model is loaded */ -static int dummy_sethostname (void) {return 0;} -static int dummy_setdomainname (void) {return 0;} -static int dummy_reboot (unsigned int cmd) {return 0;} +static int dummy_sethostname(char *hostname) {return 0;} +static int dummy_setdomainname(char *domainname) { return 0; } +static int dummy_reboot (unsigned int cmd, void *arg) { return 0; } static int dummy_mount (char * dev_name, struct nameidata *nd, char * type, unsigned long flags, void * data) {return 0;} static int dummy_add_vfsmnt (struct nameidata *nd, struct super_block *sb, char * dev_name) {return 0;} static int dummy_umount (struct vfsmount *mnt, int flags) {return 0;} @@ -42,20 +46,12 @@ static void dummy_umount_busy (struct vfsmount *mnt) {return;} static int dummy_remount (struct vfsmount *mnt, unsigned long flags, void *data) {return 0;} static void dummy_post_remount (struct vfsmount *mnt, unsigned long flags, void *data) {return;} -static int dummy_ioperm (void) {return 0;} -static int dummy_iopl (void) {return 0;} -static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) {return 0;} +static int dummy_ioperm(unsigned long from, unsigned long num, int turn_on) { return 0; } +static int dummy_iopl(unsigned int old, unsigned int level) { return 0; } +static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) { return 0; } static int dummy_setcapablity (void) {return 0;} -static int dummy_acct (void) {return 0;} -static int dummy_capable (int cap) -{ - /* stolen from original capable call */ - if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0) { - current->flags |= PF_SUPERPRIV; - return 0; - } - return -EPERM; -} +static int dummy_acct (struct file *file) { return 0; } +static int dummy_capable (int cap) {return 0;} static int dummy_binprm_alloc_security(struct linux_binprm *bprm) {return 0;} static void dummy_binprm_free_security (struct linux_binprm *bprm) {return;} @@ -64,6 +60,7 @@ static int dummy_sb_alloc_security(struct super_block *sb) {return 0;} static void dummy_sb_free_security (struct super_block *sb) {return;} static int dummy_sb_statfs (struct super_block *sb) {return 0;} + static int dummy_inode_alloc_security (struct inode *inode) {return 0;} static void dummy_inode_free_security (struct inode *inode) {return;} static int dummy_inode_create (struct inode *inode, struct dentry *dentry, int mask) {return 0;} @@ -83,9 +80,9 @@ static int dummy_inode_readlink (struct dentry *dentry, char *name, int mask) {return 0;} static int dummy_inode_follow_link (struct dentry *dentry, struct nameidata *nameidata) {return 0;} static int dummy_inode_truncate (struct inode *inode) {return 0;} -static int dummy_inode_permission (struct inode *inode, int mask) {return 0;} +static int dummy_inode_permission(struct inode *inode, int mask) { return 0; } static int dummy_inode_revalidate (struct dentry *inode) {return 0;} -static int dummy_inode_setattr (struct dentry *dentry, struct iattr *iattr) {return 0;} +static int dummy_inode_setattr(struct dentry *dentry, struct iattr *iattr) { return 0; } static void dummy_inode_attach_pathlabel(struct dentry *dentry, struct vfsmount *mnt) {return;} static int dummy_inode_stat(struct inode *inode) {return 0;} @@ -95,7 +92,8 @@ static int dummy_file_llseek (struct file *file) {return 0;} static int dummy_file_read (struct file *file) {return 0;} static int dummy_file_write (struct file *file) {return 0;} -static int dummy_file_ioctl (struct file *file) {return 0;} +static int dummy_file_ioctl (struct file *file, unsigned int command +, unsigned long arg) {return 0;} static int dummy_file_mmap (struct file *file, unsigned long prot, unsigned long flags) {return 0;} static int dummy_file_mprotect (struct vm_area_struct *vma, unsigned long prot) {return 0;} static int dummy_file_lock (struct file *file) {return 0;} @@ -103,22 +101,22 @@ static int dummy_file_writev (struct file *file) {return 0;} static int dummy_file_fcntl (struct file *file, unsigned int cmd, unsigned long arg) {return 0;} static int dummy_file_fcntl64 (struct file *file, unsigned int cmd, unsigned long arg) {return 0;} - -static int dummy_fown_alloc_security (struct fown_struct *fown) {return 0;} -static void dummy_fown_free_security (struct fown_struct *fown) {return;} -static int dummy_fown_send_sigiotask (struct task_struct *tsk, struct fown_struct *fown, int fd, int reason) {return 0;} +static int dummy_file_set_fowner (struct file *file) {return 0;} +static int dummy_file_send_sigiotask (struct task_struct *tsk, struct fown_struct *fown, int fd, int reason) { return 0; } static int dummy_task_create (void) {return 0;} static int dummy_task_alloc_security (struct task_struct *p) {return 0;} static void dummy_task_free_security (struct task_struct *p) {return;} -static int dummy_task_setuid (void) {return 0;} -static int dummy_task_setgid (void) {return 0;} -static int dummy_task_setgroups (void) {return 0;} -static int dummy_task_setnice (struct task_struct *p, int nice) {return 0;} -static int dummy_task_setrlimit (unsigned int resource) {return 0;} -static int dummy_task_setscheduler (struct task_struct *p, int policy) {return 0;} +static int dummy_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) { return 0; } +static int dummy_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) { return 0; } +static int dummy_task_setgroups(int gidsetsize, gid_t *grouplist) { return 0; } +static int dummy_task_setnice(struct task_struct *p, int nice) { return 0; } +static int dummy_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) { return 0; } +static int dummy_task_setscheduler(struct task_struct *p, int policy) { return 0; } static int dummy_task_wait (struct task_struct *p) {return 0;} -static int dummy_task_kill (struct task_struct *p, struct siginfo *info, int sig) {return 0;} + +static int dummy_task_kill (struct task_struct *p, struct siginfo *info, int sig) { return 0; } + static int dummy_task_set_label (char *filename) {return 0;} static void dummy_task_reset_label (void) {return;} @@ -126,16 +124,26 @@ static int dummy_module_init_module (const char *name_user, struct module *mod_user) {return 0;} static int dummy_module_delete_module (const char *name_user) {return 0;} +static int dummy_ipc_permission(struct kern_ipc_perm *ipcp, short flag) { return 0; } +static int dummy_ipc_getinfo(int id, int cmd) {return 0;} + static int dummy_msg_queue_create (key_t key) {return 0;} static int dummy_msg_queue_permission (void) {return 0;} static int dummy_msg_queue_setmaxqbytes (void) {return 0;} static int dummy_msg_queue_setattr (void) {return 0;} static int dummy_msg_queue_delete (void) {return 0;} -static int dummy_shm_create (key_t key) {return 0;} -static int dummy_shm_permission (void) {return 0;} -static int dummy_shm_setattr (void) {return 0;} -static int dummy_shm_delete (void) {return 0;} +static int dummy_shm_alloc_security(struct shmid_kernel *shp) {return 0;} +static void dummy_shm_free_security(struct shmid_kernel *shp) {return;} +static int dummy_shm_associate(struct shmid_kernel *shp, int shmid, int shmflg) {return 0;} +static int dummy_shm_shmctl(struct shmid_kernel *shp, int shmid, int cmd) {return 0;} +static int dummy_shm_shmat(struct shmid_kernel *shp, int shmid, char *shmaddr, int shmflg) {return 0;} + +static int dummy_sem_alloc_security(struct sem_array *sma) {return 0;} +static void dummy_sem_free_security(struct sem_array *sma) {return;} +static int dummy_sem_associate(struct sem_array *sma, int semid, int semflg) {return 0;} +static int dummy_sem_semctl(struct sem_array *sma, int semid, int cmd) {return 0;} +static int dummy_sem_semop(struct sem_array *sma, int semid, struct sembuf *sops, unsigned nsops, int alter) {return 0;} static int dummy_register (const char *name, struct security_operations *ops) {return -EINVAL;} @@ -194,12 +202,8 @@ writev: dummy_file_writev, fcntl: dummy_file_fcntl, fcntl64: dummy_file_fcntl64, -}; - -static struct fown_security_ops dummy_fown_ops = { - alloc_security: dummy_fown_alloc_security, - free_security: dummy_fown_free_security, - send_sigiotask: dummy_fown_send_sigiotask, + set_fowner: dummy_file_set_fowner, + send_sigiotask: dummy_file_send_sigiotask, }; static struct task_security_ops dummy_task_ops = { @@ -227,6 +231,11 @@ }; +static struct ipc_security_ops dummy_ipc_ops = { + permission: dummy_ipc_permission, + getinfo: dummy_ipc_getinfo, +}; + static struct msg_queue_security_ops dummy_msg_queue_ops = { create: dummy_msg_queue_create, permission: dummy_msg_queue_permission, @@ -236,10 +245,19 @@ }; static struct shm_security_ops dummy_shm_ops = { - create: dummy_shm_create, - permission: dummy_shm_permission, - setattr: dummy_shm_setattr, - delete: dummy_shm_delete, + alloc_security: dummy_shm_alloc_security, + free_security: dummy_shm_free_security, + associate: dummy_shm_associate, + shmctl: dummy_shm_shmctl, + shmat: dummy_shm_shmat, +}; + +static struct sem_security_ops dummy_sem_ops = { + alloc_security: dummy_sem_alloc_security, + free_security: dummy_sem_free_security, + associate: dummy_sem_associate, + semctl: dummy_sem_semctl, + semop: dummy_sem_semop, }; static struct security_operations dummy_security_ops = { @@ -268,9 +286,11 @@ file_ops: &dummy_file_ops, task_ops: &dummy_task_ops, socket_ops: &dummy_socket_ops, + ipc_ops: &dummy_ipc_ops, module_ops: &dummy_module_ops, msg_queue_ops: &dummy_msg_queue_ops, shm_ops: &dummy_shm_ops, + sem_ops: &dummy_sem_ops, register_security: dummy_register, unregister_security: dummy_unregister, @@ -401,7 +421,17 @@ int capable (int cap) { - return security_ops->capable(cap) ? 0 : 1; + if (!cap_raised(current->cap_effective, cap)) + return 0; + + if (!security_ops->capable(cap)) + { + current->flags |= PF_SUPERPRIV; + return 1; + } + + return 0; + } EXPORT_SYMBOL(register_security); @@ -409,4 +439,3 @@ EXPORT_SYMBOL(mod_reg_security); EXPORT_SYMBOL(mod_unreg_security); EXPORT_SYMBOL(capable); -EXPORT_SYMBOL(security_ops); diff -X dontdiff -Nru lsm-wirex/kernel/signal.c lsm-nailabs/kernel/signal.c --- lsm-wirex/kernel/signal.c Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/signal.c Mon Jun 18 12:36:38 2001 @@ -311,7 +311,7 @@ && ((sig != SIGCONT) || (current->session != t->session)) && (current->euid ^ t->suid) && (current->euid ^ t->uid) && (current->uid ^ t->suid) && (current->uid ^ t->uid) - && security_ops->task_ops->kill(t, info, sig); + && !capable(CAP_KILL); } /* @@ -517,6 +517,9 @@ /* The somewhat baroque permissions check... */ ret = -EPERM; if (bad_signal(sig, info, t)) + goto out_nolock; + ret = security_ops->task_ops->kill(t, info, sig); + if (ret) goto out_nolock; /* The null signal is a permissions and process existance probe. diff -X dontdiff -Nru lsm-wirex/kernel/sys.c lsm-nailabs/kernel/sys.c --- lsm-wirex/kernel/sys.c Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/sys.c Mon Jun 18 13:16:58 2001 @@ -215,14 +215,18 @@ if (!proc_sel(p, which, who)) continue; no_nice = security_ops->task_ops->setnice(p, niceval); + if (no_nice) { + error = no_nice; + continue; + } if (p->uid != current->euid && - p->uid != current->uid && no_nice) { + p->uid != current->uid && !capable(CAP_SYS_NICE)) { error = -EPERM; continue; } if (error == -ESRCH) error = 0; - if (niceval < p->nice && no_nice) + if (niceval < p->nice && !capable(CAP_SYS_NICE)) error = -EACCES; else p->nice = niceval; @@ -272,12 +276,15 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void * arg) { char buffer[256]; - int result; + int retval; - /* check that we have permission to do this */ - result = security_ops->reboot(cmd); - if (result) { - return result; + /* We only trust the superuser with rebooting the system. */ + if (!capable(CAP_SYS_BOOT)) + return -EPERM; + + retval = security_ops->reboot(cmd, arg); + if (retval) { + return retval; } /* For safety, we require "magic" arguments. */ @@ -384,13 +391,16 @@ int old_egid = current->egid; int new_rgid = old_rgid; int new_egid = old_egid; - int ok_to_setgid; + int retval = 0; + + retval = security_ops->task_ops->setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); + if (retval) + return retval; - ok_to_setgid = !(security_ops->task_ops->setgid()); if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || (current->egid==rgid) || - ok_to_setgid) + capable(CAP_SETGID)) new_rgid = rgid; else return -EPERM; @@ -399,7 +409,7 @@ if ((old_rgid == egid) || (current->egid == egid) || (current->sgid == egid) || - ok_to_setgid) + capable(CAP_SETGID)) new_egid = egid; else { return -EPERM; @@ -427,8 +437,13 @@ asmlinkage long sys_setgid(gid_t gid) { int old_egid = current->egid; + int retval; - if (!security_ops->task_ops->setgid()) + retval = security_ops->task_ops->setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); + if (retval) + return retval; + + if (capable(CAP_SETGID)) { if(old_egid != gid) { @@ -542,19 +557,21 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) { int old_ruid, old_euid, old_suid, new_ruid, new_euid; - int no_setuid; + int retval; + + retval = security_ops->task_ops->setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); + if (retval) + return retval; new_ruid = old_ruid = current->uid; new_euid = old_euid = current->euid; old_suid = current->suid; - no_setuid = security_ops->task_ops->setuid(); - if (ruid != (uid_t) -1) { new_ruid = ruid; if ((old_ruid != ruid) && (current->euid != ruid) && - no_setuid) + !capable(CAP_SETUID)) return -EPERM; } @@ -563,7 +580,7 @@ if ((old_ruid != euid) && (current->euid != euid) && (current->suid != euid) && - no_setuid) + !capable(CAP_SETUID)) return -EPERM; } @@ -581,7 +598,6 @@ current->suid = current->euid; current->fsuid = current->euid; - /* XXX need to fold this in to LSM hook -cmw */ if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } @@ -606,12 +622,17 @@ { int old_euid = current->euid; int old_ruid, old_suid, new_ruid, new_suid; + int retval; + + retval = security_ops->task_ops->setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); + if (retval) + return retval; old_ruid = new_ruid = current->uid; old_suid = current->suid; new_suid = old_suid; - if (!security_ops->task_ops->setuid()) { + if (capable(CAP_SETUID)) { if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) return -EAGAIN; new_suid = uid; @@ -626,7 +647,6 @@ current->fsuid = current->euid = uid; current->suid = new_suid; - /* XXX need to fold this in to LSM hook -cmw */ if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } @@ -644,8 +664,13 @@ int old_ruid = current->uid; int old_euid = current->euid; int old_suid = current->suid; + int retval; + + retval = security_ops->task_ops->setuid(ruid, euid, suid, LSM_SETID_RES); + if (retval) + return retval; - if (security_ops->task_ops->setuid()) { + if (!capable(CAP_SETUID)) { if ((ruid != (uid_t) -1) && (ruid != current->uid) && (ruid != current->euid) && (ruid != current->suid)) return -EPERM; @@ -672,7 +697,6 @@ if (suid != (uid_t) -1) current->suid = suid; - /* XXX need to fold this in to LSM hook -cmw */ if (!issecure(SECURE_NO_SETUID_FIXUP)) { cap_emulate_setxuid(old_ruid, old_euid, old_suid); } @@ -696,7 +720,13 @@ */ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { - if (security_ops->task_ops->setgid()) { + int retval; + + retval = security_ops->task_ops->setgid(rgid, egid, sgid, LSM_SETID_RES); + if (retval) + return retval; + + if (!capable(CAP_SETGID)) { if ((rgid != (gid_t) -1) && (rgid != current->gid) && (rgid != current->egid) && (rgid != current->sgid)) return -EPERM; @@ -744,11 +774,16 @@ asmlinkage long sys_setfsuid(uid_t uid) { int old_fsuid; + int retval; + + retval = security_ops->task_ops->setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); + if (retval) + return retval; old_fsuid = current->fsuid; if (uid == current->uid || uid == current->euid || uid == current->suid || uid == current->fsuid || - !security_ops->task_ops->setuid()) + capable(CAP_SETUID)) { if (uid != old_fsuid) { @@ -767,7 +802,6 @@ * if not, we might be a bit too harsh here. */ - /* XXX need to fold this in to LSM hook -cmw */ if (!issecure(SECURE_NO_SETUID_FIXUP)) { if (old_fsuid == 0 && current->fsuid != 0) { cap_t(current->cap_effective) &= ~CAP_FS_MASK; @@ -787,11 +821,16 @@ asmlinkage long sys_setfsgid(gid_t gid) { int old_fsgid; + int retval; + + retval = security_ops->task_ops->setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS); + if (retval) + return retval; old_fsgid = current->fsgid; if (gid == current->gid || gid == current->egid || gid == current->sgid || gid == current->fsgid || - !security_ops->task_ops->setgid()) + capable(CAP_SETGID)) { if (gid != old_fsgid) { @@ -979,12 +1018,19 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist) { - if (security_ops->task_ops->setgroups()) + gid_t groups[NGROUPS]; + int retval; + + if (!capable(CAP_SETGID)) return -EPERM; if ((unsigned) gidsetsize > NGROUPS) return -EINVAL; - if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t))) + if(copy_from_user(groups, grouplist, gidsetsize * sizeof(gid_t))) return -EFAULT; + retval = security_ops->task_ops->setgroups(gidsetsize, groups); + if (retval) + return retval; + memcpy(current->groups, groups, gidsetsize * sizeof(gid_t)); current->ngroups = gidsetsize; return 0; } @@ -1039,21 +1085,25 @@ asmlinkage long sys_sethostname(char *name, int len) { + char nodename[__NEW_UTS_LEN+1]; int errno; - if (security_ops->sethostname()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; + if (copy_from_user(nodename, name, len)) + return -EFAULT; + nodename[len] = 0; + + errno = security_ops->sethostname(nodename); + if (errno) + return errno; down_write(&uts_sem); - errno = -EFAULT; - if (!copy_from_user(system_utsname.nodename, name, len)) { - system_utsname.nodename[len] = 0; - errno = 0; - } + memcpy(system_utsname.nodename, nodename, len+1); up_write(&uts_sem); - return errno; + return 0; } asmlinkage long sys_gethostname(char *name, int len) @@ -1079,19 +1129,23 @@ */ asmlinkage long sys_setdomainname(char *name, int len) { + char domainname[__NEW_UTS_LEN+1]; int errno; - if (security_ops->setdomainname()) + if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; + if (copy_from_user(domainname, name, len)) + return -EFAULT; + domainname[len] = 0; + + errno = security_ops->setdomainname(domainname); + if (errno) + return errno; down_write(&uts_sem); - errno = -EFAULT; - if (!copy_from_user(system_utsname.domainname, name, len)) { - errno = 0; - system_utsname.domainname[len] = 0; - } + memcpy(system_utsname.domainname, domainname, len+1); up_write(&uts_sem); return errno; } @@ -1130,6 +1184,7 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim) { struct rlimit new_rlim, *old_rlim; + int retval; if (resource >= RLIM_NLIMITS) return -EINVAL; @@ -1140,12 +1195,17 @@ old_rlim = current->rlim + resource; if (((new_rlim.rlim_cur > old_rlim->rlim_max) || (new_rlim.rlim_max > old_rlim->rlim_max)) && - security_ops->task_ops->setrlimit(resource)) + !capable(CAP_SYS_RESOURCE)) return -EPERM; if (resource == RLIMIT_NOFILE) { if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN) return -EPERM; } + + retval = security_ops->task_ops->setrlimit(resource, &new_rlim); + if (retval) + return retval; + *old_rlim = new_rlim; return 0; } diff -X dontdiff -Nru lsm-wirex/kernel/sysctl.c lsm-nailabs/kernel/sysctl.c --- lsm-wirex/kernel/sysctl.c Mon Jun 18 13:45:15 2001 +++ lsm-nailabs/kernel/sysctl.c Mon Jun 11 14:19:57 2001 @@ -942,7 +942,6 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp, void *buffer, size_t *lenp) { - /* XXX this is really capabilities specific -cmw */ if (!capable(CAP_SYS_MODULE)) { return -EPERM; } diff -X dontdiff -Nru lsm-wirex/security/Config.in lsm-nailabs/security/Config.in --- lsm-wirex/security/Config.in Mon Jun 18 13:45:29 2001 +++ lsm-nailabs/security/Config.in Mon Jun 18 14:12:26 2001 @@ -3,6 +3,5 @@ # mainmenu_option next_comment comment 'Security options' -tristate ' Capabilities Support' CONFIG_CAPABILITIES endmenu _______________________________________________ linux-security-module mailing list linux-security-moduleat_private http://mail.wirex.com/mailman/listinfo/linux-security-module
This archive was generated by hypermail 2b30 : Mon Jun 18 2001 - 12:06:38 PDT