]> git.hungrycats.org Git - linux/commitdiff
LSM: Enable the security framework. This includes basic task control hooks.
authorGreg Kroah-Hartman <greg@kroah.com>
Fri, 19 Jul 2002 09:01:00 +0000 (02:01 -0700)
committerGreg Kroah-Hartman <greg@kroah.com>
Fri, 19 Jul 2002 09:01:00 +0000 (02:01 -0700)
17 files changed:
Makefile
arch/i386/config.in
arch/i386/kernel/entry.S
arch/i386/kernel/ptrace.c
fs/exec.c
include/linux/binfmts.h
include/linux/sched.h
init/main.c
kernel/capability.c
kernel/exit.c
kernel/fork.c
kernel/kmod.c
kernel/ptrace.c
kernel/sched.c
kernel/signal.c
kernel/sys.c
kernel/uid16.c

index bd25959aa9e94f6a1a11c88298f4ea5131ecdb26..866cc74d539eac7a923c7d5060563821b7407882 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -157,7 +157,8 @@ objtree := $(TOPDIR)
 
 export srctree objtree
 
-SUBDIRS                := init kernel mm fs ipc lib drivers sound net
+SUBDIRS                := init kernel mm fs ipc lib drivers sound net security
+
 
 noconfig_targets := xconfig menuconfig config oldconfig randconfig \
                    defconfig allyesconfig allnoconfig allmodconfig \
@@ -223,7 +224,7 @@ endif
 # ---------------------------------------------------------------------------
 
 INIT           := init/init.o
-CORE_FILES     := kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
+CORE_FILES     := kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o security/built-in.o
 LIBS           := lib/lib.a
 DRIVERS                := drivers/built-in.o sound/sound.o
 NETWORKS       := net/network.o
index 0a35c2b5638cb7fe0f9d4a196966dd58eae841f1..497404ef3ab152488da4e251b9ae7d4875285fbf 100644 (file)
@@ -423,4 +423,5 @@ fi
 
 endmenu
 
+source security/Config.in
 source lib/Config.in
index 09d3034543783cf1cee1d2c80a04342e98c44aba..c068803128c89b7e325de0fb46ac4bb733dfb451 100644 (file)
@@ -744,7 +744,7 @@ ENTRY(sys_call_table)
        .long sys_getdents64    /* 220 */
        .long sys_fcntl64
        .long sys_ni_syscall    /* reserved for TUX */
-       .long sys_ni_syscall    /* reserved for Security */
+       .long sys_security      /* reserved for Security */
        .long sys_gettid
        .long sys_readahead     /* 225 */
        .long sys_setxattr
index 4afb2afc64d3f585c727aef15237a834f53f3c90..a10602335c56a2cf69b599a9e7d78d36ddbb695c 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/user.h>
+#include <linux/security.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -159,6 +160,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                /* are we already being traced? */
                if (current->ptrace & PT_PTRACED)
                        goto out;
+               ret = security_ops->ptrace(current->parent, current);
+               if (ret)
+                       goto out;
                /* set the ptrace bit in the process flags. */
                current->ptrace |= PT_PTRACED;
                ret = 0;
