]> git.hungrycats.org Git - linux/commitdiff
LSM: Add all of the new security/* files for basic task control
authorGreg Kroah-Hartman <greg@kroah.com>
Fri, 19 Jul 2002 08:55:59 +0000 (01:55 -0700)
committerGreg Kroah-Hartman <greg@kroah.com>
Fri, 19 Jul 2002 08:55:59 +0000 (01:55 -0700)
This includes the security_* functions, and the default and capability
modules.

include/linux/security.h [new file with mode: 0644]
security/Config.help [new file with mode: 0644]
security/Config.in [new file with mode: 0644]
security/Makefile [new file with mode: 0644]
security/capability.c [new file with mode: 0644]
security/dummy.c [new file with mode: 0644]
security/security.c [new file with mode: 0644]

diff --git a/include/linux/security.h b/include/linux/security.h
new file mode 100644 (file)
index 0000000..3063323
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Linux Security plug
+ *
+ * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com>
+ * Copyright (C) 2001 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com>
+ * Copyright (C) 2001 James Morris <jmorris@intercode.com.au>
+ * Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group)
+ *
+ *     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.
+ *
+ *     Due to this file being licensed under the GPL there is controversy over
+ *     whether this permits you to write a module that #includes this file
+ *     without placing your module under the GPL.  Please consult a lawyer for
+ *     advice before doing this.
+ *
+ */
+
+#ifndef __LINUX_SECURITY_H
+#define __LINUX_SECURITY_H
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+#include <linux/binfmts.h>
+#include <linux/signal.h>
+#include <linux/resource.h>
+#include <linux/sem.h>
+#include <linux/sysctl.h>
+#include <linux/shm.h>
+#include <linux/msg.h>
+
+/*
+ * Values used in the task_security_ops calls
+ */
+/* setuid or setgid, id0 == uid or gid */
+#define LSM_SETID_ID   1
+
+/* setreuid or setregid, id0 == real, id1 == eff */
+#define LSM_SETID_RE   2
+
+/* setresuid or setresgid, id0 == real, id1 == eff, uid2 == saved */
+#define LSM_SETID_RES  4
+
+/* setfsuid or setfsgid, id0 == fsuid or fsgid */
+#define LSM_SETID_FS   8
+
+/* forward declares to avoid warnings */
+struct sk_buff;
+struct net_device;
+struct nfsctl_arg;
+struct sched_param;
+struct swap_info_struct;
+
+/**
+ * struct security_operations - main security structure
+ *
+ * Security hooks for program execution operations.
+ *
+ * @bprm_alloc_security:
+ *     Allocate and attach a security structure to the @bprm->security field.
+ *     The security field is initialized to NULL when the bprm structure is
+ *     allocated.
+ *     @bprm contains the linux_binprm structure to be modified.
+ *     Return 0 if operation was successful.
+ * @bprm_free_security:
+ *     @bprm contains the linux_binprm structure to be modified.
+ *     Deallocate and clear the @bprm->security field.
+ * @bprm_compute_creds:
+ *     Compute and set the security attributes of a process being transformed
+ *     by an execve operation based on the old attributes (current->security)
+ *     and the information saved in @bprm->security by the set_security hook.
+ *     Since this hook function (and its caller) are void, this hook can not
+ *     return an error.  However, it can leave the security attributes of the
+ *     process unchanged if an access failure occurs at this point. It can
+ *     also perform other state changes on the process (e.g.  closing open
+ *     file descriptors to which access is no longer granted if the attributes
+ *     were changed). 
+ *     @bprm contains the linux_binprm structure.
+ * @bprm_set_security:
+ *     Save security information in the bprm->security field, typically based
+ *     on information about the bprm->file, for later use by the compute_creds
+ *     hook.  This hook may also optionally check permissions (e.g. for
+ *     transitions between security domains).
+ *     This hook may be called multiple times during a single execve, e.g. for
+ *     interpreters.  The hook can tell whether it has already been called by
+ *     checking to see if @bprm->security is non-NULL.  If so, then the hook
+ *     may decide either to retain the security information saved earlier or
+ *     to replace it.
+ *     @bprm contains the linux_binprm structure.
+ *     Return 0 if the hook is successful and permission is granted.
+ * @bprm_check_security:
+ *     This hook mediates the point when a search for a binary handler will
+ *     begin.  It allows a check the @bprm->security value which is set in
+ *     the preceding set_security call.  The primary difference from
+ *     set_security is that the argv list and envp list are reliably
+ *     available in @bprm.  This hook may be called multiple times
+ *     during a single execve; and in each pass set_security is called
+ *     first.
+ *     @bprm contains the linux_binprm structure.
+ *     Return 0 if the hook is successful and permission is granted.
+ *
+ * Security hooks for task operations.
+ *
+ * @task_create:
+ *     Check permission before creating a child process.  See the clone(2)
+ *     manual page for definitions of the @clone_flags.
+ *     @clone_flags contains the flags indicating what should be shared.
+ *     Return 0 if permission is granted.
+ * @task_alloc_security:
+ *     @p contains the task_struct for child process.
+ *     Allocate and attach a security structure to the p->security field. The
+ *     security field is initialized to NULL when the task structure is
+ *     allocated.
+ *     Return 0 if operation was successful.
+ * @task_free_security:
+ *     @p contains the task_struct for process.
+ *     Deallocate and clear the p->security field.
+ * @task_setuid:
+ *     Check permission before setting one or more of the user identity
+ *     attributes of the current process.  The @flags parameter indicates
+ *     which of the set*uid system calls invoked this hook and how to
+ *     interpret the @id0, @id1, and @id2 parameters.  See the LSM_SETID
+ *     definitions at the beginning of this file for the @flags values and
+ *     their meanings.
+ *     @id0 contains a uid.
+ *     @id1 contains a uid.
+ *     @id2 contains a uid.
+ *     @flags contains one of the LSM_SETID_* values.
+ *     Return 0 if permission is granted.
+ * @task_post_setuid:
+ *     Update the module's state after setting one or more of the user
+ *     identity attributes of the current process.  The @flags parameter
+ *     indicates which of the set*uid system calls invoked this hook.  If
+ *     @flags is LSM_SETID_FS, then @old_ruid is the old fs uid and the other
+ *     parameters are not used.
+ *     @old_ruid contains the old real uid (or fs uid if LSM_SETID_FS).
+ *     @old_euid contains the old effective uid (or -1 if LSM_SETID_FS).
+ *     @old_suid contains the old saved uid (or -1 if LSM_SETID_FS).
+ *     @flags contains one of the LSM_SETID_* values.
+ *     Return 0 on success.
+ * @task_setgid:
+ *     Check permission before setting one or more of the group identity
+ *     attributes of the current process.  The @flags parameter indicates
+ *     which of the set*gid system calls invoked this hook and how to
+ *     interpret the @id0, @id1, and @id2 parameters.  See the LSM_SETID
+ *     definitions at the beginning of this file for the @flags values and
+ *     their meanings.
+ *     @id0 contains a gid.
+ *     @id1 contains a gid.
+ *     @id2 contains a gid.
+ *     @flags contains one of the LSM_SETID_* values.
+ *     Return 0 if permission is granted.
+ * @task_setpgid:
+ *     Check permission before setting the process group identifier of the
+ *     process @p to @pgid.
+ *     @p contains the task_struct for process being modified.
+ *     @pgid contains the new pgid.
+ *     Return 0 if permission is granted.
+ * @task_getpgid:
+ *     Check permission before getting the process group identifier of the
+ *     process @p.
+ *     @p contains the task_struct for the process.
+ *     Return 0 if permission is granted.
+ * @task_getsid:
+ *     Check permission before getting the session identifier of the process
+ *     @p.
+ *     @p contains the task_struct for the process.
+ *     Return 0 if permission is granted.
+ * @task_setgroups:
+ *     Check permission before setting the supplementary group set of the
+ *     current process to @grouplist.
+ *     @gidsetsize contains the number of elements in @grouplist.
+ *     @grouplist contains the array of gids.
+ *     Return 0 if permission is granted.
+ * @task_setnice:
+ *     Check permission before setting the nice value of @p to @nice.
+ *     @p contains the task_struct of process.
+ *     @nice contains the new nice value.
+ *     Return 0 if permission is granted.
+ * @task_setrlimit:
+ *     Check permission before setting the resource limits of the current
+ *     process for @resource to @new_rlim.  The old resource limit values can
+ *     be examined by dereferencing (current->rlim + resource).
+ *     @resource contains the resource whose limit is being set.
+ *     @new_rlim contains the new limits for @resource.
+ *     Return 0 if permission is granted.
+ * @task_setscheduler:
+ *     Check permission before setting scheduling policy and/or parameters of
+ *     process @p based on @policy and @lp.
+ *     @p contains the task_struct for process.
+ *     @policy contains the scheduling policy.
+ *     @lp contains the scheduling parameters.
+ *     Return 0 if permission is granted.
+ * @task_getscheduler:
+ *     Check permission before obtaining scheduling information for process
+ *     @p.
+ *     @p contains the task_struct for process.
+ *     Return 0 if permission is granted.
+ * @task_kill:
+ *     Check permission before sending signal @sig to @p.  @info can be NULL,
+ *     the constant 1, or a pointer to a siginfo structure.  If @info is 1 or
+ *     SI_FROMKERNEL(info) is true, then the signal should be viewed as coming
+ *     from the kernel and should typically be permitted.
+ *     SIGIO signals are handled separately by the send_sigiotask hook in
+ *     file_security_ops.
+ *     @p contains the task_struct for process.
+ *     @info contains the signal information.
+ *     @sig contains the signal value.
+ *     Return 0 if permission is granted.
+ * @task_wait:
+ *     Check permission before allowing a process to reap a child process @p
+ *     and collect its status information.
+ *     @p contains the task_struct for process.
+ *     Return 0 if permission is granted.
+ * @task_prctl:
+ *     Check permission before performing a process control operation on the
+ *     current process.
+ *     @option contains the operation.
+ *     @arg2 contains a argument.
+ *     @arg3 contains a argument.
+ *     @arg4 contains a argument.
+ *     @arg5 contains a argument.
+ *     Return 0 if permission is granted.
+ * @task_kmod_set_label:
+ *     Set the security attributes in current->security for the kernel module
+ *     loader thread, so that it has the permissions needed to perform its
+ *     function.
+ * @task_reparent_to_init:
+ *     Set the security attributes in @p->security for a kernel thread that
+ *     is being reparented to the init task.
+ *     @p contains the task_struct for the kernel thread.
+ *
+ * @ptrace:
+ *     Check permission before allowing the @parent process to trace the
+ *     @child process.
+ *     Security modules may also want to perform a process tracing check
+ *     during an execve in the set_security or compute_creds hooks of
+ *     binprm_security_ops if the process is being traced and its security
+ *     attributes would be changed by the execve.
+ *     @parent contains the task_struct structure for parent process.
+ *     @child contains the task_struct structure for child process.
+ *     Return 0 if permission is granted.
+ * @capget:
+ *     Get the @effective, @inheritable, and @permitted capability sets for
+ *     the @target process.  The hook may also perform permission checking to
+ *     determine if the current process is allowed to see the capability sets
+ *     of the @target process.
+ *     @target contains the task_struct structure for target process.
+ *     @effective contains the effective capability set.
+ *     @inheritable contains the inheritable capability set.
+ *     @permitted contains the permitted capability set.
+ *     Return 0 if the capability sets were successfully obtained.
+ * @capset_check:
+ *     Check permission before setting the @effective, @inheritable, and
+ *     @permitted capability sets for the @target process.
+ *     Caveat:  @target is also set to current if a set of processes is
+ *     specified (i.e. all processes other than current and init or a
+ *     particular process group).  Hence, the capset_set hook may need to
+ *     revalidate permission to the actual target process.
+ *     @target contains the task_struct structure for target process.
+ *     @effective contains the effective capability set.
+ *     @inheritable contains the inheritable capability set.
+ *     @permitted contains the permitted capability set.
+ *     Return 0 if permission is granted.
+ * @capset_set:
+ *     Set the @effective, @inheritable, and @permitted capability sets for
+ *     the @target process.  Since capset_check cannot always check permission
+ *     to the real @target process, this hook may also perform permission
+ *     checking to determine if the current process is allowed to set the
+ *     capability sets of the @target process.  However, this hook has no way
+ *     of returning an error due to the structure of the sys_capset code.
+ *     @target contains the task_struct structure for target process.
+ *     @effective contains the effective capability set.
+ *     @inheritable contains the inheritable capability set.
+ *     @permitted contains the permitted capability set.
+ * @capable:
+ *     Check whether the @tsk process has the @cap capability.
+ *     @tsk contains the task_struct for the process.
+ *     @cap contains the capability <include/linux/capability.h>.
+ *     Return 0 if the capability is granted for @tsk.
+ * @sys_security:
+ *     Security modules may use this hook to implement new system calls for
+ *     security-aware applications.  The interface is similar to socketcall,
+ *     but with an @id parameter to help identify the security module whose
+ *     call is being invoked.  The module is responsible for interpreting the
+ *     parameters, and must copy in the @args array from user space if it is
+ *     used.
+ *     The recommended convention for creating the hexadecimal @id value is
+ *     echo "Name_of_module" | md5sum | cut -c -8; by using this convention,
+ *     there is no need for a central registry.
+ *     @id contains the security module identifier.
+ *     @call contains the call value.
+ *     @args contains the call arguments (user space pointer).
+ *     The module should return -ENOSYS if it does not implement any new
+ *     system calls.
+ *
+ * @register_security:
+ *     allow module stacking.
+ *     @name contains the name of the security module being stacked.
+ *     @ops contains a pointer to the struct security_operations of the module to stack.
+ * @unregister_security:
+ *     remove a stacked module.
+ *     @name contains the name of the security module being unstacked.
+ *     @ops contains a pointer to the struct security_operations of the module to unstack.
+ * 
+ * This is the main security structure.
+ */
+struct security_operations {
+       int (*ptrace) (struct task_struct * parent, struct task_struct * child);
+       int (*capget) (struct task_struct * target,
+                      kernel_cap_t * effective,
+                      kernel_cap_t * inheritable, kernel_cap_t * permitted);
+       int (*capset_check) (struct task_struct * target,
+                            kernel_cap_t * effective,
+                            kernel_cap_t * inheritable,
+                            kernel_cap_t * permitted);
+       void (*capset_set) (struct task_struct * target,
+                           kernel_cap_t * effective,
+                           kernel_cap_t * inheritable,
+                           kernel_cap_t * permitted);
+       int (*capable) (struct task_struct * tsk, int cap);
+       int (*sys_security) (unsigned int id, unsigned call,
+                            unsigned long *args);
+
+       int (*bprm_alloc_security) (struct linux_binprm * bprm);
+       void (*bprm_free_security) (struct linux_binprm * bprm);
+       void (*bprm_compute_creds) (struct linux_binprm * bprm);
+       int (*bprm_set_security) (struct linux_binprm * bprm);
+       int (*bprm_check_security) (struct linux_binprm * bprm);
+
+       int (*task_create) (unsigned long clone_flags);
+       int (*task_alloc_security) (struct task_struct * p);
+       void (*task_free_security) (struct task_struct * p);
+       int (*task_setuid) (uid_t id0, uid_t id1, uid_t id2, int flags);
+       int (*task_post_setuid) (uid_t old_ruid /* or fsuid */ ,
+                                uid_t old_euid, uid_t old_suid, int flags);
+       int (*task_setgid) (gid_t id0, gid_t id1, gid_t id2, int flags);
+       int (*task_setpgid) (struct task_struct * p, pid_t pgid);
+       int (*task_getpgid) (struct task_struct * p);
+       int (*task_getsid) (struct task_struct * p);
+       int (*task_setgroups) (int gidsetsize, gid_t * grouplist);
+       int (*task_setnice) (struct task_struct * p, int nice);
+       int (*task_setrlimit) (unsigned int resource, struct rlimit * new_rlim);
+       int (*task_setscheduler) (struct task_struct * p, int policy,
+                                 struct sched_param * lp);
+       int (*task_getscheduler) (struct task_struct * p);
+       int (*task_kill) (struct task_struct * p,
+                         struct siginfo * info, int sig);
+       int (*task_wait) (struct task_struct * p);
+       int (*task_prctl) (int option, unsigned long arg2,
+                          unsigned long arg3, unsigned long arg4,
+                          unsigned long arg5);
+       void (*task_kmod_set_label) (void);
+       void (*task_reparent_to_init) (struct task_struct * p);
+
+       /* allow module stacking */
+       int (*register_security) (const char *name,
+                                 struct security_operations *ops);
+       int (*unregister_security) (const char *name,
+                                   struct security_operations *ops);
+};
+
+
+/* prototypes */
+extern int security_scaffolding_startup        (void);
+extern int register_security   (struct security_operations *ops);
+extern int unregister_security (struct security_operations *ops);
+extern int mod_reg_security    (const char *name, struct security_operations *ops);
+extern int mod_unreg_security  (const char *name, struct security_operations *ops);
+extern int capable             (int cap);
+
+/* global variables */
+extern struct security_operations *security_ops;
+
+
+#endif /* __KERNEL__ */
+
+#endif /* ! __LINUX_SECURITY_H */
+
diff --git a/security/Config.help b/security/Config.help
new file mode 100644 (file)
index 0000000..e2934a0
--- /dev/null
@@ -0,0 +1,4 @@
+CONFIG_SECURITY_CAPABILITIES
+  This enables the "default" Linux capabilities functionality.
+  If you are unsure how to answer this question, answer Y.
+
diff --git a/security/Config.in b/security/Config.in
new file mode 100644 (file)
index 0000000..77379ce
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Security configuration
+#
+mainmenu_option next_comment
+comment 'Security options'
+tristate 'Capabilities Support' CONFIG_SECURITY_CAPABILITIES
+endmenu
diff --git a/security/Makefile b/security/Makefile
new file mode 100644 (file)
index 0000000..9349c30
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Makefile for the kernel security code
+#
+
+# Objects that export symbols
+export-objs    := security.o
+
+# Object file lists
+obj-y          := security.o dummy.o
+
+obj-$(CONFIG_SECURITY_CAPABILITIES)    += capability.o
+
+include $(TOPDIR)/Rules.make
diff --git a/security/capability.c b/security/capability.c
new file mode 100644 (file)
index 0000000..d5b7c5c
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ *  Capabilities Linux Security Module
+ *
+ *     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/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+
+/* flag to keep track of how we were registered */
+static int secondary;
+
+static int cap_capable (struct task_struct *tsk, int cap)
+{
+       /* Derived from include/linux/sched.h:capable. */
+       if (cap_raised (tsk->cap_effective, cap))
+               return 0;
+       else
+               return -EPERM;
+}
+
+static int cap_sys_security (unsigned int id, unsigned int call,
+                            unsigned long *args)
+{
+       return -ENOSYS;
+}
+
+static int cap_ptrace (struct task_struct *parent, struct task_struct *child)
+{
+       /* Derived from arch/i386/kernel/ptrace.c:sys_ptrace. */
+       if (!cap_issubset (child->cap_permitted, current->cap_permitted) &&
+           !capable (CAP_SYS_PTRACE))
+               return -EPERM;
+       else
+               return 0;
+}
+
+static int cap_capget (struct task_struct *target, kernel_cap_t * effective,
+                      kernel_cap_t * inheritable, kernel_cap_t * permitted)
+{
+       /* Derived from kernel/capability.c:sys_capget. */
+       *effective = cap_t (target->cap_effective);
+       *inheritable = cap_t (target->cap_inheritable);
+       *permitted = cap_t (target->cap_permitted);
+       return 0;
+}
+
+static int cap_capset_check (struct task_struct *target,
+                            kernel_cap_t * effective,
+                            kernel_cap_t * inheritable,
+                            kernel_cap_t * permitted)
+{
+       /* Derived from kernel/capability.c:sys_capset. */
+       /* verify restrictions on target's new Inheritable set */
+       if (!cap_issubset (*inheritable,
+                          cap_combine (target->cap_inheritable,
+                                       current->cap_permitted))) {
+               return -EPERM;
+       }
+
+       /* verify restrictions on target's new Permitted set */
+       if (!cap_issubset (*permitted,
+                          cap_combine (target->cap_permitted,
+                                       current->cap_permitted))) {
+               return -EPERM;
+       }
+
+       /* verify the _new_Effective_ is a subset of the _new_Permitted_ */
+       if (!cap_issubset (*effective, *permitted)) {
+               return -EPERM;
+       }
+
+       return 0;
+}
+
+static void cap_capset_set (struct task_struct *target,
+                           kernel_cap_t * effective,
+                           kernel_cap_t * inheritable,
+                           kernel_cap_t * permitted)
+{
+       target->cap_effective = *effective;
+       target->cap_inheritable = *inheritable;
+       target->cap_permitted = *permitted;
+}
+
+static int cap_bprm_alloc_security (struct linux_binprm *bprm)
+{
+       return 0;
+}
+
+static int cap_bprm_set_security (struct linux_binprm *bprm)
+{
+       /* Copied from fs/exec.c:prepare_binprm. */
+
+       /* 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);
+       }
+       return 0;
+}
+
+static int cap_bprm_check_security (struct linux_binprm *bprm)
+{
+       return 0;
+}
+
+static void cap_bprm_free_security (struct linux_binprm *bprm)
+{
+       return;
+}
+
+/* Copied from fs/exec.c */
+static inline int must_not_trace_exec (struct task_struct *p)
+{
+       return (p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP);
+}
+
+static void cap_bprm_compute_creds (struct linux_binprm *bprm)
+{
+       /* Derived from fs/exec.c:compute_creds. */
+       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 (!cap_issubset (new_permitted, current->cap_permitted)) {
+               current->mm->dumpable = 0;
+
+               lock_kernel ();
+               if (must_not_trace_exec (current)
+                   || atomic_read (&current->fs->count) > 1
+                   || atomic_read (&current->files->count) > 1
+                   || atomic_read (&current->sig->count) > 1) {
+                       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 */
+
+       if (do_unlock)
+               unlock_kernel ();
+
+       current->keep_capabilities = 0;
+}
+
+static int cap_task_create (unsigned long clone_flags)
+{
+       return 0;
+}
+
+static int cap_task_alloc_security (struct task_struct *p)
+{
+       return 0;
+}
+
+static void cap_task_free_security (struct task_struct *p)
+{
+       return;
+}
+
+static int cap_task_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
+{
+       return 0;
+}
+
+/* moved from kernel/sys.c. */
+/* 
+ * 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 cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid,
+                                int flags)
+{
+       switch (flags) {
+       case LSM_SETID_RE:
+       case LSM_SETID_ID:
+       case LSM_SETID_RES:
+               /* Copied from kernel/sys.c:setreuid/setuid/setresuid. */
+               if (!issecure (SECURE_NO_SETUID_FIXUP)) {
+                       cap_emulate_setxuid (old_ruid, old_euid, old_suid);
+               }
+               break;
+       case LSM_SETID_FS:
+               {
+                       uid_t old_fsuid = old_ruid;
+
+                       /* Copied from kernel/sys.c:setfsuid. */
+
+                       /*
+                        * 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);
+                               }
+                       }
+                       break;
+               }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cap_task_setgid (gid_t id0, gid_t id1, gid_t id2, int flags)
+{
+       return 0;
+}
+
+static int cap_task_setpgid (struct task_struct *p, pid_t pgid)
+{
+       return 0;
+}
+
+static int cap_task_getpgid (struct task_struct *p)
+{
+       return 0;
+}
+
+static int cap_task_getsid (struct task_struct *p)
+{
+       return 0;
+}
+
+static int cap_task_setgroups (int gidsetsize, gid_t * grouplist)
+{
+       return 0;
+}
+
+static int cap_task_setnice (struct task_struct *p, int nice)
+{
+       return 0;
+}
+
+static int cap_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
+{
+       return 0;
+}
+
+static int cap_task_setscheduler (struct task_struct *p, int policy,
+                                 struct sched_param *lp)
+{
+       return 0;
+}
+
+static int cap_task_getscheduler (struct task_struct *p)
+{
+       return 0;
+}
+
+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 0;
+}
+
+static int cap_task_prctl (int option, unsigned long arg2, unsigned long arg3,
+                          unsigned long arg4, unsigned long arg5)
+{
+       return 0;
+}
+
+static void cap_task_kmod_set_label (void)
+{
+       cap_set_full (current->cap_effective);
+       return;
+}
+
+static void cap_task_reparent_to_init (struct task_struct *p)
+{
+       p->cap_effective = CAP_INIT_EFF_SET;
+       p->cap_inheritable = CAP_INIT_INH_SET;
+       p->cap_permitted = CAP_FULL_SET;
+       p->keep_capabilities = 0;
+       return;
+}
+
+static int cap_register (const char *name, struct security_operations *ops)
+{
+       return -EINVAL;
+}
+
+static int cap_unregister (const char *name, struct security_operations *ops)
+{
+       return -EINVAL;
+}
+
+static struct security_operations capability_ops = {
+       ptrace:                         cap_ptrace,
+       capget:                         cap_capget,
+       capset_check:                   cap_capset_check,
+       capset_set:                     cap_capset_set,
+       capable:                        cap_capable,
+       sys_security:                   cap_sys_security,
+       
+       bprm_alloc_security:            cap_bprm_alloc_security,
+       bprm_free_security:             cap_bprm_free_security,
+       bprm_compute_creds:             cap_bprm_compute_creds,
+       bprm_set_security:              cap_bprm_set_security,
+       bprm_check_security:            cap_bprm_check_security,
+       
+       task_create:                    cap_task_create,
+       task_alloc_security:            cap_task_alloc_security,
+       task_free_security:             cap_task_free_security,
+       task_setuid:                    cap_task_setuid,
+       task_post_setuid:               cap_task_post_setuid,
+       task_setgid:                    cap_task_setgid,
+       task_setpgid:                   cap_task_setpgid,
+       task_getpgid:                   cap_task_getpgid,
+       task_getsid:                    cap_task_getsid,
+       task_setgroups:                 cap_task_setgroups,
+       task_setnice:                   cap_task_setnice,
+       task_setrlimit:                 cap_task_setrlimit,
+       task_setscheduler:              cap_task_setscheduler,
+       task_getscheduler:              cap_task_getscheduler,
+       task_wait:                      cap_task_wait,
+       task_kill:                      cap_task_kill,
+       task_prctl:                     cap_task_prctl,
+       task_kmod_set_label:            cap_task_kmod_set_label,
+       task_reparent_to_init:          cap_task_reparent_to_init,
+       
+       register_security:              cap_register,
+       unregister_security:            cap_unregister,
+};
+
+#if defined(CONFIG_SECURITY_CAPABILITIES_MODULE)
+#define MY_NAME THIS_MODULE->name
+#else
+#define MY_NAME "capability"
+#endif
+
+static int __init capability_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 capabilities "
+                               "with primary security module.\n");
+                       return -EINVAL;
+               }
+               secondary = 1;
+       }
+       printk (KERN_INFO "Capability LSM initialized\n");
+       return 0;
+}
+
+static void __exit capability_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_init);
+module_exit (capability_exit);
+
+MODULE_DESCRIPTION("Standard Linux Capabilities Security Module");
+MODULE_LICENSE("GPL");
diff --git a/security/dummy.c b/security/dummy.c
new file mode 100644 (file)
index 0000000..197946f
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Stub functions for the default security function pointers in case no
+ * security model is loaded.
+ *
+ * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com>
+ * Copyright (C) 2001 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+
+static int dummy_ptrace (struct task_struct *parent, struct task_struct *child)
+{
+       return 0;
+}
+
+static int dummy_capget (struct task_struct *target, kernel_cap_t * effective,
+                        kernel_cap_t * inheritable, kernel_cap_t * permitted)
+{
+       return 0;
+}
+
+static int dummy_capset_check (struct task_struct *target,
+                              kernel_cap_t * effective,
+                              kernel_cap_t * inheritable,
+                              kernel_cap_t * permitted)
+{
+       return 0;
+}
+
+static void dummy_capset_set (struct task_struct *target,
+                             kernel_cap_t * effective,
+                             kernel_cap_t * inheritable,
+                             kernel_cap_t * permitted)
+{
+       return;
+}
+
+static int dummy_capable (struct task_struct *tsk, int cap)
+{
+       if (cap_is_fs_cap (cap) ? tsk->fsuid == 0 : tsk->euid == 0)
+               /* capability granted */
+               return 0;
+
+       /* capability denied */
+       return -EPERM;
+}
+
+static int dummy_sys_security (unsigned int id, unsigned int call,
+                              unsigned long *args)
+{
+       return -ENOSYS;
+}
+
+static int dummy_bprm_alloc_security (struct linux_binprm *bprm)
+{
+       return 0;
+}
+
+static void dummy_bprm_free_security (struct linux_binprm *bprm)
+{
+       return;
+}
+
+static void dummy_bprm_compute_creds (struct linux_binprm *bprm)
+{
+       return;
+}
+
+static int dummy_bprm_set_security (struct linux_binprm *bprm)
+{
+       return 0;
+}
+
+static int dummy_bprm_check_security (struct linux_binprm *bprm)
+{
+       return 0;
+}
+
+static int dummy_task_create (unsigned long clone_flags)
+{
+       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 (uid_t id0, uid_t id1, uid_t id2, int flags)
+{
+       return 0;
+}
+
+static int dummy_task_post_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_setpgid (struct task_struct *p, pid_t pgid)
+{
+       return 0;
+}
+
+static int dummy_task_getpgid (struct task_struct *p)
+{
+       return 0;
+}
+
+static int dummy_task_getsid (struct task_struct *p)
+{
+       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,
+                                   struct sched_param *lp)
+{
+       return 0;
+}
+
+static int dummy_task_getscheduler (struct task_struct *p)
+{
+       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_prctl (int option, unsigned long arg2, unsigned long arg3,
+                            unsigned long arg4, unsigned long arg5)
+{
+       return 0;
+}
+
+static void dummy_task_kmod_set_label (void)
+{
+       return;
+}
+
+static void dummy_task_reparent_to_init (struct task_struct *p)
+{
+       p->euid = p->fsuid = 0;
+       return;
+}
+
+static int dummy_register (const char *name, struct security_operations *ops)
+{
+       return -EINVAL;
+}
+
+static int dummy_unregister (const char *name, struct security_operations *ops)
+{
+       return -EINVAL;
+}
+
+struct security_operations dummy_security_ops = {
+       ptrace:                         dummy_ptrace,
+       capget:                         dummy_capget,
+       capset_check:                   dummy_capset_check,
+       capset_set:                     dummy_capset_set,
+       capable:                        dummy_capable,
+       sys_security:                   dummy_sys_security,
+       
+       bprm_alloc_security:            dummy_bprm_alloc_security,
+       bprm_free_security:             dummy_bprm_free_security,
+       bprm_compute_creds:             dummy_bprm_compute_creds,
+       bprm_set_security:              dummy_bprm_set_security,
+       bprm_check_security:            dummy_bprm_check_security,
+
+       task_create:                    dummy_task_create,
+       task_alloc_security:            dummy_task_alloc_security,
+       task_free_security:             dummy_task_free_security,
+       task_setuid:                    dummy_task_setuid,
+       task_post_setuid:               dummy_task_post_setuid,
+       task_setgid:                    dummy_task_setgid,
+       task_setpgid:                   dummy_task_setpgid,
+       task_getpgid:                   dummy_task_getpgid,
+       task_getsid:                    dummy_task_getsid,
+       task_setgroups:                 dummy_task_setgroups,
+       task_setnice:                   dummy_task_setnice,
+       task_setrlimit:                 dummy_task_setrlimit,
+       task_setscheduler:              dummy_task_setscheduler,
+       task_getscheduler:              dummy_task_getscheduler,
+       task_wait:                      dummy_task_wait,
+       task_kill:                      dummy_task_kill,
+       task_prctl:                     dummy_task_prctl,
+       task_kmod_set_label:            dummy_task_kmod_set_label,
+       task_reparent_to_init:          dummy_task_reparent_to_init,
+       
+       register_security:              dummy_register,
+       unregister_security:            dummy_unregister,
+};
+
diff --git a/security/security.c b/security/security.c
new file mode 100644 (file)
index 0000000..0cf0cea
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Security plug functions
+ *
+ * Copyright (C) 2001 WireX Communications, Inc <chris@wirex.com>
+ * Copyright (C) 2001 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/security.h>
+
+#define SECURITY_SCAFFOLD_VERSION      "1.0.0"
+
+extern struct security_operations dummy_security_ops;  /* lives in dummy.c */
+
+struct security_operations *security_ops;      /* Initialized to NULL */
+
+/* This macro checks that all pointers in a struct are non-NULL.  It 
+ * can be fooled by struct padding for object tile alignment and when
+ * pointers to data and pointers to functions aren't the same size.
+ * Yes it's ugly, we'll replace it if it becomes a problem.
+ */
+#define VERIFY_STRUCT(struct_type, s, e) \
+       do { \
+               unsigned long * __start = (unsigned long *)(s); \
+               unsigned long * __end = __start + \
+                               sizeof(struct_type)/sizeof(unsigned long *); \
+               while (__start != __end) { \
+                       if (!*__start) { \
+                               printk(KERN_INFO "%s is missing something\n",\
+                                       #struct_type); \
+                               e++; \
+                               break; \
+                       } \
+                       __start++; \
+               } \
+       } while (0)
+
+static int inline verify (struct security_operations *ops)
+{
+       int err;
+
+       /* verify the security_operations structure exists */
+       if (!ops) {
+               printk (KERN_INFO "Passed a NULL security_operations "
+                       "pointer, " __FUNCTION__ " failed.\n");
+               return -EINVAL;
+       }
+
+       /* Perform a little sanity checking on our inputs */
+       err = 0;
+
+       /* This first check scans the whole security_ops struct for
+        * missing structs or functions.
+        *
+        * (There is no further check now, but will leave as is until
+        *  the lazy registration stuff is done -- JM).
+        */
+       VERIFY_STRUCT(struct security_operations, ops, err);
+
+       if (err) {
+               printk (KERN_INFO "Not enough functions specified in the "
+                       "security_operation structure, " __FUNCTION__
+                       " failed.\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/**
+ * security_scaffolding_startup - initialzes the security scaffolding framework
+ *
+ * This should be called early in the kernel initialization sequence.
+ */
+int security_scaffolding_startup (void)
+{
+       printk (KERN_INFO "Security Scaffold v" SECURITY_SCAFFOLD_VERSION
+               " initialized\n");
+
+       security_ops = &dummy_security_ops;
+
+       return 0;
+}
+
+/**
+ * register_security - registers a security framework with the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * This function is to allow a security module to register itself with the
+ * kernel security subsystem.  Some rudimentary checking is done on the @ops
+ * value passed to this function.  A call to unregister_security() should be
+ * done to remove this security_options structure from the kernel.
+ *
+ * If the @ops structure does not contain function pointers for all hooks in
+ * the structure, or there is already a security module registered with the
+ * kernel, an error will be returned.  Otherwise 0 is returned on success.
+ */
+int register_security (struct security_operations *ops)
+{
+
+       if (verify (ops)) {
+               printk (KERN_INFO __FUNCTION__ " could not verify "
+                       "security_operations structure.\n");
+               return -EINVAL;
+       }
+       if (security_ops != &dummy_security_ops) {
+               printk (KERN_INFO "There is already a security "
+                       "framework initialized, " __FUNCTION__ " failed.\n");
+               return -EINVAL;
+       }
+
+       security_ops = ops;
+
+       return 0;
+}
+
+/**
+ * unregister_security - unregisters a security framework with the kernel
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * This function removes a struct security_operations variable that had
+ * previously been registered with a successful call to register_security().
+ *
+ * If @ops does not match the valued previously passed to register_security()
+ * an error is returned.  Otherwise the default security options is set to the
+ * the dummy_security_ops structure, and 0 is returned.
+ */
+int unregister_security (struct security_operations *ops)
+{
+       if (ops != security_ops) {
+               printk (KERN_INFO __FUNCTION__ ": trying to unregister "
+                       "a security_opts structure that is not "
+                       "registered, failing.\n");
+               return -EINVAL;
+       }
+
+       security_ops = &dummy_security_ops;
+
+       return 0;
+}
+
+/**
+ * mod_reg_security - allows security modules to be "stacked"
+ * @name: a pointer to a string with the name of the security_options to be registered
+ * @ops: a pointer to the struct security_options that is to be registered
+ *
+ * This function allows security modules to be stacked if the currently loaded
+ * security module allows this to happen.  It passes the @name and @ops to the
+ * register_security function of the currently loaded security module.
+ *
+ * The return value depends on the currently loaded security module, with 0 as
+ * success.
+ */
+int mod_reg_security (const char *name, struct security_operations *ops)
+{
+       if (verify (ops)) {
+               printk (KERN_INFO __FUNCTION__ " could not verify "
+                       "security operations.\n");
+               return -EINVAL;
+       }
+
+       if (ops == security_ops) {
+               printk (KERN_INFO __FUNCTION__ " security operations "
+                       "already registered.\n");
+               return -EINVAL;
+       }
+
+       return security_ops->register_security (name, ops);
+}
+
+/**
+ * mod_unreg_security - allows a security module registered with mod_reg_security() to be unloaded
+ * @name: a pointer to a string with the name of the security_options to be removed
+ * @ops: a pointer to the struct security_options that is to be removed
+ *
+ * This function allows security modules that have been successfully registered
+ * with a call to mod_reg_security() to be unloaded from the system.
+ * This calls the currently loaded security module's unregister_security() call
+ * with the @name and @ops variables.
+ *
+ * The return value depends on the currently loaded security module, with 0 as
+ * success.
+ */
+int mod_unreg_security (const char *name, struct security_operations *ops)
+{
+       if (ops == security_ops) {
+               printk (KERN_INFO __FUNCTION__ " invalid attempt to unregister "
+                       " primary security ops.\n");
+               return -EINVAL;
+       }
+
+       return security_ops->unregister_security (name, ops);
+}
+
+/**
+ * capable - calls the currently loaded security module's capable() function with the specified capability
+ * @cap: the requested capability level.
+ *
+ * This function calls the currently loaded security module's cabable()
+ * function with a pointer to the current task and the specified @cap value.
+ *
+ * This allows the security module to implement the capable function call
+ * however it chooses to.
+ */
+int capable (int cap)
+{
+       if (security_ops->capable (current, cap)) {
+               /* capability denied */
+               return 0;
+       }
+
+       /* capability granted */
+       current->flags |= PF_SUPERPRIV;
+       return 1;
+}
+
+/**
+ * sys_security - security syscall multiplexor.
+ * @id: module id
+ * @call: call identifier
+ * @args: arg list for call
+ *
+ * Similar to sys_socketcall.  Can use id to help identify which module user
+ * app is talking to.  The recommended convention for creating the
+ * hexadecimal id value is:
+ * 'echo "Name_of_module" | md5sum | cut -c -8'.
+ * By following this convention, there's no need for a central registry.
+ */
+asmlinkage long sys_security (unsigned int id, unsigned int call,
+                             unsigned long *args)
+{
+       return security_ops->sys_security (id, call, args);
+}
+
+EXPORT_SYMBOL (register_security);
+EXPORT_SYMBOL (unregister_security);
+EXPORT_SYMBOL (mod_reg_security);
+EXPORT_SYMBOL (mod_unreg_security);
+EXPORT_SYMBOL (capable);
+EXPORT_SYMBOL (security_ops);