index 354735b146cc1e69a7a2b41f3e6b158bd428e8d0..32fcccd085629e288aea3f7b31bc6d401ffc0c2c 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -623,6 +623,7 @@ int prepare_binprm(struct linux_binprm *bprm)
 {
        int mode;
        struct inode * inode = bprm->file->f_dentry->d_inode;
+       int retval;
 
        mode = inode->i_mode;
        /*
@@ -652,27 +653,10 @@ int prepare_binprm(struct linux_binprm *bprm)
                        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 */
+       retval = security_ops->bprm_set_security(bprm);
+       if (retval)
+               return retval;
 
        memset(bprm->buf,0,BINPRM_BUF_SIZE);
        return kernel_read(bprm->file,0,bprm->buf,BINPRM_BUF_SIZE);
@@ -695,16 +679,9 @@ int prepare_binprm(struct linux_binprm *bprm)
 
 void compute_creds(struct linux_binprm *bprm) 
 {
-       kernel_cap_t new_permitted, working;
        int do_unlock = 0;
 
-       new_permitted = cap_intersect(bprm->cap_permitted, cap_bset);
-       working = cap_intersect(bprm->cap_inheritable,
-                               current->cap_inheritable);
-       new_permitted = cap_combine(new_permitted, working);
-
-       if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
-           !cap_issubset(new_permitted, current->cap_permitted)) {
+       if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
                 current->mm->dumpable = 0;
                
                lock_kernel();
@@ -716,32 +693,17 @@ void compute_creds(struct linux_binprm *bprm)
                                bprm->e_uid = current->uid;
                                bprm->e_gid = current->gid;
                        }
-                       if(!capable(CAP_SETPCAP)) {
-                               new_permitted = cap_intersect(new_permitted,
-                                                       current->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) {
-               current->cap_permitted = new_permitted;
-               current->cap_effective =
-                       cap_intersect(new_permitted, bprm->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;
+
+       security_ops->bprm_compute_creds(bprm);
 }
 
 
@@ -811,6 +773,10 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
            }
        }
 #endif
+       retval = security_ops->bprm_check_security(bprm);
+       if (retval) 
+               return retval;
+
        /* kernel module loader fixup */
        /* so we don't try to load run modprobe in kernel space. */
        set_fs(USER_DS);
@@ -887,7 +853,7 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
        bprm.sh_bang = 0;
        bprm.loader = 0;
        bprm.exec = 0;
-
+       bprm.security = NULL;
        bprm.mm = mm_alloc();
        retval = -ENOMEM;
        if (!bprm.mm)
@@ -905,6 +871,10 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
        if ((retval = bprm.envc) < 0)
                goto out_mm;
 
+       retval = security_ops->bprm_alloc_security(&bprm);
+       if (retval) 
+               goto out;
+
        retval = prepare_binprm(&bprm);
        if (retval < 0) 
                goto out; 
@@ -923,9 +893,11 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs
                goto out; 
 
        retval = search_binary_handler(&bprm,regs);
-       if (retval >= 0)
+       if (retval >= 0) {
                /* execve success */
+               security_ops->bprm_free_security(&bprm);
                return retval;
+       }
 
 out:
        /* Something went wrong, return the inode and free the argument pages*/
@@ -935,6 +907,9 @@ out:
                        __free_page(page);
        }
 
+       if (bprm.security)
+               security_ops->bprm_free_security(&bprm);
+
 out_mm:
        mmdrop(bprm.mm);
 
index fe17499f614446fe5c5150985eba6c3fd883db8e..314addb2329d6c6753edb6ba0f31a8c3f57a32a5 100644 (file)
@@ -28,6 +28,7 @@ struct linux_binprm{
        struct file * file;
        int e_uid, e_gid;
        kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
+       void *security;
        int argc, envc;
        char * filename;        /* Name of binary */
        unsigned long loader, exec;
index 2e38ae05d9d2c67e0ca82e3b015bd3b62c1fd1c5..1d288587e44d950d628af6bd50909da333d8ca66 100644 (file)
@@ -354,6 +354,8 @@ struct task_struct {
        void *notifier_data;
        sigset_t *notifier_mask;
        
+       void *security;
+
 /* Thread group tracking */
        u32 parent_exec_id;
        u32 self_exec_id;
@@ -587,10 +589,9 @@ extern int request_irq(unsigned int,
                       unsigned long, const char *, void *);
 extern void free_irq(unsigned int, void *);
 
-/*
- * capable() checks for a particular capability.
- * 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)
 {
        if (cap_raised(current->cap_effective, cap)) {
@@ -599,6 +600,7 @@ static inline int capable(int cap)
        }
        return 0;
 }
+#endif /* if 0 */
 
 /*
  * Routines for handling mm_structs
index 81879f47768ff6b0de8e3cf02ffb91b0272e8c80..2133b32001de0dac5bd9471855be94bf6775aafe 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/tty.h>
 #include <linux/percpu.h>
 #include <linux/kernel_stat.h>
+#include <linux/security.h>
 
 #include <asm/io.h>
 #include <asm/bugs.h>
@@ -390,6 +391,7 @@ asmlinkage void __init start_kernel(void)
 
        fork_init(mempages);
        proc_caches_init();
+       security_scaffolding_startup();
        buffer_init();
        vfs_caches_init(mempages);
        radix_tree_init();
index 5796b182005c19cdfb6ce06c7b1132817a60a08e..223d22dece42028a54821f6893e958d61952d075 100644 (file)
@@ -63,6 +63,7 @@ asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
      data.permitted = cap_t(target->cap_permitted);
      data.inheritable = cap_t(target->cap_inheritable); 
      data.effective = cap_t(target->cap_effective);
+     ret = security_ops->capget(target, &data.effective, &data.inheritable, &data.permitted);
 
 out:
      read_unlock(&tasklist_lock); 
@@ -87,9 +88,7 @@ static inline void cap_set_pg(int pgrp, kernel_cap_t *effective,
      for_each_task(target) {
              if (target->pgrp != pgrp)
                      continue;
-             target->cap_effective   = *effective;
-             target->cap_inheritable = *inheritable;
-             target->cap_permitted   = *permitted;
+            security_ops->capset_set(target, effective, inheritable, permitted);
      }
 }
 
@@ -106,9 +105,7 @@ static inline void cap_set_all(kernel_cap_t *effective,
      for_each_task(target) {
              if (target == current || target->pid == 1)
                      continue;
-             target->cap_effective   = *effective;
-             target->cap_inheritable = *inheritable;
-             target->cap_permitted   = *permitted;
+            security_ops->capset_set(target, effective, inheritable, permitted);
      }
 }
 
@@ -166,7 +163,9 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
 
      ret = -EPERM;
 
-     /* verify restrictions on target's new Inheritable set */
+     if (security_ops->capset_check(target, &effective, &inheritable, &permitted))
+            goto out;
+
      if (!cap_issubset(inheritable, cap_combine(target->cap_inheritable,
                        current->cap_permitted)))
              goto out;
@@ -182,6 +181,8 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
 
      ret = 0;
 
+     /* having verified that the proposed changes are legal,
+           we now put them into effect. */
      if (pid < 0) {
              if (pid == -1)  /* all procs other than current and init */
                      cap_set_all(&effective, &inheritable, &permitted);
@@ -189,9 +190,7 @@ asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
              else            /* all procs in process group */
                      cap_set_pg(-pid, &effective, &inheritable, &permitted);
      } else {
-             target->cap_effective   = effective;
-             target->cap_inheritable = inheritable;
-             target->cap_permitted   = permitted;
+            security_ops->capset_set(target, &effective, &inheritable, &permitted);
      }
 
 out:
index c47a4c045fea30667c696bb1652437b286cb6cfb..f727a3c511c8c395dfaf41aac11be1646e915b69 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/personality.h>
 #include <linux/tty.h>
 #include <linux/namespace.h>
+#include <linux/security.h>
 #include <linux/acct.h>
 #include <linux/file.h>
 #include <linux/binfmts.h>
@@ -61,6 +62,7 @@ static void release_task(struct task_struct * p)
        wait_task_inactive(p);
 #endif
        atomic_dec(&p->user->processes);
+       security_ops->task_free_security(p);
        free_uid(p->user);
        unhash_process(p);
 
@@ -187,10 +189,7 @@ void reparent_to_init(void)
        /* cpus_allowed? */
        /* rt_priority? */
        /* signals? */
-       current->cap_effective = CAP_INIT_EFF_SET;
-       current->cap_inheritable = CAP_INIT_INH_SET;
-       current->cap_permitted = CAP_FULL_SET;
-       current->keep_capabilities = 0;
+       security_ops->task_reparent_to_init(current);
        memcpy(current->rlim, init_task.rlim, sizeof(*(current->rlim)));
        current->user = INIT_USER;
 
@@ -625,6 +624,10 @@ repeat:
                        if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
                            && !(options & __WALL))
                                continue;
+
+                       if (security_ops->task_wait(p))
+                               continue;
+
                        flag = 1;
                        switch (p->state) {
                        case TASK_STOPPED:
index c0fb979902fe54bd1fac3fa8cd2223295b8a4925..f99f9e69521ae7bef0c02d0d6ca11066fb20be70 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/file.h>
 #include <linux/binfmts.h>
 #include <linux/fs.h>
-#include <linux/mm.h>
+#include <linux/security.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -618,6 +618,10 @@ struct task_struct *do_fork(unsigned long clone_flags,
        if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
                return ERR_PTR(-EINVAL);
 
+       retval = security_ops->task_create(clone_flags);
+       if (retval)
+               goto fork_out;
+
        retval = -ENOMEM;
        p = dup_task_struct(current);
        if (!p)
@@ -697,13 +701,16 @@ struct task_struct *do_fork(unsigned long clone_flags,
        p->array = NULL;
        p->lock_depth = -1;             /* -1 = no lock */
        p->start_time = jiffies;
+       p->security = NULL;
 
        INIT_LIST_HEAD(&p->local_pages);
 
        retval = -ENOMEM;
+       if (security_ops->task_alloc_security(p))
+               goto bad_fork_cleanup;
        /* copy all the process information */
        if (copy_semundo(clone_flags, p))
-               goto bad_fork_cleanup;
+               goto bad_fork_cleanup_security;
        if (copy_files(clone_flags, p))
                goto bad_fork_cleanup_semundo;
        if (copy_fs(clone_flags, p))
@@ -812,6 +819,8 @@ bad_fork_cleanup_files:
        exit_files(p); /* blocking */
 bad_fork_cleanup_semundo:
        exit_semundo(p);
+bad_fork_cleanup_security:
+       security_ops->task_free_security(p);
 bad_fork_cleanup:
        put_exec_domain(p->thread_info->exec_domain);
        if (p->binfmt && p->binfmt->module)
index 05388d9557fa2313f318c9cecf85bcb296f83733..c3b7e90aecdca6f4004e9f5082487ac7a4991a4c 100644 (file)
@@ -134,7 +134,7 @@ int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
        /* Give kmod all effective privileges.. */
        curtask->euid = curtask->fsuid = 0;
        curtask->egid = curtask->fsgid = 0;
-       cap_set_full(curtask->cap_effective);
+       security_ops->task_kmod_set_label();
 
        /* Allow execve args to be in kernel space. */
        set_fs(KERNEL_DS);
index 24d41164144e227ba488b3a5d745212e3b7dfa2e..1a64a0c03b95c0c6a7eb44b847b0af2ac0569ae6 100644 (file)
@@ -41,7 +41,9 @@ int ptrace_check_attach(struct task_struct *child, int kill)
 
 int ptrace_attach(struct task_struct *task)
 {
+       int retval;
        task_lock(task);
+       retval = -EPERM;
        if (task->pid <= 1)
                goto bad;
        if (task == current)
@@ -53,7 +55,6 @@ int ptrace_attach(struct task_struct *task)
            (current->uid != task->uid) ||
            (current->gid != task->egid) ||
            (current->gid != task->sgid) ||
-           (!cap_issubset(task->cap_permitted, current->cap_permitted)) ||
            (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE))
                goto bad;
        rmb();
@@ -62,6 +63,9 @@ int ptrace_attach(struct task_struct *task)
        /* the same process cannot be attached many times */
        if (task->ptrace & PT_PTRACED)
                goto bad;
+       retval = security_ops->ptrace(current, task);
+       if (retval)
+               goto bad;
 
        /* Go */
        task->ptrace |= PT_PTRACED;
@@ -82,7 +86,7 @@ int ptrace_attach(struct task_struct *task)
 
 bad:
        task_unlock(task);
-       return -EPERM;
+       return retval;
 }
 
 int ptrace_detach(struct task_struct *child, unsigned int data)
index 3b1d88b615218b6ad264e9428ed50964b2321b6e..c8a11b29794ec5be69245994e5062ad858664213 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/completion.h>
 #include <linux/kernel_stat.h>
+#include <linux/security.h>
 
 /*
  * Convert user-nice values [ -20 ... 0 ... 19 ]
@@ -1123,6 +1124,7 @@ out_unlock:
 
 asmlinkage long sys_nice(int increment)
 {
+       int retval;
        long nice;
 
        /*
@@ -1144,6 +1146,11 @@ asmlinkage long sys_nice(int increment)
                nice = -20;
        if (nice > 19)
                nice = 19;
+
+       retval = security_ops->task_setnice(current, nice);
+       if (retval)
+               return retval;
+
        set_user_nice(current, nice);
        return 0;
 }
@@ -1236,6 +1243,10 @@ static int setscheduler(pid_t pid, int policy, struct sched_param *param)
            !capable(CAP_SYS_NICE))
                goto out_unlock;
 
+       retval = security_ops->task_setscheduler(p, policy, &lp);
+       if (retval)
+               goto out_unlock;
+
        array = p->array;
        if (array)
                deactivate_task(p, task_rq(p));
@@ -1280,8 +1291,11 @@ asmlinkage long sys_sched_getscheduler(pid_t pid)
        retval = -ESRCH;
        read_lock(&tasklist_lock);
        p = find_process_by_pid(pid);
-       if (p)
-               retval = p->policy;
+       if (p) {
+               retval = security_ops->task_getscheduler(p);
+               if (!retval)
+                       retval = p->policy;
+       }
        read_unlock(&tasklist_lock);
 
 out_nounlock:
@@ -1302,6 +1316,11 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param)
        retval = -ESRCH;
        if (!p)
                goto out_unlock;
+
+       retval = security_ops->task_getscheduler(p);
+       if (retval)
+               goto out_unlock;
+
        lp.sched_priority = p->rt_priority;
        read_unlock(&tasklist_lock);
 
@@ -1509,14 +1528,22 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
        retval = -ESRCH;
        read_lock(&tasklist_lock);
        p = find_process_by_pid(pid);
-       if (p)
-               jiffies_to_timespec(p->policy & SCHED_FIFO ?
-                                        0 : TASK_TIMESLICE(p), &t);
+       if (!p)
+               goto out_unlock;
+
+       retval = security_ops->task_getscheduler(p);
+       if (retval)
+               goto out_unlock;
+
+       jiffies_to_timespec(p->policy & SCHED_FIFO ?
+                               0 : TASK_TIMESLICE(p), &t);
        read_unlock(&tasklist_lock);
-       if (p)
-               retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
+       retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0;
 out_nounlock:
        return retval;
+out_unlock:
+       read_unlock(&tasklist_lock);
+       return retval;
 }
 
 static void show_task(task_t * p)
index c08c89e9a62cc533e8475b8d0e3f6a4371fca023..90ae5af97bf7d23711bf4c8f8e5b49056779fbd5 100644 (file)
@@ -548,6 +548,9 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
        ret = -EPERM;
        if (bad_signal(sig, info, t))
                goto out_nolock;
+       ret = security_ops->task_kill(t, info, sig);
+       if (ret)
+               goto out_nolock;
 
        /* The null signal is a permissions and process existence probe.
           No signal is actually delivered.  Same goes for zombies. */
index 2559bef8ed0971f414eaeb12ecf2260b5318dec6..37a9525b3f1db850590219532d6dcbbc4dc428e9 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/tqueue.h>
 #include <linux/device.h>
 #include <linux/times.h>
+#include <linux/security.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -234,6 +235,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
 
        read_lock(&tasklist_lock);
        for_each_task(p) {
+               int no_nice;
                if (!proc_sel(p, which, who))
                        continue;
                if (p->uid != current->euid &&
@@ -243,10 +245,17 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
                }
                if (error == -ESRCH)
                        error = 0;
-               if (niceval < task_nice(p) && !capable(CAP_SYS_NICE))
+               if (niceval < task_nice(p) && !capable(CAP_SYS_NICE)) {
                        error = -EACCES;
-               else
-                       set_user_nice(p, niceval);
+                       continue;
+               }
+               no_nice = security_ops->task_setnice(p, niceval);
+               if (no_nice) {
+                       error = no_nice;
+                       continue;
+               }
+               set_user_nice(p, niceval);
+
        }
        read_unlock(&tasklist_lock);
 
@@ -416,6 +425,11 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
        int old_egid = current->egid;
        int new_rgid = old_rgid;
        int new_egid = old_egid;
+       int retval;
+
+       retval = security_ops->task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE);
+       if (retval)
+               return retval;
 
        if (rgid != (gid_t) -1) {
                if ((old_rgid == rgid) ||
@@ -457,6 +471,11 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
 asmlinkage long sys_setgid(gid_t gid)
 {
        int old_egid = current->egid;
+       int retval;
+
+       retval = security_ops->task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID);
+       if (retval)
+               return retval;
 
        if (capable(CAP_SETGID))
        {
@@ -481,52 +500,6 @@ asmlinkage long sys_setgid(gid_t gid)
        return 0;
 }
   
-/* 
- * cap_emulate_setxuid() fixes the effective / permitted capabilities of
- * a process after a call to setuid, setreuid, or setresuid.
- *
- *  1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of
- *  {r,e,s}uid != 0, the permitted and effective capabilities are
- *  cleared.
- *
- *  2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective
- *  capabilities of the process are cleared.
- *
- *  3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective
- *  capabilities are set to the permitted capabilities.
- *
- *  fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should 
- *  never happen.
- *
- *  -astor 
- *
- * cevans - New behaviour, Oct '99
- * A process may, via prctl(), elect to keep its capabilities when it
- * calls setuid() and switches away from uid==0. Both permitted and
- * effective sets will be retained.
- * Without this change, it was impossible for a daemon to drop only some
- * of its privilege. The call to setuid(!=0) would drop all privileges!
- * Keeping uid 0 is not an option because uid 0 owns too many vital
- * files..
- * Thanks to Olaf Kirch and Peter Benie for spotting this.
- */
-static inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
-                                      int old_suid)
-{
-       if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
-           (current->uid != 0 && current->euid != 0 && current->suid != 0) &&
-           !current->keep_capabilities) {
-               cap_clear(current->cap_permitted);
-               cap_clear(current->cap_effective);
-       }
-       if (old_euid == 0 && current->euid != 0) {
-               cap_clear(current->cap_effective);
-       }
-       if (old_euid != 0 && current->euid == 0) {
-               current->cap_effective = current->cap_permitted;
-       }
-}
-
 static int set_user(uid_t new_ruid, int dumpclear)
 {
        struct user_struct *new_user, *old_user;
@@ -572,6 +545,11 @@ static int set_user(uid_t new_ruid, int dumpclear)
 asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
 {
        int old_ruid, old_euid, old_suid, new_ruid, new_euid;
+       int retval;
+
+       retval = security_ops->task_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;
@@ -608,11 +586,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
                current->suid = current->euid;
        current->fsuid = current->euid;
 
-       if (!issecure(SECURE_NO_SETUID_FIXUP)) {
-               cap_emulate_setxuid(old_ruid, old_euid, old_suid);
-       }
-
-       return 0;
+       return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
 }
 
 
@@ -632,6 +606,11 @@ asmlinkage long sys_setuid(uid_t uid)
 {
        int old_euid = current->euid;
        int old_ruid, old_suid, new_ruid, new_suid;
+       int retval;
+
+       retval = security_ops->task_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;
@@ -652,11 +631,7 @@ asmlinkage long sys_setuid(uid_t uid)
        current->fsuid = current->euid = uid;
        current->suid = new_suid;
 
-       if (!issecure(SECURE_NO_SETUID_FIXUP)) {
-               cap_emulate_setxuid(old_ruid, old_euid, old_suid);
-       }
-
-       return 0;
+       return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
 }
 
 
@@ -669,6 +644,11 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
        int old_ruid = current->uid;
        int old_euid = current->euid;
        int old_suid = current->suid;
+       int retval;
+
+       retval = security_ops->task_setuid(ruid, euid, suid, LSM_SETID_RES);
+       if (retval)
+               return retval;
 
        if (!capable(CAP_SETUID)) {
                if ((ruid != (uid_t) -1) && (ruid != current->uid) &&
@@ -697,11 +677,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
        if (suid != (uid_t) -1)
                current->suid = suid;
 
-       if (!issecure(SECURE_NO_SETUID_FIXUP)) {
-               cap_emulate_setxuid(old_ruid, old_euid, old_suid);
-       }
-
-       return 0;
+       return security_ops->task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
 }
 
 asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
@@ -720,6 +696,12 @@ asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
  */
 asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
 {
+       int retval;
+
+       retval = security_ops->task_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))
@@ -768,6 +750,11 @@ asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid)
 asmlinkage long sys_setfsuid(uid_t uid)
 {
        int old_fsuid;
+       int retval;
+
+       retval = security_ops->task_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 ||
@@ -782,24 +769,9 @@ asmlinkage long sys_setfsuid(uid_t uid)
                current->fsuid = uid;
        }
 
-       /* We emulate fsuid by essentially doing a scaled-down version
-        * of what we did in setresuid and friends. However, we only
-        * operate on the fs-specific bits of the process' effective
-        * capabilities 
-        *
-        * FIXME - is fsuser used for all CAP_FS_MASK capabilities?
-        *          if not, we might be a bit too harsh here.
-        */
-       
-       if (!issecure(SECURE_NO_SETUID_FIXUP)) {
-               if (old_fsuid == 0 && current->fsuid != 0) {
-                       cap_t(current->cap_effective) &= ~CAP_FS_MASK;
-               }
-               if (old_fsuid != 0 && current->fsuid == 0) {
-                       cap_t(current->cap_effective) |=
-                               (cap_t(current->cap_permitted) & CAP_FS_MASK);
-               }
-       }
+       retval = security_ops->task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
+       if (retval)
+               return retval;
 
        return old_fsuid;
 }
@@ -810,6 +782,11 @@ asmlinkage long sys_setfsuid(uid_t uid)
 asmlinkage long sys_setfsgid(gid_t gid)
 {
        int old_fsgid;
+       int retval;
+
+       retval = security_ops->task_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 ||
@@ -904,6 +881,10 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
        }
 
 ok_pgid:
+       err = security_ops->task_setpgid(p, pgid);
+       if (err)
+               goto out;
+
        p->pgrp = pgid;
        err = 0;
 out:
@@ -924,8 +905,11 @@ asmlinkage long sys_getpgid(pid_t pid)
                p = find_task_by_pid(pid);
 
                retval = -ESRCH;
-               if (p)
-                       retval = p->pgrp;
+               if (p) {
+                       retval = security_ops->task_getpgid(p);
+                       if (!retval)
+                               retval = p->pgrp;
+               }
                read_unlock(&tasklist_lock);
                return retval;
        }
@@ -949,8 +933,11 @@ asmlinkage long sys_getsid(pid_t pid)
                p = find_task_by_pid(pid);
 
                retval = -ESRCH;
-               if(p)
-                       retval = p->session;
+               if(p) {
+                       retval = security_ops->task_getsid(p);
+                       if (!retval)
+                               retval = p->session;
+               }
                read_unlock(&tasklist_lock);
                return retval;
        }
@@ -1008,12 +995,19 @@ asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist)
  
 asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist)
 {
+       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_setgroups(gidsetsize, groups);
+       if (retval)
+               return retval;
+       memcpy(current->groups, groups, gidsetsize * sizeof(gid_t));
        current->ngroups = gidsetsize;
        return 0;
 }
@@ -1158,6 +1152,7 @@ asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim)
 asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim)
 {
        struct rlimit new_rlim, *old_rlim;
+       int retval;
 
        if (resource >= RLIM_NLIMITS)
                return -EINVAL;
@@ -1172,6 +1167,11 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim)
                if (new_rlim.rlim_cur > NR_OPEN || new_rlim.rlim_max > NR_OPEN)
                        return -EPERM;
        }
+
+       retval = security_ops->task_setrlimit(resource, &new_rlim);
+       if (retval)
+               return retval;
+
        *old_rlim = new_rlim;
        return 0;
 }
@@ -1243,6 +1243,10 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
        int error = 0;
        int sig;
 
+       error = security_ops->task_prctl(option, arg2, arg3, arg4, arg5);
+       if (error)
+               return error;
+
        switch (option) {
                case PR_SET_PDEATHSIG:
                        sig = arg2;
index f76e4fd706e576caa7651447f90b1336fb581a5e..63b24096f8c346d95519be65a352e11d4edc0580 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/prctl.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
+#include <linux/security.h>
 
 #include <asm/uaccess.h>
 
@@ -128,6 +129,7 @@ asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t *grouplist)
 asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t *grouplist)
 {
        old_gid_t groups[NGROUPS];
+       gid_t new_groups[NGROUPS];
        int i;
 
        if (!capable(CAP_SETGID))
@@ -137,7 +139,11 @@ asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t *grouplist)
        if (copy_from_user(groups, grouplist, gidsetsize * sizeof(old_gid_t)))
                return -EFAULT;
        for (i = 0 ; i < gidsetsize ; i++)
-               current->groups[i] = (gid_t)groups[i];
+               new_groups[i] = (gid_t)groups[i];
+       i = security_ops->task_setgroups(gidsetsize, new_groups);
+       if (i)
+               return i;
+       memcpy(current->groups, new_groups, gidsetsize * sizeof(gid_t));
        current->ngroups = gidsetsize;
        return 0;
 }