Merge branch 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Mar 2019 19:44:01 +0000 (11:44 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Mar 2019 19:44:01 +0000 (11:44 -0800)
Pull security subsystem updates from James Morris:

 - Extend LSM stacking to allow sharing of cred, file, ipc, inode, and
   task blobs. This paves the way for more full-featured LSMs to be
   merged, and is specifically aimed at LandLock and SARA LSMs. This
   work is from Casey and Kees.

 - There's a new LSM from Micah Morton: "SafeSetID gates the setid
   family of syscalls to restrict UID/GID transitions from a given
   UID/GID to only those approved by a system-wide whitelist." This
   feature is currently shipping in ChromeOS.

* 'next-general' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (62 commits)
  keys: fix missing __user in KEYCTL_PKEY_QUERY
  LSM: Update list of SECURITYFS users in Kconfig
  LSM: Ignore "security=" when "lsm=" is specified
  LSM: Update function documentation for cap_capable
  security: mark expected switch fall-throughs and add a missing break
  tomoyo: Bump version.
  LSM: fix return value check in safesetid_init_securityfs()
  LSM: SafeSetID: add selftest
  LSM: SafeSetID: remove unused include
  LSM: SafeSetID: 'depend' on CONFIG_SECURITY
  LSM: Add 'name' field for SafeSetID in DEFINE_LSM
  LSM: add SafeSetID module that gates setid calls
  LSM: add SafeSetID module that gates setid calls
  tomoyo: Allow multiple use_group lines.
  tomoyo: Coding style fix.
  tomoyo: Swicth from cred->security to task_struct->security.
  security: keys: annotate implicit fall throughs
  security: keys: annotate implicit fall throughs
  security: keys: annotate implicit fall through
  capabilities:: annotate implicit fall through
  ...

78 files changed:
Documentation/admin-guide/LSM/SafeSetID.rst [new file with mode: 0644]
Documentation/admin-guide/LSM/index.rst
Documentation/admin-guide/kernel-parameters.txt
MAINTAINERS
fs/proc/base.c
fs/proc/internal.h
include/linux/capability.h
include/linux/cred.h
include/linux/lsm_hooks.h
include/linux/security.h
include/linux/selinux.h [deleted file]
kernel/capability.c
kernel/cred.c
kernel/seccomp.c
kernel/sys.c
security/Kconfig
security/Makefile
security/apparmor/Kconfig
security/apparmor/capability.c
security/apparmor/domain.c
security/apparmor/include/capability.h
security/apparmor/include/cred.h
security/apparmor/include/file.h
security/apparmor/include/lib.h
security/apparmor/include/task.h
security/apparmor/ipc.c
security/apparmor/lsm.c
security/apparmor/resource.c
security/apparmor/task.c
security/commoncap.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_template_lib.c
security/keys/keyctl.c
security/keys/keyring.c
security/keys/process_keys.c
security/keys/request_key.c
security/loadpin/loadpin.c
security/safesetid/Kconfig [new file with mode: 0644]
security/safesetid/Makefile [new file with mode: 0644]
security/safesetid/lsm.c [new file with mode: 0644]
security/safesetid/lsm.h [new file with mode: 0644]
security/safesetid/securityfs.c [new file with mode: 0644]
security/security.c
security/selinux/Kconfig
security/selinux/Makefile
security/selinux/exports.c [deleted file]
security/selinux/hooks.c
security/selinux/include/audit.h
security/selinux/include/objsec.h
security/selinux/selinuxfs.c
security/selinux/ss/services.c
security/selinux/xfrm.c
security/smack/smack.h
security/smack/smack_access.c
security/smack/smack_lsm.c
security/smack/smackfs.c
security/tomoyo/audit.c
security/tomoyo/common.c
security/tomoyo/common.h
security/tomoyo/condition.c
security/tomoyo/domain.c
security/tomoyo/file.c
security/tomoyo/gc.c
security/tomoyo/group.c
security/tomoyo/load_policy.c
security/tomoyo/memory.c
security/tomoyo/mount.c
security/tomoyo/realpath.c
security/tomoyo/securityfs_if.c
security/tomoyo/tomoyo.c
security/tomoyo/util.c
security/yama/yama_lsm.c
tools/testing/selftests/safesetid/.gitignore [new file with mode: 0644]
tools/testing/selftests/safesetid/Makefile [new file with mode: 0644]
tools/testing/selftests/safesetid/config [new file with mode: 0644]
tools/testing/selftests/safesetid/safesetid-test.c [new file with mode: 0644]
tools/testing/selftests/safesetid/safesetid-test.sh [new file with mode: 0755]

diff --git a/Documentation/admin-guide/LSM/SafeSetID.rst b/Documentation/admin-guide/LSM/SafeSetID.rst
new file mode 100644 (file)
index 0000000..212434e
--- /dev/null
@@ -0,0 +1,107 @@
+=========
+SafeSetID
+=========
+SafeSetID is an LSM module that gates the setid family of syscalls to restrict
+UID/GID transitions from a given UID/GID to only those approved by a
+system-wide whitelist. These restrictions also prohibit the given UIDs/GIDs
+from obtaining auxiliary privileges associated with CAP_SET{U/G}ID, such as
+allowing a user to set up user namespace UID mappings.
+
+
+Background
+==========
+In absence of file capabilities, processes spawned on a Linux system that need
+to switch to a different user must be spawned with CAP_SETUID privileges.
+CAP_SETUID is granted to programs running as root or those running as a non-root
+user that have been explicitly given the CAP_SETUID runtime capability. It is
+often preferable to use Linux runtime capabilities rather than file
+capabilities, since using file capabilities to run a program with elevated
+privileges opens up possible security holes since any user with access to the
+file can exec() that program to gain the elevated privileges.
+
+While it is possible to implement a tree of processes by giving full
+CAP_SET{U/G}ID capabilities, this is often at odds with the goals of running a
+tree of processes under non-root user(s) in the first place. Specifically,
+since CAP_SETUID allows changing to any user on the system, including the root
+user, it is an overpowered capability for what is needed in this scenario,
+especially since programs often only call setuid() to drop privileges to a
+lesser-privileged user -- not elevate privileges. Unfortunately, there is no
+generally feasible way in Linux to restrict the potential UIDs that a user can
+switch to through setuid() beyond allowing a switch to any user on the system.
+This SafeSetID LSM seeks to provide a solution for restricting setid
+capabilities in such a way.
+
+The main use case for this LSM is to allow a non-root program to transition to
+other untrusted uids without full blown CAP_SETUID capabilities. The non-root
+program would still need CAP_SETUID to do any kind of transition, but the
+additional restrictions imposed by this LSM would mean it is a "safer" version
+of CAP_SETUID since the non-root program cannot take advantage of CAP_SETUID to
+do any unapproved actions (e.g. setuid to uid 0 or create/enter new user
+namespace). The higher level goal is to allow for uid-based sandboxing of system
+services without having to give out CAP_SETUID all over the place just so that
+non-root programs can drop to even-lesser-privileged uids. This is especially
+relevant when one non-root daemon on the system should be allowed to spawn other
+processes as different uids, but its undesirable to give the daemon a
+basically-root-equivalent CAP_SETUID.
+
+
+Other Approaches Considered
+===========================
+
+Solve this problem in userspace
+-------------------------------
+For candidate applications that would like to have restricted setid capabilities
+as implemented in this LSM, an alternative option would be to simply take away
+setid capabilities from the application completely and refactor the process
+spawning semantics in the application (e.g. by using a privileged helper program
+to do process spawning and UID/GID transitions). Unfortunately, there are a
+number of semantics around process spawning that would be affected by this, such
+as fork() calls where the program doesn???t immediately call exec() after the
+fork(), parent processes specifying custom environment variables or command line
+args for spawned child processes, or inheritance of file handles across a
+fork()/exec(). Because of this, as solution that uses a privileged helper in
+userspace would likely be less appealing to incorporate into existing projects
+that rely on certain process-spawning semantics in Linux.
+
+Use user namespaces
+-------------------
+Another possible approach would be to run a given process tree in its own user
+namespace and give programs in the tree setid capabilities. In this way,
+programs in the tree could change to any desired UID/GID in the context of their
+own user namespace, and only approved UIDs/GIDs could be mapped back to the
+initial system user namespace, affectively preventing privilege escalation.
+Unfortunately, it is not generally feasible to use user namespaces in isolation,
+without pairing them with other namespace types, which is not always an option.
+Linux checks for capabilities based off of the user namespace that ???owns??? some
+entity. For example, Linux has the notion that network namespaces are owned by
+the user namespace in which they were created. A consequence of this is that
+capability checks for access to a given network namespace are done by checking
+whether a task has the given capability in the context of the user namespace
+that owns the network namespace -- not necessarily the user namespace under
+which the given task runs. Therefore spawning a process in a new user namespace
+effectively prevents it from accessing the network namespace owned by the
+initial namespace. This is a deal-breaker for any application that expects to
+retain the CAP_NET_ADMIN capability for the purpose of adjusting network
+configurations. Using user namespaces in isolation causes problems regarding
+other system interactions, including use of pid namespaces and device creation.
+
+Use an existing LSM
+-------------------
+None of the other in-tree LSMs have the capability to gate setid transitions, or
+even employ the security_task_fix_setuid hook at all. SELinux says of that hook:
+"Since setuid only affects the current process, and since the SELinux controls
+are not based on the Linux identity attributes, SELinux does not need to control
+this operation."
+
+
+Directions for use
+==================
+This LSM hooks the setid syscalls to make sure transitions are allowed if an
+applicable restriction policy is in place. Policies are configured through
+securityfs by writing to the safesetid/add_whitelist_policy and
+safesetid/flush_whitelist_policies files at the location where securityfs is
+mounted. The format for adding a policy is '<UID>:<UID>', using literal
+numbers, such as '123:456'. To flush the policies, any write to the file is
+sufficient. Again, configuring a policy for a UID will prevent that UID from
+obtaining auxiliary setid privileges, such as allowing a user to set up user
+namespace UID mappings.
index c980dfe9abf17afc5431048fd7df58b69562955b..a6ba95fbaa9f105a00cc6594b018661de9075aaa 100644 (file)
@@ -17,9 +17,8 @@ MAC extensions, other extensions can be built using the LSM to provide
 specific changes to system operation when these tweaks are not available
 in the core functionality of Linux itself.
 
-Without a specific LSM built into the kernel, the default LSM will be the
-Linux capabilities system. Most LSMs choose to extend the capabilities
-system, building their checks on top of the defined capability hooks.
+The Linux capabilities modules will always be included. This may be
+followed by any number of "minor" modules and at most one "major" module.
 For more details on capabilities, see ``capabilities(7)`` in the Linux
 man-pages project.
 
@@ -30,6 +29,14 @@ order in which checks are made. The capability module will always
 be first, followed by any "minor" modules (e.g. Yama) and then
 the one "major" module (e.g. SELinux) if there is one configured.
 
+Process attributes associated with "major" security modules should
+be accessed and maintained using the special files in ``/proc/.../attr``.
+A security module may maintain a module specific subdirectory there,
+named after the module. ``/proc/.../attr/smack`` is provided by the Smack
+security module and contains all its special files. The files directly
+in ``/proc/.../attr`` remain as legacy interfaces for modules that provide
+subdirectories.
+
 .. toctree::
    :maxdepth: 1
 
@@ -39,3 +46,4 @@ the one "major" module (e.g. SELinux) if there is one configured.
    Smack
    tomoyo
    Yama
+   SafeSetID
index a422560fbc15a7c6fb66afd85db48ed4e53e2b27..42379633801f4741a1af5a03c1153b1230d948eb 100644 (file)
 
        lsm.debug       [SECURITY] Enable LSM initialization debugging output.
 
+       lsm=lsm1,...,lsmN
+                       [SECURITY] Choose order of LSM initialization. This
+                       overrides CONFIG_LSM, and the "security=" parameter.
+
        machvec=        [IA-64] Force the use of a particular machine-vector
                        (machvec) in a generic kernel.
                        Example: machvec=hpzx1_swiotlb
                        Note: increases power consumption, thus should only be
                        enabled if running jitter sensitive (HPC/RT) workloads.
 
-       security=       [SECURITY] Choose a security module to enable at boot.
-                       If this boot parameter is not specified, only the first
-                       security module asking for security registration will be
-                       loaded. An invalid security module name will be treated
-                       as if no module has been chosen.
+       security=       [SECURITY] Choose a legacy "major" security module to
+                       enable at boot. This has been deprecated by the
+                       "lsm=" parameter.
 
        selinux=        [SELINUX] Disable or enable SELinux at boot time.
                        Format: { "0" | "1" }
index da98f27cf1b582f303a9616d44259ddf83e8b9cd..09d47cd02a146bbfe8c7d039ad9fb53f6ce0a74e 100644 (file)
@@ -15557,12 +15557,11 @@ F:    mm/shmem.c
 TOMOYO SECURITY MODULE
 M:     Kentaro Takeda <takedakn@nttdata.co.jp>
 M:     Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
-L:     tomoyo-dev-en@lists.sourceforge.jp (subscribers-only, for developers in English)
-L:     tomoyo-users-en@lists.sourceforge.jp (subscribers-only, for users in English)
-L:     tomoyo-dev@lists.sourceforge.jp (subscribers-only, for developers in Japanese)
-L:     tomoyo-users@lists.sourceforge.jp (subscribers-only, for users in Japanese)
-W:     http://tomoyo.sourceforge.jp/
-T:     quilt http://svn.sourceforge.jp/svnroot/tomoyo/trunk/2.5.x/tomoyo-lsm/patches/
+L:     tomoyo-dev-en@lists.osdn.me (subscribers-only, for developers in English)
+L:     tomoyo-users-en@lists.osdn.me (subscribers-only, for users in English)
+L:     tomoyo-dev@lists.osdn.me (subscribers-only, for developers in Japanese)
+L:     tomoyo-users@lists.osdn.me (subscribers-only, for users in Japanese)
+W:     https://tomoyo.osdn.jp/
 S:     Maintained
 F:     security/tomoyo/
 
index 511b279ec69cdce7a3e434d9d9152fd95678bd36..fca9fa5f23d85cd8975b06baade0fe395db23538 100644 (file)
@@ -140,9 +140,13 @@ struct pid_entry {
 #define REG(NAME, MODE, fops)                          \
        NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {})
 #define ONE(NAME, MODE, show)                          \
-       NOD(NAME, (S_IFREG|(MODE)),                     \
+       NOD(NAME, (S_IFREG|(MODE)),                     \
                NULL, &proc_single_file_operations,     \
                { .proc_show = show } )
+#define ATTR(LSM, NAME, MODE)                          \
+       NOD(NAME, (S_IFREG|(MODE)),                     \
+               NULL, &proc_pid_attr_operations,        \
+               { .lsm = LSM })
 
 /*
  * Count the number of hardlinks for the pid_entry table, excluding the .
@@ -2521,7 +2525,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
        if (!task)
                return -ESRCH;
 
-       length = security_getprocattr(task,
+       length = security_getprocattr(task, PROC_I(inode)->op.lsm,
                                      (char*)file->f_path.dentry->d_name.name,
                                      &p);
        put_task_struct(task);
@@ -2570,7 +2574,9 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
        if (rv < 0)
                goto out_free;
 
-       rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count);
+       rv = security_setprocattr(PROC_I(inode)->op.lsm,
+                                 file->f_path.dentry->d_name.name, page,
+                                 count);
        mutex_unlock(&current->signal->cred_guard_mutex);
 out_free:
        kfree(page);
@@ -2584,13 +2590,53 @@ static const struct file_operations proc_pid_attr_operations = {
        .llseek         = generic_file_llseek,
 };
 
+#define LSM_DIR_OPS(LSM) \
+static int proc_##LSM##_attr_dir_iterate(struct file *filp, \
+                            struct dir_context *ctx) \
+{ \
+       return proc_pident_readdir(filp, ctx, \
+                                  LSM##_attr_dir_stuff, \
+                                  ARRAY_SIZE(LSM##_attr_dir_stuff)); \
+} \
+\
+static const struct file_operations proc_##LSM##_attr_dir_ops = { \
+       .read           = generic_read_dir, \
+       .iterate        = proc_##LSM##_attr_dir_iterate, \
+       .llseek         = default_llseek, \
+}; \
+\
+static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \
+                               struct dentry *dentry, unsigned int flags) \
+{ \
+       return proc_pident_lookup(dir, dentry, \
+                                 LSM##_attr_dir_stuff, \
+                                 ARRAY_SIZE(LSM##_attr_dir_stuff)); \
+} \
+\
+static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \
+       .lookup         = proc_##LSM##_attr_dir_lookup, \
+       .getattr        = pid_getattr, \
+       .setattr        = proc_setattr, \
+}
+
+#ifdef CONFIG_SECURITY_SMACK
+static const struct pid_entry smack_attr_dir_stuff[] = {
+       ATTR("smack", "current",        0666),
+};
+LSM_DIR_OPS(smack);
+#endif
+
 static const struct pid_entry attr_dir_stuff[] = {
-       REG("current",    S_IRUGO|S_IWUGO, proc_pid_attr_operations),
-       REG("prev",       S_IRUGO,         proc_pid_attr_operations),
-       REG("exec",       S_IRUGO|S_IWUGO, proc_pid_attr_operations),
-       REG("fscreate",   S_IRUGO|S_IWUGO, proc_pid_attr_operations),
-       REG("keycreate",  S_IRUGO|S_IWUGO, proc_pid_attr_operations),
-       REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
+       ATTR(NULL, "current",           0666),
+       ATTR(NULL, "prev",              0444),
+       ATTR(NULL, "exec",              0666),
+       ATTR(NULL, "fscreate",          0666),
+       ATTR(NULL, "keycreate",         0666),
+       ATTR(NULL, "sockcreate",        0666),
+#ifdef CONFIG_SECURITY_SMACK
+       DIR("smack",                    0555,
+           proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
+#endif
 };
 
 static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
index 4fc5a9b68f76d8d1f9498aacef8920eb42ffc9b3..ea575375f210d393d43e94ff63ed0394285a7634 100644 (file)
@@ -82,6 +82,7 @@ union proc_op {
        int (*proc_show)(struct seq_file *m,
                struct pid_namespace *ns, struct pid *pid,
                struct task_struct *task);
+       const char *lsm;
 };
 
 struct proc_inode {
index f640dcbc880c0c291cdbd2a5780f4fd21be4b7b3..c3f9a4d558a04453e1d3747a7f4d2bbdfe6c0000 100644 (file)
@@ -209,6 +209,7 @@ extern bool has_ns_capability_noaudit(struct task_struct *t,
 extern bool capable(int cap);
 extern bool ns_capable(struct user_namespace *ns, int cap);
 extern bool ns_capable_noaudit(struct user_namespace *ns, int cap);
+extern bool ns_capable_setid(struct user_namespace *ns, int cap);
 #else
 static inline bool has_capability(struct task_struct *t, int cap)
 {
@@ -240,6 +241,10 @@ static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap)
 {
        return true;
 }
+static inline bool ns_capable_setid(struct user_namespace *ns, int cap)
+{
+       return true;
+}
 #endif /* CONFIG_MULTIUSER */
 extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode);
 extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
index 4907c9df86b32ff7f645ced3f687bce85472a18f..ddd45bb74887426419927144a889634d3e5ae998 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/capability.h>
 #include <linux/init.h>
 #include <linux/key.h>
-#include <linux/selinux.h>
 #include <linux/atomic.h>
 #include <linux/uidgid.h>
 #include <linux/sched.h>
index 9a0bdf91e6467bc1c4dae2629b9608a4047533ef..22fc786d723ae4cc36a0588d6e5f320a524b66f1 100644 (file)
  *     @cred contains the credentials to use.
  *     @ns contains the user namespace we want the capability in
  *     @cap contains the capability <include/linux/capability.h>.
- *     @audit contains whether to write an audit message or not
+ *     @opts contains options for the capable check <include/linux/security.h>
  *     Return 0 if the capability is granted for @tsk.
  * @syslog:
  *     Check permission before accessing the kernel message ring or changing
@@ -1446,8 +1446,10 @@ union security_list_options {
                        const kernel_cap_t *effective,
                        const kernel_cap_t *inheritable,
                        const kernel_cap_t *permitted);
-       int (*capable)(const struct cred *cred, struct user_namespace *ns,
-                       int cap, int audit);
+       int (*capable)(const struct cred *cred,
+                       struct user_namespace *ns,
+                       int cap,
+                       unsigned int opts);
        int (*quotactl)(int cmds, int type, int id, struct super_block *sb);
        int (*quota_on)(struct dentry *dentry);
        int (*syslog)(int type);
@@ -2027,6 +2029,18 @@ struct security_hook_list {
        char                            *lsm;
 } __randomize_layout;
 
+/*
+ * Security blob size or offset data.
+ */
+struct lsm_blob_sizes {
+       int     lbs_cred;
+       int     lbs_file;
+       int     lbs_inode;
+       int     lbs_ipc;
+       int     lbs_msg_msg;
+       int     lbs_task;
+};
+
 /*
  * Initializing a security_hook_list structure takes
  * up a lot of space in a source file. This macro takes
@@ -2042,9 +2056,21 @@ extern char *lsm_names;
 extern void security_add_hooks(struct security_hook_list *hooks, int count,
                                char *lsm);
 
+#define LSM_FLAG_LEGACY_MAJOR  BIT(0)
+#define LSM_FLAG_EXCLUSIVE     BIT(1)
+
+enum lsm_order {
+       LSM_ORDER_FIRST = -1,   /* This is only for capabilities. */
+       LSM_ORDER_MUTABLE = 0,
+};
+
 struct lsm_info {
        const char *name;       /* Required. */
+       enum lsm_order order;   /* Optional: default is LSM_ORDER_MUTABLE */
+       unsigned long flags;    /* Optional: flags describing LSM */
+       int *enabled;           /* Optional: controlled by CONFIG_LSM */
        int (*init)(void);      /* Required. */
+       struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
 };
 
 extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
@@ -2084,17 +2110,6 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
 #define __lsm_ro_after_init    __ro_after_init
 #endif /* CONFIG_SECURITY_WRITABLE_HOOKS */
 
-extern int __init security_module_enable(const char *module);
-extern void __init capability_add_hooks(void);
-#ifdef CONFIG_SECURITY_YAMA
-extern void __init yama_add_hooks(void);
-#else
-static inline void __init yama_add_hooks(void) { }
-#endif
-#ifdef CONFIG_SECURITY_LOADPIN
-void __init loadpin_add_hooks(void);
-#else
-static inline void loadpin_add_hooks(void) { };
-#endif
+extern int lsm_inode_alloc(struct inode *inode);
 
 #endif /* ! __LINUX_LSM_HOOKS_H */
index dbfb5a66babb5ae8ed99b7e13095fc085fba01c8..13537a49ae97258f46065f809443c7dc5f44e59f 100644 (file)
@@ -54,9 +54,12 @@ struct xattr;
 struct xfrm_sec_ctx;
 struct mm_struct;
 
+/* Default (no) options for the capable function */
+#define CAP_OPT_NONE 0x0
 /* If capable should audit the security request */
-#define SECURITY_CAP_NOAUDIT 0
-#define SECURITY_CAP_AUDIT 1
+#define CAP_OPT_NOAUDIT BIT(1)
+/* If capable is being called by a setid function */
+#define CAP_OPT_INSETID BIT(2)
 
 /* LSM Agnostic defines for sb_set_mnt_opts */
 #define SECURITY_LSM_NATIVE_LABELS     1
@@ -72,7 +75,7 @@ enum lsm_event {
 
 /* These functions are in security/commoncap.c */
 extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
-                      int cap, int audit);
+                      int cap, unsigned int opts);
 extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz);
 extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
 extern int cap_ptrace_traceme(struct task_struct *parent);
@@ -207,10 +210,10 @@ int security_capset(struct cred *new, const struct cred *old,
                    const kernel_cap_t *effective,
                    const kernel_cap_t *inheritable,
                    const kernel_cap_t *permitted);
-int security_capable(const struct cred *cred, struct user_namespace *ns,
-                       int cap);
-int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
-                            int cap);
+int security_capable(const struct cred *cred,
+                      struct user_namespace *ns,
+                      int cap,
+                      unsigned int opts);
 int security_quotactl(int cmds, int type, int id, struct super_block *sb);
 int security_quota_on(struct dentry *dentry);
 int security_syslog(int type);
@@ -366,8 +369,10 @@ int security_sem_semctl(struct kern_ipc_perm *sma, int cmd);
 int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops,
                        unsigned nsops, int alter);
 void security_d_instantiate(struct dentry *dentry, struct inode *inode);
-int security_getprocattr(struct task_struct *p, char *name, char **value);
-int security_setprocattr(const char *name, void *value, size_t size);
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+                        char **value);
+int security_setprocattr(const char *lsm, const char *name, void *value,
+                        size_t size);
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
 int security_ismaclabel(const char *name);
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
@@ -462,14 +467,11 @@ static inline int security_capset(struct cred *new,
 }
 
 static inline int security_capable(const struct cred *cred,
-                                  struct user_namespace *ns, int cap)
+                                  struct user_namespace *ns,
+                                  int cap,
+                                  unsigned int opts)
 {
-       return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT);
-}
-
-static inline int security_capable_noaudit(const struct cred *cred,
-                                          struct user_namespace *ns, int cap) {
-       return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT);
+       return cap_capable(cred, ns, cap, opts);
 }
 
 static inline int security_quotactl(int cmds, int type, int id,
@@ -1112,15 +1114,18 @@ static inline int security_sem_semop(struct kern_ipc_perm *sma,
        return 0;
 }
 
-static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode)
+static inline void security_d_instantiate(struct dentry *dentry,
+                                         struct inode *inode)
 { }
 
-static inline int security_getprocattr(struct task_struct *p, char *name, char **value)
+static inline int security_getprocattr(struct task_struct *p, const char *lsm,
+                                      char *name, char **value)
 {
        return -EINVAL;
 }
 
-static inline int security_setprocattr(char *name, void *value, size_t size)
+static inline int security_setprocattr(const char *lsm, char *name,
+                                      void *value, size_t size)
 {
        return -EINVAL;
 }
diff --git a/include/linux/selinux.h b/include/linux/selinux.h
deleted file mode 100644 (file)
index 44f4596..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * SELinux services exported to the rest of the kernel.
- *
- * Author: James Morris <jmorris@redhat.com>
- *
- * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
- * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
- * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- */
-#ifndef _LINUX_SELINUX_H
-#define _LINUX_SELINUX_H
-
-struct selinux_audit_rule;
-struct audit_context;
-struct kern_ipc_perm;
-
-#ifdef CONFIG_SECURITY_SELINUX
-
-/**
- * selinux_is_enabled - is SELinux enabled?
- */
-bool selinux_is_enabled(void);
-#else
-
-static inline bool selinux_is_enabled(void)
-{
-       return false;
-}
-#endif /* CONFIG_SECURITY_SELINUX */
-
-#endif /* _LINUX_SELINUX_H */
index 1e1c0236f55b5b05b54caa49dca62c1b7e2d5819..1444f3954d750ba685b9423e94522e0243175f90 100644 (file)
@@ -93,9 +93,7 @@ static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
                break;
        case _LINUX_CAPABILITY_VERSION_2:
                warn_deprecated_v2();
-               /*
-                * fall through - v3 is otherwise equivalent to v2.
-                */
+               /* fall through - v3 is otherwise equivalent to v2. */
        case _LINUX_CAPABILITY_VERSION_3:
                *tocopy = _LINUX_CAPABILITY_U32S_3;
                break;
@@ -299,7 +297,7 @@ bool has_ns_capability(struct task_struct *t,
        int ret;
 
        rcu_read_lock();
-       ret = security_capable(__task_cred(t), ns, cap);
+       ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NONE);
        rcu_read_unlock();
 
        return (ret == 0);
@@ -340,7 +338,7 @@ bool has_ns_capability_noaudit(struct task_struct *t,
        int ret;
 
        rcu_read_lock();
-       ret = security_capable_noaudit(__task_cred(t), ns, cap);
+       ret = security_capable(__task_cred(t), ns, cap, CAP_OPT_NOAUDIT);
        rcu_read_unlock();
 
        return (ret == 0);
@@ -363,7 +361,9 @@ bool has_capability_noaudit(struct task_struct *t, int cap)
        return has_ns_capability_noaudit(t, &init_user_ns, cap);
 }
 
-static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
+static bool ns_capable_common(struct user_namespace *ns,
+                             int cap,
+                             unsigned int opts)
 {
        int capable;
 
@@ -372,8 +372,7 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
                BUG();
        }
 
-       capable = audit ? security_capable(current_cred(), ns, cap) :
-                         security_capable_noaudit(current_cred(), ns, cap);
+       capable = security_capable(current_cred(), ns, cap, opts);
        if (capable == 0) {
                current->flags |= PF_SUPERPRIV;
                return true;
@@ -394,7 +393,7 @@ static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
  */
 bool ns_capable(struct user_namespace *ns, int cap)
 {
-       return ns_capable_common(ns, cap, true);
+       return ns_capable_common(ns, cap, CAP_OPT_NONE);
 }
 EXPORT_SYMBOL(ns_capable);
 
@@ -412,10 +411,29 @@ EXPORT_SYMBOL(ns_capable);
  */
 bool ns_capable_noaudit(struct user_namespace *ns, int cap)
 {
-       return ns_capable_common(ns, cap, false);
+       return ns_capable_common(ns, cap, CAP_OPT_NOAUDIT);
 }
 EXPORT_SYMBOL(ns_capable_noaudit);
 
+/**
+ * ns_capable_setid - Determine if the current task has a superior capability
+ * in effect, while signalling that this check is being done from within a
+ * setid syscall.
+ * @ns:  The usernamespace we want the capability in
+ * @cap: The capability to be tested for
+ *
+ * Return true if the current task has the given superior capability currently
+ * available for use, false if not.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool ns_capable_setid(struct user_namespace *ns, int cap)
+{
+       return ns_capable_common(ns, cap, CAP_OPT_INSETID);
+}
+EXPORT_SYMBOL(ns_capable_setid);
+
 /**
  * capable - Determine if the current task has a superior capability in effect
  * @cap: The capability to be tested for
@@ -448,10 +466,11 @@ EXPORT_SYMBOL(capable);
 bool file_ns_capable(const struct file *file, struct user_namespace *ns,
                     int cap)
 {
+
        if (WARN_ON_ONCE(!cap_valid(cap)))
                return false;
 
-       if (security_capable(file->f_cred, ns, cap) == 0)
+       if (security_capable(file->f_cred, ns, cap, CAP_OPT_NONE) == 0)
                return true;
 
        return false;
@@ -500,10 +519,12 @@ bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns)
 {
        int ret = 0;  /* An absent tracer adds no restrictions */
        const struct cred *cred;
+
        rcu_read_lock();
        cred = rcu_dereference(tsk->ptracer_cred);
        if (cred)
-               ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE);
+               ret = security_capable(cred, ns, CAP_SYS_PTRACE,
+                                      CAP_OPT_NOAUDIT);
        rcu_read_unlock();
        return (ret == 0);
 }
index 21f4a97085b4041bcbe9b23568aec7bed935f21f..45d77284aed0a91383e71e53bfadf6dd5017f7e0 100644 (file)
@@ -760,19 +760,6 @@ bool creds_are_invalid(const struct cred *cred)
 {
        if (cred->magic != CRED_MAGIC)
                return true;
-#ifdef CONFIG_SECURITY_SELINUX
-       /*
-        * cred->security == NULL if security_cred_alloc_blank() or
-        * security_prepare_creds() returned an error.
-        */
-       if (selinux_is_enabled() && cred->security) {
-               if ((unsigned long) cred->security < PAGE_SIZE)
-                       return true;
-               if ((*(u32 *)cred->security & 0xffffff00) ==
-                   (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
-                       return true;
-       }
-#endif
        return false;
 }
 EXPORT_SYMBOL(creds_are_invalid);
index a43c601ac252a7591c0464c9ef58162c94285ae0..54a0347ca8128f09cdbbcc83e2e8f8eea633a7ab 100644 (file)
@@ -445,8 +445,8 @@ static struct seccomp_filter *seccomp_prepare_filter(struct sock_fprog *fprog)
         * behavior of privileged children.
         */
        if (!task_no_new_privs(current) &&
-           security_capable_noaudit(current_cred(), current_user_ns(),
-                                    CAP_SYS_ADMIN) != 0)
+           security_capable(current_cred(), current_user_ns(),
+                                    CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) != 0)
                return ERR_PTR(-EACCES);
 
        /* Allocate a new seccomp_filter */
index f7eb62eceb2437d18bd3f9a7c8f8287255627015..c5f875048aefe60755d6afe4a235e52cbd20c766 100644 (file)
@@ -516,7 +516,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
                new->uid = kruid;
                if (!uid_eq(old->uid, kruid) &&
                    !uid_eq(old->euid, kruid) &&
-                   !ns_capable(old->user_ns, CAP_SETUID))
+                   !ns_capable_setid(old->user_ns, CAP_SETUID))
                        goto error;
        }
 
@@ -525,7 +525,7 @@ long __sys_setreuid(uid_t ruid, uid_t euid)
                if (!uid_eq(old->uid, keuid) &&
                    !uid_eq(old->euid, keuid) &&
                    !uid_eq(old->suid, keuid) &&
-                   !ns_capable(old->user_ns, CAP_SETUID))
+                   !ns_capable_setid(old->user_ns, CAP_SETUID))
                        goto error;
        }
 
@@ -584,7 +584,7 @@ long __sys_setuid(uid_t uid)
        old = current_cred();
 
        retval = -EPERM;
-       if (ns_capable(old->user_ns, CAP_SETUID)) {
+       if (ns_capable_setid(old->user_ns, CAP_SETUID)) {
                new->suid = new->uid = kuid;
                if (!uid_eq(kuid, old->uid)) {
                        retval = set_user(new);
@@ -646,7 +646,7 @@ long __sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
        old = current_cred();
 
        retval = -EPERM;
-       if (!ns_capable(old->user_ns, CAP_SETUID)) {
+       if (!ns_capable_setid(old->user_ns, CAP_SETUID)) {
                if (ruid != (uid_t) -1        && !uid_eq(kruid, old->uid) &&
                    !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid))
                        goto error;
@@ -814,7 +814,7 @@ long __sys_setfsuid(uid_t uid)
 
        if (uid_eq(kuid, old->uid)  || uid_eq(kuid, old->euid)  ||
            uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) ||
-           ns_capable(old->user_ns, CAP_SETUID)) {
+           ns_capable_setid(old->user_ns, CAP_SETUID)) {
                if (!uid_eq(kuid, old->fsuid)) {
                        new->fsuid = kuid;
                        if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0)
index e4fe2f3c2c65a00eb8ea794178c73998b0e567de..1d6463fb1450c03b8739b102b48b64e05aaa533e 100644 (file)
@@ -40,8 +40,7 @@ config SECURITYFS
        bool "Enable the securityfs filesystem"
        help
          This will build the securityfs filesystem.  It is currently used by
-         the TPM bios character driver and IMA, an integrity provider.  It is
-         not used by SELinux or SMACK.
+         various security modules (AppArmor, IMA, SafeSetID, TOMOYO, TPM).
 
          If you are unsure how to answer this question, answer N.
 
@@ -236,45 +235,19 @@ source "security/tomoyo/Kconfig"
 source "security/apparmor/Kconfig"
 source "security/loadpin/Kconfig"
 source "security/yama/Kconfig"
+source "security/safesetid/Kconfig"
 
 source "security/integrity/Kconfig"
 
-choice
-       prompt "Default security module"
-       default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX
-       default DEFAULT_SECURITY_SMACK if SECURITY_SMACK
-       default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO
-       default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR
-       default DEFAULT_SECURITY_DAC
-
+config LSM
+       string "Ordered list of enabled LSMs"
+       default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor"
        help
-         Select the security module that will be used by default if the
-         kernel parameter security= is not specified.
-
-       config DEFAULT_SECURITY_SELINUX
-               bool "SELinux" if SECURITY_SELINUX=y
-
-       config DEFAULT_SECURITY_SMACK
-               bool "Simplified Mandatory Access Control" if SECURITY_SMACK=y
-
-       config DEFAULT_SECURITY_TOMOYO
-               bool "TOMOYO" if SECURITY_TOMOYO=y
-
-       config DEFAULT_SECURITY_APPARMOR
-               bool "AppArmor" if SECURITY_APPARMOR=y
-
-       config DEFAULT_SECURITY_DAC
-               bool "Unix Discretionary Access Controls"
-
-endchoice
+         A comma-separated list of LSMs, in initialization order.
+         Any LSMs left off this list will be ignored. This can be
+         controlled at boot with the "lsm=" parameter.
 
-config DEFAULT_SECURITY
-       string
-       default "selinux" if DEFAULT_SECURITY_SELINUX
-       default "smack" if DEFAULT_SECURITY_SMACK
-       default "tomoyo" if DEFAULT_SECURITY_TOMOYO
-       default "apparmor" if DEFAULT_SECURITY_APPARMOR
-       default "" if DEFAULT_SECURITY_DAC
+         If unsure, leave this as the default.
 
 endmenu
 
index 4d2d3782ddefd3fbdd6d2984a1faa8a2bd6561ae..c598b904938f90cd24fe170e9d21ed16e6caaf46 100644 (file)
@@ -10,6 +10,7 @@ subdir-$(CONFIG_SECURITY_TOMOYO)        += tomoyo
 subdir-$(CONFIG_SECURITY_APPARMOR)     += apparmor
 subdir-$(CONFIG_SECURITY_YAMA)         += yama
 subdir-$(CONFIG_SECURITY_LOADPIN)      += loadpin
+subdir-$(CONFIG_SECURITY_SAFESETID)    += safesetid
 
 # always enable default capabilities
 obj-y                                  += commoncap.o
@@ -25,6 +26,7 @@ obj-$(CONFIG_SECURITY_TOMOYO)         += tomoyo/
 obj-$(CONFIG_SECURITY_APPARMOR)                += apparmor/
 obj-$(CONFIG_SECURITY_YAMA)            += yama/
 obj-$(CONFIG_SECURITY_LOADPIN)         += loadpin/
+obj-$(CONFIG_SECURITY_SAFESETID)       += safesetid/
 obj-$(CONFIG_CGROUP_DEVICE)            += device_cgroup.o
 
 # Object integrity file lists
index b6b68a7750ce36597ecba044f82385c8e6efc71f..3de21f46c82af95176f379c5fb4c22d721bbd82d 100644 (file)
@@ -14,22 +14,6 @@ config SECURITY_APPARMOR
 
          If you are unsure how to answer this question, answer N.
 
-config SECURITY_APPARMOR_BOOTPARAM_VALUE
-       int "AppArmor boot parameter default value"
-       depends on SECURITY_APPARMOR
-       range 0 1
-       default 1
-       help
-         This option sets the default value for the kernel parameter
-         'apparmor', which allows AppArmor to be enabled or disabled
-          at boot.  If this option is set to 0 (zero), the AppArmor
-         kernel parameter will default to 0, disabling AppArmor at
-         boot.  If this option is set to 1 (one), the AppArmor
-         kernel parameter will default to 1, enabling AppArmor at
-         boot.
-
-         If you are unsure how to answer this question, answer 1.
-
 config SECURITY_APPARMOR_HASH
        bool "Enable introspection of sha1 hashes for loaded profiles"
        depends on SECURITY_APPARMOR
index 253ef6e9d445355c0f1d3379d319a8e052541032..752f73980e3085e81daceccc269f45e09b812b3c 100644 (file)
@@ -110,13 +110,13 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
  * profile_capable - test if profile allows use of capability @cap
  * @profile: profile being enforced    (NOT NULL, NOT unconfined)
  * @cap: capability to test if allowed
- * @audit: whether an audit record should be generated
+ * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
  * @sa: audit data (MAY BE NULL indicating no auditing)
  *
  * Returns: 0 if allowed else -EPERM
  */
-static int profile_capable(struct aa_profile *profile, int cap, int audit,
-                          struct common_audit_data *sa)
+static int profile_capable(struct aa_profile *profile, int cap,
+                          unsigned int opts, struct common_audit_data *sa)
 {
        int error;
 
@@ -126,7 +126,7 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit,
        else
                error = -EPERM;
 
-       if (audit == SECURITY_CAP_NOAUDIT) {
+       if (opts & CAP_OPT_NOAUDIT) {
                if (!COMPLAIN_MODE(profile))
                        return error;
                /* audit the cap request in complain mode but note that it
@@ -142,13 +142,13 @@ static int profile_capable(struct aa_profile *profile, int cap, int audit,
  * aa_capable - test permission to use capability
  * @label: label being tested for capability (NOT NULL)
  * @cap: capability to be tested
- * @audit: whether an audit record should be generated
+ * @opts: CAP_OPT_NOAUDIT bit determines whether audit record is generated
  *
  * Look up capability in profile capability set.
  *
  * Returns: 0 on success, or else an error code.
  */
-int aa_capable(struct aa_label *label, int cap, int audit)
+int aa_capable(struct aa_label *label, int cap, unsigned int opts)
 {
        struct aa_profile *profile;
        int error = 0;
@@ -156,7 +156,7 @@ int aa_capable(struct aa_label *label, int cap, int audit)
 
        sa.u.cap = cap;
        error = fn_for_each_confined(label, profile,
-                       profile_capable(profile, cap, audit, &sa));
+                       profile_capable(profile, cap, opts, &sa));
 
        return error;
 }
index 11975ec8d5665957d145ae67f31a03bb41fc77e4..ca2dccf5b445e0ce68777320f681b87804c2c369 100644 (file)
@@ -572,7 +572,7 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
                        stack = NULL;
                        break;
                }
-               /* fall through to X_NAME */
+               /* fall through to X_NAME */
        case AA_X_NAME:
                if (xindex & AA_X_CHILD)
                        /* released by caller */
@@ -975,7 +975,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
        }
        aa_put_label(cred_label(bprm->cred));
        /* transfer reference, released when cred is freed */
-       cred_label(bprm->cred) = new;
+       set_cred_label(bprm->cred, new);
 
 done:
        aa_put_label(label);
index e0304e2aeb7ffda8fe6862c235526c22dd10db20..1b3663b6ab129d649cd7d9604ae4e4cb2a51ef7b 100644 (file)
@@ -40,7 +40,7 @@ struct aa_caps {
 
 extern struct aa_sfs_entry aa_sfs_entry_caps[];
 
-int aa_capable(struct aa_label *label, int cap, int audit);
+int aa_capable(struct aa_label *label, int cap, unsigned int opts);
 
 static inline void aa_free_cap_rules(struct aa_caps *caps)
 {
index 265ae6641a0644e84e40c7f774f4f447a1df3fc2..b9504a05fddcbbc14561431fa0d1c8c5c4cc7b5f 100644 (file)
 #include "policy_ns.h"
 #include "task.h"
 
-#define cred_label(X) ((X)->security)
+static inline struct aa_label *cred_label(const struct cred *cred)
+{
+       struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;
+
+       AA_BUG(!blob);
+       return *blob;
+}
 
+static inline void set_cred_label(const struct cred *cred,
+                                 struct aa_label *label)
+{
+       struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred;
+
+       AA_BUG(!blob);
+       *blob = label;
+}
 
 /**
  * aa_cred_raw_label - obtain cred's label
index 4c2c8ac8842f6d8c05c4480fa2680b4ba9ab75df..8be09208cf7c119ebd0f20e494c9f466fc74c15a 100644 (file)
@@ -32,7 +32,10 @@ struct path;
                                 AA_MAY_CHMOD | AA_MAY_CHOWN | AA_MAY_LOCK | \
                                 AA_EXEC_MMAP | AA_MAY_LINK)
 
-#define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
+static inline struct aa_file_ctx *file_ctx(struct file *file)
+{
+       return file->f_security + apparmor_blob_sizes.lbs_file;
+}
 
 /* struct aa_file_ctx - the AppArmor context the file was opened in
  * @lock: lock to update the ctx
index 6505e1ad9e230605885f20f1e6f8df2029866cf2..bbe9b384d71d19684e5de3e041b3596346a922ff 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/slab.h>
 #include <linux/fs.h>
+#include <linux/lsm_hooks.h>
 
 #include "match.h"
 
@@ -55,6 +56,9 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
                             size_t *ns_len);
 void aa_info_message(const char *str);
 
+/* Security blob offsets */
+extern struct lsm_blob_sizes apparmor_blob_sizes;
+
 /**
  * aa_strneq - compare null terminated @str to a non null terminated substring
  * @str: a null terminated string
index 55edaa1d83f89c68142c3a00c996a90c21f7b021..311e652324e3a9395c36d11af474b2488bc9d4c2 100644 (file)
 #ifndef __AA_TASK_H
 #define __AA_TASK_H
 
-#define task_ctx(X) ((X)->security)
+static inline struct aa_task_ctx *task_ctx(struct task_struct *task)
+{
+       return task->security + apparmor_blob_sizes.lbs_task;
+}
 
 /*
  * struct aa_task_ctx - information for current task label change
@@ -36,17 +39,6 @@ int aa_set_current_hat(struct aa_label *label, u64 token);
 int aa_restore_previous_label(u64 cookie);
 struct aa_label *aa_get_task_label(struct task_struct *task);
 
-/**
- * aa_alloc_task_ctx - allocate a new task_ctx
- * @flags: gfp flags for allocation
- *
- * Returns: allocated buffer or NULL on failure
- */
-static inline struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags)
-{
-       return kzalloc(sizeof(struct aa_task_ctx), flags);
-}
-
 /**
  * aa_free_task_ctx - free a task_ctx
  * @ctx: task_ctx to free (MAYBE NULL)
@@ -57,8 +49,6 @@ static inline void aa_free_task_ctx(struct aa_task_ctx *ctx)
                aa_put_label(ctx->nnp);
                aa_put_label(ctx->previous);
                aa_put_label(ctx->onexec);
-
-               kzfree(ctx);
        }
 }
 
index 527ea1557120ece44aa0c04d901bfa3e8d9b9422..aacd1e95cb596888fec63a00de1124092c11a188 100644 (file)
@@ -107,7 +107,8 @@ static int profile_tracer_perm(struct aa_profile *tracer,
        aad(sa)->label = &tracer->label;
        aad(sa)->peer = tracee;
        aad(sa)->request = 0;
-       aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1);
+       aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
+                                   CAP_OPT_NONE);
 
        return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
 }
index 8db1731d046ad0b55f594266472308edd0b8217e..49d664ddff444810ef9c6e8a1b0276c5ba473c53 100644 (file)
@@ -60,7 +60,7 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
 static void apparmor_cred_free(struct cred *cred)
 {
        aa_put_label(cred_label(cred));
-       cred_label(cred) = NULL;
+       set_cred_label(cred, NULL);
 }
 
 /*
@@ -68,7 +68,7 @@ static void apparmor_cred_free(struct cred *cred)
  */
 static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
-       cred_label(cred) = NULL;
+       set_cred_label(cred, NULL);
        return 0;
 }
 
@@ -78,7 +78,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
                                 gfp_t gfp)
 {
-       cred_label(new) = aa_get_newest_label(cred_label(old));
+       set_cred_label(new, aa_get_newest_label(cred_label(old)));
        return 0;
 }
 
@@ -87,26 +87,21 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
  */
 static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
 {
-       cred_label(new) = aa_get_newest_label(cred_label(old));
+       set_cred_label(new, aa_get_newest_label(cred_label(old)));
 }
 
 static void apparmor_task_free(struct task_struct *task)
 {
 
        aa_free_task_ctx(task_ctx(task));
-       task_ctx(task) = NULL;
 }
 
 static int apparmor_task_alloc(struct task_struct *task,
                               unsigned long clone_flags)
 {
-       struct aa_task_ctx *new = aa_alloc_task_ctx(GFP_KERNEL);
-
-       if (!new)
-               return -ENOMEM;
+       struct aa_task_ctx *new = task_ctx(task);
 
        aa_dup_task_ctx(new, task_ctx(current));
-       task_ctx(task) = new;
 
        return 0;
 }
@@ -177,14 +172,14 @@ static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
 }
 
 static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
-                           int cap, int audit)
+                           int cap, unsigned int opts)
 {
        struct aa_label *label;
        int error = 0;
 
        label = aa_get_newest_cred_label(cred);
        if (!unconfined(label))
-               error = aa_capable(label, cap, audit);
+               error = aa_capable(label, cap, opts);
        aa_put_label(label);
 
        return error;
@@ -434,21 +429,21 @@ static int apparmor_file_open(struct file *file)
 
 static int apparmor_file_alloc_security(struct file *file)
 {
-       int error = 0;
-
-       /* freed by apparmor_file_free_security */
+       struct aa_file_ctx *ctx = file_ctx(file);
        struct aa_label *label = begin_current_label_crit_section();
-       file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
-       if (!file_ctx(file))
-               error = -ENOMEM;
-       end_current_label_crit_section(label);
 
-       return error;
+       spin_lock_init(&ctx->lock);
+       rcu_assign_pointer(ctx->label, aa_get_label(label));
+       end_current_label_crit_section(label);
+       return 0;
 }
 
 static void apparmor_file_free_security(struct file *file)
 {
-       aa_free_file_ctx(file_ctx(file));
+       struct aa_file_ctx *ctx = file_ctx(file);
+
+       if (ctx)
+               aa_put_label(rcu_access_pointer(ctx->label));
 }
 
 static int common_file_perm(const char *op, struct file *file, u32 mask)
@@ -1151,6 +1146,15 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
 }
 #endif
 
+/*
+ * The cred blob is a pointer to, not an instance of, an aa_task_ctx.
+ */
+struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
+       .lbs_cred = sizeof(struct aa_task_ctx *),
+       .lbs_file = sizeof(struct aa_file_ctx),
+       .lbs_task = sizeof(struct aa_task_ctx),
+};
+
 static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
        LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -1333,8 +1337,8 @@ bool aa_g_paranoid_load = true;
 module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
 
 /* Boot time disable flag */
-static bool apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
-module_param_named(enabled, apparmor_enabled, bool, S_IRUGO);
+static int apparmor_enabled __lsm_ro_after_init = 1;
+module_param_named(enabled, apparmor_enabled, int, 0444);
 
 static int __init apparmor_enabled_setup(char *str)
 {
@@ -1479,14 +1483,8 @@ static int param_set_mode(const char *val, const struct kernel_param *kp)
 static int __init set_init_ctx(void)
 {
        struct cred *cred = (struct cred *)current->real_cred;
-       struct aa_task_ctx *ctx;
-
-       ctx = aa_alloc_task_ctx(GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
 
-       cred_label(cred) = aa_get_label(ns_unconfined(root_ns));
-       task_ctx(current) = ctx;
+       set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
 
        return 0;
 }
@@ -1665,12 +1663,6 @@ static int __init apparmor_init(void)
 {
        int error;
 
-       if (!apparmor_enabled || !security_module_enable("apparmor")) {
-               aa_info_message("AppArmor disabled by boot time parameter");
-               apparmor_enabled = false;
-               return 0;
-       }
-
        aa_secids_init();
 
        error = aa_setup_dfa_engine();
@@ -1731,5 +1723,8 @@ alloc_out:
 
 DEFINE_LSM(apparmor) = {
        .name = "apparmor",
+       .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+       .enabled = &apparmor_enabled,
+       .blobs = &apparmor_blob_sizes,
        .init = apparmor_init,
 };
index 95fd26d09757f2c7fb7b39d541e1aa6fdc923a5d..552ed09cb47e75829a60e202b3a9465cecefe246 100644 (file)
@@ -124,7 +124,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
         */
 
        if (label != peer &&
-           aa_capable(label, CAP_SYS_RESOURCE, SECURITY_CAP_NOAUDIT) != 0)
+           aa_capable(label, CAP_SYS_RESOURCE, CAP_OPT_NOAUDIT) != 0)
                error = fn_for_each(label, profile,
                                audit_resource(profile, resource,
                                               new_rlim->rlim_max, peer,
index c6b78a14da91842a7288e4c92e6db490284f0c4c..4551110f049694311ab5958770a94cac2331ab9b 100644 (file)
@@ -81,7 +81,7 @@ int aa_replace_current_label(struct aa_label *label)
         */
        aa_get_label(label);
        aa_put_label(cred_label(new));
-       cred_label(new) = label;
+       set_cred_label(new, label);
 
        commit_creds(new);
        return 0;
@@ -138,7 +138,7 @@ int aa_set_current_hat(struct aa_label *label, u64 token)
                return -EACCES;
        }
 
-       cred_label(new) = aa_get_newest_label(label);
+       set_cred_label(new, aa_get_newest_label(label));
        /* clear exec on switching context */
        aa_put_label(ctx->onexec);
        ctx->onexec = NULL;
@@ -172,7 +172,7 @@ int aa_restore_previous_label(u64 token)
                return -ENOMEM;
 
        aa_put_label(cred_label(new));
-       cred_label(new) = aa_get_newest_label(ctx->previous);
+       set_cred_label(new, aa_get_newest_label(ctx->previous));
        AA_BUG(!cred_label(new));
        /* clear exec && prev information when restoring to previous context */
        aa_clear_task_ctx_trans(ctx);
index 232db019f0519f6af292eb5db97d300856eb1bd9..f1d117c3d8ae634eee3d31344eb8bc5e87c95f5f 100644 (file)
@@ -57,7 +57,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
  * @cred: The credentials to use
  * @ns:  The user namespace in which we need the capability
  * @cap: The capability to check for
- * @audit: Whether to write an audit message or not
+ * @opts: Bitmask of options defined in include/linux/security.h
  *
  * Determine whether the nominated task has the specified capability amongst
  * its effective set, returning 0 if it does, -ve if it does not.
@@ -68,7 +68,7 @@ static void warn_setuid_and_fcaps_mixed(const char *fname)
  * kernel's capable() and has_capability() returns 1 for this case.
  */
 int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
-               int cap, int audit)
+               int cap, unsigned int opts)
 {
        struct user_namespace *ns = targ_ns;
 
@@ -222,12 +222,11 @@ int cap_capget(struct task_struct *target, kernel_cap_t *effective,
  */
 static inline int cap_inh_is_capped(void)
 {
-
        /* they are so limited unless the current task has the CAP_SETPCAP
         * capability
         */
        if (cap_capable(current_cred(), current_cred()->user_ns,
-                       CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
+                       CAP_SETPCAP, CAP_OPT_NONE) == 0)
                return 0;
        return 1;
 }
@@ -1208,8 +1207,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
                    || ((old->securebits & SECURE_ALL_LOCKS & ~arg2))   /*[2]*/
                    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))   /*[3]*/
                    || (cap_capable(current_cred(),
-                                   current_cred()->user_ns, CAP_SETPCAP,
-                                   SECURITY_CAP_AUDIT) != 0)           /*[4]*/
+                                   current_cred()->user_ns,
+                                   CAP_SETPCAP,
+                                   CAP_OPT_NONE) != 0)                 /*[4]*/
                        /*
                         * [1] no changing of bits that are locked
                         * [2] no unlocking of locks
@@ -1304,9 +1304,10 @@ int cap_vm_enough_memory(struct mm_struct *mm, long pages)
 {
        int cap_sys_admin = 0;
 
-       if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
-                       SECURITY_CAP_NOAUDIT) == 0)
+       if (cap_capable(current_cred(), &init_user_ns,
+                               CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) == 0)
                cap_sys_admin = 1;
+
        return cap_sys_admin;
 }
 
@@ -1325,7 +1326,7 @@ int cap_mmap_addr(unsigned long addr)
 
        if (addr < dac_mmap_min_addr) {
                ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
-                                 SECURITY_CAP_AUDIT);
+                                 CAP_OPT_NONE);
                /* set PF_SUPERPRIV if it turns out we allow the low mmap */
                if (ret == 0)
                        current->flags |= PF_SUPERPRIV;
@@ -1362,10 +1363,17 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory),
 };
 
-void __init capability_add_hooks(void)
+static int __init capability_init(void)
 {
        security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks),
                                "capability");
+       return 0;
 }
 
+DEFINE_LSM(capability) = {
+       .name = "capability",
+       .order = LSM_ORDER_FIRST,
+       .init = capability_init,
+};
+
 #endif /* CONFIG_SECURITY */
index a2baa85ea2f57d8a72d8bc872716e0ca987c3550..5fb7127bbe68e154abee6039036482b14c1ea77a 100644 (file)
@@ -114,6 +114,7 @@ static void ima_set_cache_status(struct integrity_iint_cache *iint,
                break;
        case CREDS_CHECK:
                iint->ima_creds_status = status;
+               break;
        case FILE_CHECK:
        case POST_SETATTR:
                iint->ima_file_status = status;
index 8bc8a1c8cb3f8cc3cf03fc3255d568438baa580f..122797023bdb842774a8f23319ad87cae8ef2cf1 100644 (file)
@@ -938,10 +938,12 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                case Opt_uid_gt:
                case Opt_euid_gt:
                        entry->uid_op = &uid_gt;
+                       /* fall through */
                case Opt_uid_lt:
                case Opt_euid_lt:
                        if ((token == Opt_uid_lt) || (token == Opt_euid_lt))
                                entry->uid_op = &uid_lt;
+                       /* fall through */
                case Opt_uid_eq:
                case Opt_euid_eq:
                        uid_token = (token == Opt_uid_eq) ||
@@ -970,9 +972,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
                        break;
                case Opt_fowner_gt:
                        entry->fowner_op = &uid_gt;
+                       /* fall through */
                case Opt_fowner_lt:
                        if (token == Opt_fowner_lt)
                                entry->fowner_op = &uid_lt;
+                       /* fall through */
                case Opt_fowner_eq:
                        ima_log_string_op(ab, "fowner", args[0].from,
                                          entry->fowner_op);
index 43752002c2223ca0315237b3dc2bf5df9ac5c4c0..513b457ae900ea00cff17247f324d8b966d98246 100644 (file)
@@ -83,6 +83,7 @@ static void ima_show_template_data_ascii(struct seq_file *m,
                /* skip ':' and '\0' */
                buf_ptr += 2;
                buflen -= buf_ptr - field_data->data;
+               /* fall through */
        case DATA_FMT_DIGEST:
        case DATA_FMT_HEX:
                if (!buflen)
index 7bbe03593e581116c0a9678a9e50788fdbac80ed..3e4053a217c326bc92f7c9488293bd2f45f2b974 100644 (file)
@@ -1752,7 +1752,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
                        return -EINVAL;
                return keyctl_pkey_query((key_serial_t)arg2,
                                         (const char __user *)arg4,
-                                        (struct keyctl_pkey_query *)arg5);
+                                        (struct keyctl_pkey_query __user *)arg5);
 
        case KEYCTL_PKEY_ENCRYPT:
        case KEYCTL_PKEY_DECRYPT:
index f81372f53dd706ba966d89c1dffb9ab1fe1b63e7..e14f09e3a4b027376bcf6f78f1464a4374cb4550 100644 (file)
@@ -246,6 +246,7 @@ static unsigned long keyring_get_key_chunk(const void *data, int level)
                                    (ASSOC_ARRAY_KEY_CHUNK_SIZE - 8));
                n--;
                offset = 1;
+               /* fall through */
        default:
                offset += sizeof(chunk) - 1;
                offset += (level - 3) * sizeof(chunk);
index 0e0b9ccad2f882f8f62540da055740f88383e2d4..9320424c4a462b751c5a09e8e67240d709f6413d 100644 (file)
@@ -380,6 +380,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
                case -EAGAIN: /* no key */
                        if (ret)
                                break;
+                       /* fall through */
                case -ENOKEY: /* negative key */
                        ret = key_ref;
                        break;
@@ -404,6 +405,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
                case -EAGAIN: /* no key */
                        if (ret)
                                break;
+                       /* fall through */
                case -ENOKEY: /* negative key */
                        ret = key_ref;
                        break;
@@ -424,6 +426,7 @@ key_ref_t search_my_process_keyrings(struct keyring_search_context *ctx)
                case -EAGAIN: /* no key */
                        if (ret)
                                break;
+                       /* fall through */
                case -ENOKEY: /* negative key */
                        ret = key_ref;
                        break;
index 7a0c6b666ff03a5e59e979a70fd14ed808b46861..2f17d84d46f1a52df1dad31d2e818358055672fc 100644 (file)
@@ -273,16 +273,19 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
                                }
                        }
 
+                       /* fall through */
                case KEY_REQKEY_DEFL_THREAD_KEYRING:
                        dest_keyring = key_get(cred->thread_keyring);
                        if (dest_keyring)
                                break;
 
+                       /* fall through */
                case KEY_REQKEY_DEFL_PROCESS_KEYRING:
                        dest_keyring = key_get(cred->process_keyring);
                        if (dest_keyring)
                                break;
 
+                       /* fall through */
                case KEY_REQKEY_DEFL_SESSION_KEYRING:
                        rcu_read_lock();
                        dest_keyring = key_get(
@@ -292,6 +295,7 @@ static int construct_get_dest_keyring(struct key **_dest_keyring)
                        if (dest_keyring)
                                break;
 
+                       /* fall through */
                case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
                        dest_keyring =
                                key_get(cred->user->session_keyring);
index 48f39631b370a45677f166f8f746b8918c5dfe83..055fb0a6416932c89d7933514f95993bf46b8f68 100644 (file)
@@ -187,13 +187,19 @@ static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(kernel_load_data, loadpin_load_data),
 };
 
-void __init loadpin_add_hooks(void)
+static int __init loadpin_init(void)
 {
        pr_info("ready to pin (currently %senforcing)\n",
                enforce ? "" : "not ");
        security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin");
+       return 0;
 }
 
+DEFINE_LSM(loadpin) = {
+       .name = "loadpin",
+       .init = loadpin_init,
+};
+
 /* Should not be mutable after boot, so not listed in sysfs (perm == 0). */
 module_param(enforce, int, 0);
 MODULE_PARM_DESC(enforce, "Enforce module/firmware pinning");
diff --git a/security/safesetid/Kconfig b/security/safesetid/Kconfig
new file mode 100644 (file)
index 0000000..4f415c4
--- /dev/null
@@ -0,0 +1,14 @@
+config SECURITY_SAFESETID
+        bool "Gate setid transitions to limit CAP_SET{U/G}ID capabilities"
+        depends on SECURITY
+        select SECURITYFS
+        default n
+        help
+          SafeSetID is an LSM module that gates the setid family of syscalls to
+          restrict UID/GID transitions from a given UID/GID to only those
+          approved by a system-wide whitelist. These restrictions also prohibit
+          the given UIDs/GIDs from obtaining auxiliary privileges associated
+          with CAP_SET{U/G}ID, such as allowing a user to set up user namespace
+          UID mappings.
+
+          If you are unsure how to answer this question, answer N.
diff --git a/security/safesetid/Makefile b/security/safesetid/Makefile
new file mode 100644 (file)
index 0000000..6b06603
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the safesetid LSM.
+#
+
+obj-$(CONFIG_SECURITY_SAFESETID) := safesetid.o
+safesetid-y := lsm.o securityfs.o
diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c
new file mode 100644 (file)
index 0000000..cecd38e
--- /dev/null
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SafeSetID Linux Security Module
+ *
+ * Author: Micah Morton <mortonm@chromium.org>
+ *
+ * Copyright (C) 2018 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#define pr_fmt(fmt) "SafeSetID: " fmt
+
+#include <linux/hashtable.h>
+#include <linux/lsm_hooks.h>
+#include <linux/module.h>
+#include <linux/ptrace.h>
+#include <linux/sched/task_stack.h>
+#include <linux/security.h>
+
+/* Flag indicating whether initialization completed */
+int safesetid_initialized;
+
+#define NUM_BITS 8 /* 128 buckets in hash table */
+
+static DEFINE_HASHTABLE(safesetid_whitelist_hashtable, NUM_BITS);
+
+/*
+ * Hash table entry to store safesetid policy signifying that 'parent' user
+ * can setid to 'child' user.
+ */
+struct entry {
+       struct hlist_node next;
+       struct hlist_node dlist; /* for deletion cleanup */
+       uint64_t parent_kuid;
+       uint64_t child_kuid;
+};
+
+static DEFINE_SPINLOCK(safesetid_whitelist_hashtable_spinlock);
+
+static bool check_setuid_policy_hashtable_key(kuid_t parent)
+{
+       struct entry *entry;
+
+       rcu_read_lock();
+       hash_for_each_possible_rcu(safesetid_whitelist_hashtable,
+                                  entry, next, __kuid_val(parent)) {
+               if (entry->parent_kuid == __kuid_val(parent)) {
+                       rcu_read_unlock();
+                       return true;
+               }
+       }
+       rcu_read_unlock();
+
+       return false;
+}
+
+static bool check_setuid_policy_hashtable_key_value(kuid_t parent,
+                                                   kuid_t child)
+{
+       struct entry *entry;
+
+       rcu_read_lock();
+       hash_for_each_possible_rcu(safesetid_whitelist_hashtable,
+                                  entry, next, __kuid_val(parent)) {
+               if (entry->parent_kuid == __kuid_val(parent) &&
+                   entry->child_kuid == __kuid_val(child)) {
+                       rcu_read_unlock();
+                       return true;
+               }
+       }
+       rcu_read_unlock();
+
+       return false;
+}
+
+static int safesetid_security_capable(const struct cred *cred,
+                                     struct user_namespace *ns,
+                                     int cap,
+                                     unsigned int opts)
+{
+       if (cap == CAP_SETUID &&
+           check_setuid_policy_hashtable_key(cred->uid)) {
+               if (!(opts & CAP_OPT_INSETID)) {
+                       /*
+                        * Deny if we're not in a set*uid() syscall to avoid
+                        * giving powers gated by CAP_SETUID that are related
+                        * to functionality other than calling set*uid() (e.g.
+                        * allowing user to set up userns uid mappings).
+                        */
+                       pr_warn("Operation requires CAP_SETUID, which is not available to UID %u for operations besides approved set*uid transitions",
+                               __kuid_val(cred->uid));
+                       return -1;
+               }
+       }
+       return 0;
+}
+
+static int check_uid_transition(kuid_t parent, kuid_t child)
+{
+       if (check_setuid_policy_hashtable_key_value(parent, child))
+               return 0;
+       pr_warn("UID transition (%d -> %d) blocked",
+               __kuid_val(parent),
+               __kuid_val(child));
+       /*
+        * Kill this process to avoid potential security vulnerabilities
+        * that could arise from a missing whitelist entry preventing a
+        * privileged process from dropping to a lesser-privileged one.
+        */
+       force_sig(SIGKILL, current);
+       return -EACCES;
+}
+
+/*
+ * Check whether there is either an exception for user under old cred struct to
+ * set*uid to user under new cred struct, or the UID transition is allowed (by
+ * Linux set*uid rules) even without CAP_SETUID.
+ */
+static int safesetid_task_fix_setuid(struct cred *new,
+                                    const struct cred *old,
+                                    int flags)
+{
+
+       /* Do nothing if there are no setuid restrictions for this UID. */
+       if (!check_setuid_policy_hashtable_key(old->uid))
+               return 0;
+
+       switch (flags) {
+       case LSM_SETID_RE:
+               /*
+                * Users for which setuid restrictions exist can only set the
+                * real UID to the real UID or the effective UID, unless an
+                * explicit whitelist policy allows the transition.
+                */
+               if (!uid_eq(old->uid, new->uid) &&
+                       !uid_eq(old->euid, new->uid)) {
+                       return check_uid_transition(old->uid, new->uid);
+               }
+               /*
+                * Users for which setuid restrictions exist can only set the
+                * effective UID to the real UID, the effective UID, or the
+                * saved set-UID, unless an explicit whitelist policy allows
+                * the transition.
+                */
+               if (!uid_eq(old->uid, new->euid) &&
+                       !uid_eq(old->euid, new->euid) &&
+                       !uid_eq(old->suid, new->euid)) {
+                       return check_uid_transition(old->euid, new->euid);
+               }
+               break;
+       case LSM_SETID_ID:
+               /*
+                * Users for which setuid restrictions exist cannot change the
+                * real UID or saved set-UID unless an explicit whitelist
+                * policy allows the transition.
+                */
+               if (!uid_eq(old->uid, new->uid))
+                       return check_uid_transition(old->uid, new->uid);
+               if (!uid_eq(old->suid, new->suid))
+                       return check_uid_transition(old->suid, new->suid);
+               break;
+       case LSM_SETID_RES:
+               /*
+                * Users for which setuid restrictions exist cannot change the
+                * real UID, effective UID, or saved set-UID to anything but
+                * one of: the current real UID, the current effective UID or
+                * the current saved set-user-ID unless an explicit whitelist
+                * policy allows the transition.
+                */
+               if (!uid_eq(new->uid, old->uid) &&
+                       !uid_eq(new->uid, old->euid) &&
+                       !uid_eq(new->uid, old->suid)) {
+                       return check_uid_transition(old->uid, new->uid);
+               }
+               if (!uid_eq(new->euid, old->uid) &&
+                       !uid_eq(new->euid, old->euid) &&
+                       !uid_eq(new->euid, old->suid)) {
+                       return check_uid_transition(old->euid, new->euid);
+               }
+               if (!uid_eq(new->suid, old->uid) &&
+                       !uid_eq(new->suid, old->euid) &&
+                       !uid_eq(new->suid, old->suid)) {
+                       return check_uid_transition(old->suid, new->suid);
+               }
+               break;
+       case LSM_SETID_FS:
+               /*
+                * Users for which setuid restrictions exist cannot change the
+                * filesystem UID to anything but one of: the current real UID,
+                * the current effective UID or the current saved set-UID
+                * unless an explicit whitelist policy allows the transition.
+                */
+               if (!uid_eq(new->fsuid, old->uid)  &&
+                       !uid_eq(new->fsuid, old->euid)  &&
+                       !uid_eq(new->fsuid, old->suid) &&
+                       !uid_eq(new->fsuid, old->fsuid)) {
+                       return check_uid_transition(old->fsuid, new->fsuid);
+               }
+               break;
+       default:
+               pr_warn("Unknown setid state %d\n", flags);
+               force_sig(SIGKILL, current);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int add_safesetid_whitelist_entry(kuid_t parent, kuid_t child)
+{
+       struct entry *new;
+
+       /* Return if entry already exists */
+       if (check_setuid_policy_hashtable_key_value(parent, child))
+               return 0;
+
+       new = kzalloc(sizeof(struct entry), GFP_KERNEL);
+       if (!new)
+               return -ENOMEM;
+       new->parent_kuid = __kuid_val(parent);
+       new->child_kuid = __kuid_val(child);
+       spin_lock(&safesetid_whitelist_hashtable_spinlock);
+       hash_add_rcu(safesetid_whitelist_hashtable,
+                    &new->next,
+                    __kuid_val(parent));
+       spin_unlock(&safesetid_whitelist_hashtable_spinlock);
+       return 0;
+}
+
+void flush_safesetid_whitelist_entries(void)
+{
+       struct entry *entry;
+       struct hlist_node *hlist_node;
+       unsigned int bkt_loop_cursor;
+       HLIST_HEAD(free_list);
+
+       /*
+        * Could probably use hash_for_each_rcu here instead, but this should
+        * be fine as well.
+        */
+       spin_lock(&safesetid_whitelist_hashtable_spinlock);
+       hash_for_each_safe(safesetid_whitelist_hashtable, bkt_loop_cursor,
+                          hlist_node, entry, next) {
+               hash_del_rcu(&entry->next);
+               hlist_add_head(&entry->dlist, &free_list);
+       }
+       spin_unlock(&safesetid_whitelist_hashtable_spinlock);
+       synchronize_rcu();
+       hlist_for_each_entry_safe(entry, hlist_node, &free_list, dlist) {
+               hlist_del(&entry->dlist);
+               kfree(entry);
+       }
+}
+
+static struct security_hook_list safesetid_security_hooks[] = {
+       LSM_HOOK_INIT(task_fix_setuid, safesetid_task_fix_setuid),
+       LSM_HOOK_INIT(capable, safesetid_security_capable)
+};
+
+static int __init safesetid_security_init(void)
+{
+       security_add_hooks(safesetid_security_hooks,
+                          ARRAY_SIZE(safesetid_security_hooks), "safesetid");
+
+       /* Report that SafeSetID successfully initialized */
+       safesetid_initialized = 1;
+
+       return 0;
+}
+
+DEFINE_LSM(safesetid_security_init) = {
+       .init = safesetid_security_init,
+       .name = "safesetid",
+};
diff --git a/security/safesetid/lsm.h b/security/safesetid/lsm.h
new file mode 100644 (file)
index 0000000..c1ea3c2
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SafeSetID Linux Security Module
+ *
+ * Author: Micah Morton <mortonm@chromium.org>
+ *
+ * Copyright (C) 2018 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef _SAFESETID_H
+#define _SAFESETID_H
+
+#include <linux/types.h>
+
+/* Flag indicating whether initialization completed */
+extern int safesetid_initialized;
+
+/* Function type. */
+enum safesetid_whitelist_file_write_type {
+       SAFESETID_WHITELIST_ADD, /* Add whitelist policy. */
+       SAFESETID_WHITELIST_FLUSH, /* Flush whitelist policies. */
+};
+
+/* Add entry to safesetid whitelist to allow 'parent' to setid to 'child'. */
+int add_safesetid_whitelist_entry(kuid_t parent, kuid_t child);
+
+void flush_safesetid_whitelist_entries(void);
+
+#endif /* _SAFESETID_H */
diff --git a/security/safesetid/securityfs.c b/security/safesetid/securityfs.c
new file mode 100644 (file)
index 0000000..2c6c829
--- /dev/null
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SafeSetID Linux Security Module
+ *
+ * Author: Micah Morton <mortonm@chromium.org>
+ *
+ * Copyright (C) 2018 The Chromium OS Authors.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/security.h>
+#include <linux/cred.h>
+
+#include "lsm.h"
+
+static struct dentry *safesetid_policy_dir;
+
+struct safesetid_file_entry {
+       const char *name;
+       enum safesetid_whitelist_file_write_type type;
+       struct dentry *dentry;
+};
+
+static struct safesetid_file_entry safesetid_files[] = {
+       {.name = "add_whitelist_policy",
+        .type = SAFESETID_WHITELIST_ADD},
+       {.name = "flush_whitelist_policies",
+        .type = SAFESETID_WHITELIST_FLUSH},
+};
+
+/*
+ * In the case the input buffer contains one or more invalid UIDs, the kuid_t
+ * variables pointed to by 'parent' and 'child' will get updated but this
+ * function will return an error.
+ */
+static int parse_safesetid_whitelist_policy(const char __user *buf,
+                                           size_t len,
+                                           kuid_t *parent,
+                                           kuid_t *child)
+{
+       char *kern_buf;
+       char *parent_buf;
+       char *child_buf;
+       const char separator[] = ":";
+       int ret;
+       size_t first_substring_length;
+       long parsed_parent;
+       long parsed_child;
+
+       /* Duplicate string from user memory and NULL-terminate */
+       kern_buf = memdup_user_nul(buf, len);
+       if (IS_ERR(kern_buf))
+               return PTR_ERR(kern_buf);
+
+       /*
+        * Format of |buf| string should be <UID>:<UID>.
+        * Find location of ":" in kern_buf (copied from |buf|).
+        */
+       first_substring_length = strcspn(kern_buf, separator);
+       if (first_substring_length == 0 || first_substring_length == len) {
+               ret = -EINVAL;
+               goto free_kern;
+       }
+
+       parent_buf = kmemdup_nul(kern_buf, first_substring_length, GFP_KERNEL);
+       if (!parent_buf) {
+               ret = -ENOMEM;
+               goto free_kern;
+       }
+
+       ret = kstrtol(parent_buf, 0, &parsed_parent);
+       if (ret)
+               goto free_both;
+
+       child_buf = kern_buf + first_substring_length + 1;
+       ret = kstrtol(child_buf, 0, &parsed_child);
+       if (ret)
+               goto free_both;
+
+       *parent = make_kuid(current_user_ns(), parsed_parent);
+       if (!uid_valid(*parent)) {
+               ret = -EINVAL;
+               goto free_both;
+       }
+
+       *child = make_kuid(current_user_ns(), parsed_child);
+       if (!uid_valid(*child)) {
+               ret = -EINVAL;
+               goto free_both;
+       }
+
+free_both:
+       kfree(parent_buf);
+free_kern:
+       kfree(kern_buf);
+       return ret;
+}
+
+static ssize_t safesetid_file_write(struct file *file,
+                                   const char __user *buf,
+                                   size_t len,
+                                   loff_t *ppos)
+{
+       struct safesetid_file_entry *file_entry =
+               file->f_inode->i_private;
+       kuid_t parent;
+       kuid_t child;
+       int ret;
+
+       if (!ns_capable(current_user_ns(), CAP_MAC_ADMIN))
+               return -EPERM;
+
+       if (*ppos != 0)
+               return -EINVAL;
+
+       switch (file_entry->type) {
+       case SAFESETID_WHITELIST_FLUSH:
+               flush_safesetid_whitelist_entries();
+               break;
+       case SAFESETID_WHITELIST_ADD:
+               ret = parse_safesetid_whitelist_policy(buf, len, &parent,
+                                                                &child);
+               if (ret)
+                       return ret;
+
+               ret = add_safesetid_whitelist_entry(parent, child);
+               if (ret)
+                       return ret;
+               break;
+       default:
+               pr_warn("Unknown securityfs file %d\n", file_entry->type);
+               break;
+       }
+
+       /* Return len on success so caller won't keep trying to write */
+       return len;
+}
+
+static const struct file_operations safesetid_file_fops = {
+       .write = safesetid_file_write,
+};
+
+static void safesetid_shutdown_securityfs(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(safesetid_files); ++i) {
+               struct safesetid_file_entry *entry =
+                       &safesetid_files[i];
+               securityfs_remove(entry->dentry);
+               entry->dentry = NULL;
+       }
+
+       securityfs_remove(safesetid_policy_dir);
+       safesetid_policy_dir = NULL;
+}
+
+static int __init safesetid_init_securityfs(void)
+{
+       int i;
+       int ret;
+
+       if (!safesetid_initialized)
+               return 0;
+
+       safesetid_policy_dir = securityfs_create_dir("safesetid", NULL);
+       if (IS_ERR(safesetid_policy_dir)) {
+               ret = PTR_ERR(safesetid_policy_dir);
+               goto error;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(safesetid_files); ++i) {
+               struct safesetid_file_entry *entry =
+                       &safesetid_files[i];
+               entry->dentry = securityfs_create_file(
+                       entry->name, 0200, safesetid_policy_dir,
+                       entry, &safesetid_file_fops);
+               if (IS_ERR(entry->dentry)) {
+                       ret = PTR_ERR(entry->dentry);
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       safesetid_shutdown_securityfs();
+       return ret;
+}
+fs_initcall(safesetid_init_securityfs);
index 55bc49027ba97c13c06b4c1076656cef349cee3c..ed9b8cbf21cf735b43208e945d96b1f065bbd4e9 100644 (file)
 #include <linux/personality.h>
 #include <linux/backing-dev.h>
 #include <linux/string.h>
+#include <linux/msg.h>
 #include <net/flow.h>
 
 #define MAX_LSM_EVM_XATTR      2
 
-/* Maximum number of letters for an LSM name string */
-#define SECURITY_NAME_MAX      10
+/* How many LSMs were built into the kernel? */
+#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
 
 struct security_hook_heads security_hook_heads __lsm_ro_after_init;
 static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
 
+static struct kmem_cache *lsm_file_cache;
+static struct kmem_cache *lsm_inode_cache;
+
 char *lsm_names;
+static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;
+
 /* Boot-time LSM user choice */
-static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
-       CONFIG_DEFAULT_SECURITY;
+static __initdata const char *chosen_lsm_order;
+static __initdata const char *chosen_major_lsm;
+
+static __initconst const char * const builtin_lsm_order = CONFIG_LSM;
+
+/* Ordered list of LSMs to initialize. */
+static __initdata struct lsm_info **ordered_lsms;
+static __initdata struct lsm_info *exclusive;
 
 static __initdata bool debug;
 #define init_debug(...)                                                \
@@ -52,18 +64,269 @@ static __initdata bool debug;
                        pr_info(__VA_ARGS__);                   \
        } while (0)
 
-static void __init major_lsm_init(void)
+static bool __init is_enabled(struct lsm_info *lsm)
 {
-       struct lsm_info *lsm;
-       int ret;
+       if (!lsm->enabled)
+               return false;
+
+       return *lsm->enabled;
+}
+
+/* Mark an LSM's enabled flag. */
+static int lsm_enabled_true __initdata = 1;
+static int lsm_enabled_false __initdata = 0;
+static void __init set_enabled(struct lsm_info *lsm, bool enabled)
+{
+       /*
+        * When an LSM hasn't configured an enable variable, we can use
+        * a hard-coded location for storing the default enabled state.
+        */
+       if (!lsm->enabled) {
+               if (enabled)
+                       lsm->enabled = &lsm_enabled_true;
+               else
+                       lsm->enabled = &lsm_enabled_false;
+       } else if (lsm->enabled == &lsm_enabled_true) {
+               if (!enabled)
+                       lsm->enabled = &lsm_enabled_false;
+       } else if (lsm->enabled == &lsm_enabled_false) {
+               if (enabled)
+                       lsm->enabled = &lsm_enabled_true;
+       } else {
+               *lsm->enabled = enabled;
+       }
+}
+
+/* Is an LSM already listed in the ordered LSMs list? */
+static bool __init exists_ordered_lsm(struct lsm_info *lsm)
+{
+       struct lsm_info **check;
+
+       for (check = ordered_lsms; *check; check++)
+               if (*check == lsm)
+                       return true;
+
+       return false;
+}
+
+/* Append an LSM to the list of ordered LSMs to initialize. */
+static int last_lsm __initdata;
+static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
+{
+       /* Ignore duplicate selections. */
+       if (exists_ordered_lsm(lsm))
+               return;
+
+       if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM slots!?\n", from))
+               return;
+
+       /* Enable this LSM, if it is not already set. */
+       if (!lsm->enabled)
+               lsm->enabled = &lsm_enabled_true;
+       ordered_lsms[last_lsm++] = lsm;
+
+       init_debug("%s ordering: %s (%sabled)\n", from, lsm->name,
+                  is_enabled(lsm) ? "en" : "dis");
+}
+
+/* Is an LSM allowed to be initialized? */
+static bool __init lsm_allowed(struct lsm_info *lsm)
+{
+       /* Skip if the LSM is disabled. */
+       if (!is_enabled(lsm))
+               return false;
+
+       /* Not allowed if another exclusive LSM already initialized. */
+       if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+               init_debug("exclusive disabled: %s\n", lsm->name);
+               return false;
+       }
+
+       return true;
+}
+
+static void __init lsm_set_blob_size(int *need, int *lbs)
+{
+       int offset;
+
+       if (*need > 0) {
+               offset = *lbs;
+               *lbs += *need;
+               *need = offset;
+       }
+}
+
+static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+{
+       if (!needed)
+               return;
+
+       lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+       lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
+       /*
+        * The inode blob gets an rcu_head in addition to
+        * what the modules might need.
+        */
+       if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
+               blob_sizes.lbs_inode = sizeof(struct rcu_head);
+       lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+       lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+       lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+       lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+}
+
+/* Prepare LSM for initialization. */
+static void __init prepare_lsm(struct lsm_info *lsm)
+{
+       int enabled = lsm_allowed(lsm);
+
+       /* Record enablement (to handle any following exclusive LSMs). */
+       set_enabled(lsm, enabled);
+
+       /* If enabled, do pre-initialization work. */
+       if (enabled) {
+               if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+                       exclusive = lsm;
+                       init_debug("exclusive chosen: %s\n", lsm->name);
+               }
+
+               lsm_set_blob_sizes(lsm->blobs);
+       }
+}
+
+/* Initialize a given LSM, if it is enabled. */
+static void __init initialize_lsm(struct lsm_info *lsm)
+{
+       if (is_enabled(lsm)) {
+               int ret;
 
-       for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
                init_debug("initializing %s\n", lsm->name);
                ret = lsm->init();
                WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
        }
 }
 
+/* Populate ordered LSMs list from comma-separated LSM name list. */
+static void __init ordered_lsm_parse(const char *order, const char *origin)
+{
+       struct lsm_info *lsm;
+       char *sep, *name, *next;
+
+       /* LSM_ORDER_FIRST is always first. */
+       for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+               if (lsm->order == LSM_ORDER_FIRST)
+                       append_ordered_lsm(lsm, "first");
+       }
+
+       /* Process "security=", if given. */
+       if (chosen_major_lsm) {
+               struct lsm_info *major;
+
+               /*
+                * To match the original "security=" behavior, this
+                * explicitly does NOT fallback to another Legacy Major
+                * if the selected one was separately disabled: disable
+                * all non-matching Legacy Major LSMs.
+                */
+               for (major = __start_lsm_info; major < __end_lsm_info;
+                    major++) {
+                       if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
+                           strcmp(major->name, chosen_major_lsm) != 0) {
+                               set_enabled(major, false);
+                               init_debug("security=%s disabled: %s\n",
+                                          chosen_major_lsm, major->name);
+                       }
+               }
+       }
+
+       sep = kstrdup(order, GFP_KERNEL);
+       next = sep;
+       /* Walk the list, looking for matching LSMs. */
+       while ((name = strsep(&next, ",")) != NULL) {
+               bool found = false;
+
+               for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+                       if (lsm->order == LSM_ORDER_MUTABLE &&
+                           strcmp(lsm->name, name) == 0) {
+                               append_ordered_lsm(lsm, origin);
+                               found = true;
+                       }
+               }
+
+               if (!found)
+                       init_debug("%s ignored: %s\n", origin, name);
+       }
+
+       /* Process "security=", if given. */
+       if (chosen_major_lsm) {
+               for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+                       if (exists_ordered_lsm(lsm))
+                               continue;
+                       if (strcmp(lsm->name, chosen_major_lsm) == 0)
+                               append_ordered_lsm(lsm, "security=");
+               }
+       }
+
+       /* Disable all LSMs not in the ordered list. */
+       for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+               if (exists_ordered_lsm(lsm))
+                       continue;
+               set_enabled(lsm, false);
+               init_debug("%s disabled: %s\n", origin, lsm->name);
+       }
+
+       kfree(sep);
+}
+
+static void __init lsm_early_cred(struct cred *cred);
+static void __init lsm_early_task(struct task_struct *task);
+
+static void __init ordered_lsm_init(void)
+{
+       struct lsm_info **lsm;
+
+       ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms),
+                               GFP_KERNEL);
+
+       if (chosen_lsm_order) {
+               if (chosen_major_lsm) {
+                       pr_info("security= is ignored because it is superseded by lsm=\n");
+                       chosen_major_lsm = NULL;
+               }
+               ordered_lsm_parse(chosen_lsm_order, "cmdline");
+       } else
+               ordered_lsm_parse(builtin_lsm_order, "builtin");
+
+       for (lsm = ordered_lsms; *lsm; lsm++)
+               prepare_lsm(*lsm);
+
+       init_debug("cred blob size     = %d\n", blob_sizes.lbs_cred);
+       init_debug("file blob size     = %d\n", blob_sizes.lbs_file);
+       init_debug("inode blob size    = %d\n", blob_sizes.lbs_inode);
+       init_debug("ipc blob size      = %d\n", blob_sizes.lbs_ipc);
+       init_debug("msg_msg blob size  = %d\n", blob_sizes.lbs_msg_msg);
+       init_debug("task blob size     = %d\n", blob_sizes.lbs_task);
+
+       /*
+        * Create any kmem_caches needed for blobs
+        */
+       if (blob_sizes.lbs_file)
+               lsm_file_cache = kmem_cache_create("lsm_file_cache",
+                                                  blob_sizes.lbs_file, 0,
+                                                  SLAB_PANIC, NULL);
+       if (blob_sizes.lbs_inode)
+               lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+                                                   blob_sizes.lbs_inode, 0,
+                                                   SLAB_PANIC, NULL);
+
+       lsm_early_cred((struct cred *) current->cred);
+       lsm_early_task(current);
+       for (lsm = ordered_lsms; *lsm; lsm++)
+               initialize_lsm(*lsm);
+
+       kfree(ordered_lsms);
+}
+
 /**
  * security_init - initializes the security framework
  *
@@ -80,28 +343,27 @@ int __init security_init(void)
             i++)
                INIT_HLIST_HEAD(&list[i]);
 
-       /*
-        * Load minor LSMs, with the capability module always first.
-        */
-       capability_add_hooks();
-       yama_add_hooks();
-       loadpin_add_hooks();
-
-       /*
-        * Load all the remaining security modules.
-        */
-       major_lsm_init();
+       /* Load LSMs in specified order. */
+       ordered_lsm_init();
 
        return 0;
 }
 
 /* Save user chosen LSM */
-static int __init choose_lsm(char *str)
+static int __init choose_major_lsm(char *str)
+{
+       chosen_major_lsm = str;
+       return 1;
+}
+__setup("security=", choose_major_lsm);
+
+/* Explicitly choose LSM initialization order. */
+static int __init choose_lsm_order(char *str)
 {
-       strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+       chosen_lsm_order = str;
        return 1;
 }
-__setup("security=", choose_lsm);
+__setup("lsm=", choose_lsm_order);
 
 /* Enable LSM order debugging. */
 static int __init enable_debug(char *str)
@@ -147,29 +409,6 @@ static int lsm_append(char *new, char **result)
        return 0;
 }
 
-/**
- * security_module_enable - Load given security module on boot ?
- * @module: the name of the module
- *
- * Each LSM must pass this method before registering its own operations
- * to avoid security registration races. This method may also be used
- * to check if your LSM is currently loaded during kernel initialization.
- *
- * Returns:
- *
- * true if:
- *
- * - The passed LSM is the one chosen by user at boot time,
- * - or the passed LSM is configured as the default and the user did not
- *   choose an alternate LSM at boot time.
- *
- * Otherwise, return false.
- */
-int __init security_module_enable(const char *module)
-{
-       return !strcmp(module, chosen_lsm);
-}
-
 /**
  * security_add_hooks - Add a modules hooks to the hook lists.
  * @hooks: the hooks to add
@@ -209,6 +448,161 @@ int unregister_lsm_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_lsm_notifier);
 
+/**
+ * lsm_cred_alloc - allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ * @gfp: allocation type
+ *
+ * Allocate the cred blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+{
+       if (blob_sizes.lbs_cred == 0) {
+               cred->security = NULL;
+               return 0;
+       }
+
+       cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
+       if (cred->security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_early_cred - during initialization allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ *
+ * Allocate the cred blob for all the modules
+ */
+static void __init lsm_early_cred(struct cred *cred)
+{
+       int rc = lsm_cred_alloc(cred, GFP_KERNEL);
+
+       if (rc)
+               panic("%s: Early cred alloc failed.\n", __func__);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_file_alloc(struct file *file)
+{
+       if (!lsm_file_cache) {
+               file->f_security = NULL;
+               return 0;
+       }
+
+       file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
+       if (file->f_security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_inode_alloc - allocate a composite inode blob
+ * @inode: the inode that needs a blob
+ *
+ * Allocate the inode blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_inode_alloc(struct inode *inode)
+{
+       if (!lsm_inode_cache) {
+               inode->i_security = NULL;
+               return 0;
+       }
+
+       inode->i_security = kmem_cache_zalloc(lsm_inode_cache, GFP_NOFS);
+       if (inode->i_security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_task_alloc - allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_task_alloc(struct task_struct *task)
+{
+       if (blob_sizes.lbs_task == 0) {
+               task->security = NULL;
+               return 0;
+       }
+
+       task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
+       if (task->security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_ipc_alloc - allocate a composite ipc blob
+ * @kip: the ipc that needs a blob
+ *
+ * Allocate the ipc blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_ipc_alloc(struct kern_ipc_perm *kip)
+{
+       if (blob_sizes.lbs_ipc == 0) {
+               kip->security = NULL;
+               return 0;
+       }
+
+       kip->security = kzalloc(blob_sizes.lbs_ipc, GFP_KERNEL);
+       if (kip->security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_msg_msg_alloc - allocate a composite msg_msg blob
+ * @mp: the msg_msg that needs a blob
+ *
+ * Allocate the ipc blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_msg_msg_alloc(struct msg_msg *mp)
+{
+       if (blob_sizes.lbs_msg_msg == 0) {
+               mp->security = NULL;
+               return 0;
+       }
+
+       mp->security = kzalloc(blob_sizes.lbs_msg_msg, GFP_KERNEL);
+       if (mp->security == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+/**
+ * lsm_early_task - during initialization allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ */
+static void __init lsm_early_task(struct task_struct *task)
+{
+       int rc = lsm_task_alloc(task);
+
+       if (rc)
+               panic("%s: Early task alloc failed.\n", __func__);
+}
+
 /*
  * Hook list operation macros.
  *
@@ -294,16 +688,12 @@ int security_capset(struct cred *new, const struct cred *old,
                                effective, inheritable, permitted);
 }
 
-int security_capable(const struct cred *cred, struct user_namespace *ns,
-                    int cap)
+int security_capable(const struct cred *cred,
+                    struct user_namespace *ns,
+                    int cap,
+                    unsigned int opts)
 {
-       return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_AUDIT);
-}
-
-int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
-                            int cap)
-{
-       return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_NOAUDIT);
+       return call_int_hook(capable, 0, cred, ns, cap, opts);
 }
 
 int security_quotactl(int cmds, int type, int id, struct super_block *sb)
@@ -468,14 +858,40 @@ EXPORT_SYMBOL(security_add_mnt_opt);
 
 int security_inode_alloc(struct inode *inode)
 {
-       inode->i_security = NULL;
-       return call_int_hook(inode_alloc_security, 0, inode);
+       int rc = lsm_inode_alloc(inode);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(inode_alloc_security, 0, inode);
+       if (unlikely(rc))
+               security_inode_free(inode);
+       return rc;
+}
+
+static void inode_free_by_rcu(struct rcu_head *head)
+{
+       /*
+        * The rcu head is at the start of the inode blob
+        */
+       kmem_cache_free(lsm_inode_cache, head);
 }
 
 void security_inode_free(struct inode *inode)
 {
        integrity_inode_free(inode);
        call_void_hook(inode_free_security, inode);
+       /*
+        * The inode may still be referenced in a path walk and
+        * a call to security_inode_permission() can be made
+        * after inode_free_security() is called. Ideally, the VFS
+        * wouldn't do this, but fixing that is a much harder
+        * job. For now, simply free the i_security via RCU, and
+        * leave the current inode->i_security pointer intact.
+        * The inode will be freed after the RCU grace period too.
+        */
+       if (inode->i_security)
+               call_rcu((struct rcu_head *)inode->i_security,
+                               inode_free_by_rcu);
 }
 
 int security_dentry_init_security(struct dentry *dentry, int mode,
@@ -905,12 +1321,27 @@ int security_file_permission(struct file *file, int mask)
 
 int security_file_alloc(struct file *file)
 {
-       return call_int_hook(file_alloc_security, 0, file);
+       int rc = lsm_file_alloc(file);
+
+       if (rc)
+               return rc;
+       rc = call_int_hook(file_alloc_security, 0, file);
+       if (unlikely(rc))
+               security_file_free(file);
+       return rc;
 }
 
 void security_file_free(struct file *file)
 {
+       void *blob;
+
        call_void_hook(file_free_security, file);
+
+       blob = file->f_security;
+       if (blob) {
+               file->f_security = NULL;
+               kmem_cache_free(lsm_file_cache, blob);
+       }
 }
 
 int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1012,17 +1443,35 @@ int security_file_open(struct file *file)
 
 int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
 {
-       return call_int_hook(task_alloc, 0, task, clone_flags);
+       int rc = lsm_task_alloc(task);
+
+       if (rc)
+               return rc;
+       rc = call_int_hook(task_alloc, 0, task, clone_flags);
+       if (unlikely(rc))
+               security_task_free(task);
+       return rc;
 }
 
 void security_task_free(struct task_struct *task)
 {
        call_void_hook(task_free, task);
+
+       kfree(task->security);
+       task->security = NULL;
 }
 
 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
-       return call_int_hook(cred_alloc_blank, 0, cred, gfp);
+       int rc = lsm_cred_alloc(cred, gfp);
+
+       if (rc)
+               return rc;
+
+       rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
+       if (unlikely(rc))
+               security_cred_free(cred);
+       return rc;
 }
 
 void security_cred_free(struct cred *cred)
@@ -1035,11 +1484,22 @@ void security_cred_free(struct cred *cred)
                return;
 
        call_void_hook(cred_free, cred);
+
+       kfree(cred->security);
+       cred->security = NULL;
 }
 
 int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
 {
-       return call_int_hook(cred_prepare, 0, new, old, gfp);
+       int rc = lsm_cred_alloc(new, gfp);
+
+       if (rc)
+               return rc;
+
+       rc = call_int_hook(cred_prepare, 0, new, old, gfp);
+       if (unlikely(rc))
+               security_cred_free(new);
+       return rc;
 }
 
 void security_transfer_creds(struct cred *new, const struct cred *old)
@@ -1220,22 +1680,40 @@ void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
 
 int security_msg_msg_alloc(struct msg_msg *msg)
 {
-       return call_int_hook(msg_msg_alloc_security, 0, msg);
+       int rc = lsm_msg_msg_alloc(msg);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(msg_msg_alloc_security, 0, msg);
+       if (unlikely(rc))
+               security_msg_msg_free(msg);
+       return rc;
 }
 
 void security_msg_msg_free(struct msg_msg *msg)
 {
        call_void_hook(msg_msg_free_security, msg);
+       kfree(msg->security);
+       msg->security = NULL;
 }
 
 int security_msg_queue_alloc(struct kern_ipc_perm *msq)
 {
-       return call_int_hook(msg_queue_alloc_security, 0, msq);
+       int rc = lsm_ipc_alloc(msq);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(msg_queue_alloc_security, 0, msq);
+       if (unlikely(rc))
+               security_msg_queue_free(msq);
+       return rc;
 }
 
 void security_msg_queue_free(struct kern_ipc_perm *msq)
 {
        call_void_hook(msg_queue_free_security, msq);
+       kfree(msq->security);
+       msq->security = NULL;
 }
 
 int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
@@ -1262,12 +1740,21 @@ int security_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg,
 
 int security_shm_alloc(struct kern_ipc_perm *shp)
 {
-       return call_int_hook(shm_alloc_security, 0, shp);
+       int rc = lsm_ipc_alloc(shp);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(shm_alloc_security, 0, shp);
+       if (unlikely(rc))
+               security_shm_free(shp);
+       return rc;
 }
 
 void security_shm_free(struct kern_ipc_perm *shp)
 {
        call_void_hook(shm_free_security, shp);
+       kfree(shp->security);
+       shp->security = NULL;
 }
 
 int security_shm_associate(struct kern_ipc_perm *shp, int shmflg)
@@ -1287,12 +1774,21 @@ int security_shm_shmat(struct kern_ipc_perm *shp, char __user *shmaddr, int shmf
 
 int security_sem_alloc(struct kern_ipc_perm *sma)
 {
-       return call_int_hook(sem_alloc_security, 0, sma);
+       int rc = lsm_ipc_alloc(sma);
+
+       if (unlikely(rc))
+               return rc;
+       rc = call_int_hook(sem_alloc_security, 0, sma);
+       if (unlikely(rc))
+               security_sem_free(sma);
+       return rc;
 }
 
 void security_sem_free(struct kern_ipc_perm *sma)
 {
        call_void_hook(sem_free_security, sma);
+       kfree(sma->security);
+       sma->security = NULL;
 }
 
 int security_sem_associate(struct kern_ipc_perm *sma, int semflg)
@@ -1319,14 +1815,30 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 }
 EXPORT_SYMBOL(security_d_instantiate);
 
-int security_getprocattr(struct task_struct *p, char *name, char **value)
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+                               char **value)
 {
-       return call_int_hook(getprocattr, -EINVAL, p, name, value);
+       struct security_hook_list *hp;
+
+       hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
+               if (lsm != NULL && strcmp(lsm, hp->lsm))
+                       continue;
+               return hp->hook.getprocattr(p, name, value);
+       }
+       return -EINVAL;
 }
 
-int security_setprocattr(const char *name, void *value, size_t size)
+int security_setprocattr(const char *lsm, const char *name, void *value,
+                        size_t size)
 {
-       return call_int_hook(setprocattr, -EINVAL, name, value, size);
+       struct security_hook_list *hp;
+
+       hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
+               if (lsm != NULL && strcmp(lsm, hp->lsm))
+                       continue;
+               return hp->hook.setprocattr(name, value, size);
+       }
+       return -EINVAL;
 }
 
 int security_netlink_send(struct sock *sk, struct sk_buff *skb)
index 8af7a690eb40a15d06f1cba8b5ee25f60c8cdbf9..55f032f1fc2d84aff37a49b519a30f4d051b2018 100644 (file)
@@ -22,21 +22,6 @@ config SECURITY_SELINUX_BOOTPARAM
 
          If you are unsure how to answer this question, answer N.
 
-config SECURITY_SELINUX_BOOTPARAM_VALUE
-       int "NSA SELinux boot parameter default value"
-       depends on SECURITY_SELINUX_BOOTPARAM
-       range 0 1
-       default 1
-       help
-         This option sets the default value for the kernel parameter
-         'selinux', which allows SELinux to be disabled at boot.  If this
-         option is set to 0 (zero), the SELinux kernel parameter will
-         default to 0, disabling SELinux at bootup.  If this option is
-         set to 1 (one), the SELinux kernel parameter will default to 1,
-         enabling SELinux at bootup.
-
-         If you are unsure how to answer this question, answer 1.
-
 config SECURITY_SELINUX_DISABLE
        bool "NSA SELinux runtime disable"
        depends on SECURITY_SELINUX
index c7161f8792b2dc9312df1b600eee8d4adb571482..ccf95040938419a6980de885f5331380e24a6e9e 100644 (file)
@@ -6,7 +6,7 @@
 obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
 
 selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
-            netnode.o netport.o ibpkey.o exports.o \
+            netnode.o netport.o ibpkey.o \
             ss/ebitmap.o ss/hashtab.o ss/symtab.o ss/sidtab.o ss/avtab.o \
             ss/policydb.o ss/services.o ss/conditional.o ss/mls.o ss/status.o
 
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
deleted file mode 100644 (file)
index e75dd94..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * SELinux services exported to the rest of the kernel.
- *
- * Author: James Morris <jmorris@redhat.com>
- *
- * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
- * Copyright (C) 2006 Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
- * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez <tinytim@us.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2,
- * as published by the Free Software Foundation.
- */
-#include <linux/module.h>
-#include <linux/selinux.h>
-
-#include "security.h"
-
-bool selinux_is_enabled(void)
-{
-       return selinux_enabled;
-}
-EXPORT_SYMBOL_GPL(selinux_is_enabled);
index f0e36c3492baee41642fbd232625c94720ac31a4..5d92167dbe0530edc1406c52e1fc28b665bb622f 100644 (file)
@@ -79,7 +79,6 @@
 #include <linux/personality.h>
 #include <linux/audit.h>
 #include <linux/string.h>
-#include <linux/selinux.h>
 #include <linux/mutex.h>
 #include <linux/posix-timers.h>
 #include <linux/syslog.h>
@@ -121,9 +120,8 @@ __setup("enforcing=", enforcing_setup);
 #define selinux_enforcing_boot 1
 #endif
 
+int selinux_enabled __lsm_ro_after_init = 1;
 #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
-int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
-
 static int __init selinux_enabled_setup(char *str)
 {
        unsigned long enabled;
@@ -132,8 +130,6 @@ static int __init selinux_enabled_setup(char *str)
        return 1;
 }
 __setup("selinux=", selinux_enabled_setup);
-#else
-int selinux_enabled = 1;
 #endif
 
 static unsigned int selinux_checkreqprot_boot =
@@ -149,9 +145,6 @@ static int __init checkreqprot_setup(char *str)
 }
 __setup("checkreqprot=", checkreqprot_setup);
 
-static struct kmem_cache *sel_inode_cache;
-static struct kmem_cache *file_security_cache;
-
 /**
  * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
  *
@@ -214,12 +207,8 @@ static void cred_init_security(void)
        struct cred *cred = (struct cred *) current->real_cred;
        struct task_security_struct *tsec;
 
-       tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
-       if (!tsec)
-               panic("SELinux:  Failed to initialize initial task.\n");
-
+       tsec = selinux_cred(cred);
        tsec->osid = tsec->sid = SECINITSID_KERNEL;
-       cred->security = tsec;
 }
 
 /*
@@ -229,7 +218,7 @@ static inline u32 cred_sid(const struct cred *cred)
 {
        const struct task_security_struct *tsec;
 
-       tsec = cred->security;
+       tsec = selinux_cred(cred);
        return tsec->sid;
 }
 
@@ -250,13 +239,9 @@ static inline u32 task_sid(const struct task_struct *task)
 
 static int inode_alloc_security(struct inode *inode)
 {
-       struct inode_security_struct *isec;
+       struct inode_security_struct *isec = selinux_inode(inode);
        u32 sid = current_sid();
 
-       isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
-       if (!isec)
-               return -ENOMEM;
-
        spin_lock_init(&isec->lock);
        INIT_LIST_HEAD(&isec->list);
        isec->inode = inode;
@@ -264,7 +249,6 @@ static int inode_alloc_security(struct inode *inode)
        isec->sclass = SECCLASS_FILE;
        isec->task_sid = sid;
        isec->initialized = LABEL_INVALID;
-       inode->i_security = isec;
 
        return 0;
 }
@@ -281,7 +265,7 @@ static int __inode_security_revalidate(struct inode *inode,
                                       struct dentry *dentry,
                                       bool may_sleep)
 {
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
 
        might_sleep_if(may_sleep);
 
@@ -302,7 +286,7 @@ static int __inode_security_revalidate(struct inode *inode,
 
 static struct inode_security_struct *inode_security_novalidate(struct inode *inode)
 {
-       return inode->i_security;
+       return selinux_inode(inode);
 }
 
 static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
@@ -312,7 +296,7 @@ static struct inode_security_struct *inode_security_rcu(struct inode *inode, boo
        error = __inode_security_revalidate(inode, NULL, !rcu);
        if (error)
                return ERR_PTR(error);
-       return inode->i_security;
+       return selinux_inode(inode);
 }
 
 /*
@@ -321,14 +305,14 @@ static struct inode_security_struct *inode_security_rcu(struct inode *inode, boo
 static struct inode_security_struct *inode_security(struct inode *inode)
 {
        __inode_security_revalidate(inode, NULL, true);
-       return inode->i_security;
+       return selinux_inode(inode);
 }
 
 static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
 {
        struct inode *inode = d_backing_inode(dentry);
 
-       return inode->i_security;
+       return selinux_inode(inode);
 }
 
 /*
@@ -339,22 +323,17 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr
        struct inode *inode = d_backing_inode(dentry);
 
        __inode_security_revalidate(inode, dentry, true);
-       return inode->i_security;
-}
-
-static void inode_free_rcu(struct rcu_head *head)
-{
-       struct inode_security_struct *isec;
-
-       isec = container_of(head, struct inode_security_struct, rcu);
-       kmem_cache_free(sel_inode_cache, isec);
+       return selinux_inode(inode);
 }
 
 static void inode_free_security(struct inode *inode)
 {
-       struct inode_security_struct *isec = inode->i_security;
-       struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
+       struct superblock_security_struct *sbsec;
 
+       if (!isec)
+               return;
+       sbsec = inode->i_sb->s_security;
        /*
         * As not all inode security structures are in a list, we check for
         * empty list outside of the lock to make sure that we won't waste
@@ -370,42 +349,19 @@ static void inode_free_security(struct inode *inode)
                list_del_init(&isec->list);
                spin_unlock(&sbsec->isec_lock);
        }
-
-       /*
-        * The inode may still be referenced in a path walk and
-        * a call to selinux_inode_permission() can be made
-        * after inode_free_security() is called. Ideally, the VFS
-        * wouldn't do this, but fixing that is a much harder
-        * job. For now, simply free the i_security via RCU, and
-        * leave the current inode->i_security pointer intact.
-        * The inode will be freed after the RCU grace period too.
-        */
-       call_rcu(&isec->rcu, inode_free_rcu);
 }
 
 static int file_alloc_security(struct file *file)
 {
-       struct file_security_struct *fsec;
+       struct file_security_struct *fsec = selinux_file(file);
        u32 sid = current_sid();
 
-       fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
-       if (!fsec)
-               return -ENOMEM;
-
        fsec->sid = sid;
        fsec->fown_sid = sid;
-       file->f_security = fsec;
 
        return 0;
 }
 
-static void file_free_security(struct file *file)
-{
-       struct file_security_struct *fsec = file->f_security;
-       file->f_security = NULL;
-       kmem_cache_free(file_security_cache, fsec);
-}
-
 static int superblock_alloc_security(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec;
@@ -501,7 +457,7 @@ static int may_context_mount_sb_relabel(u32 sid,
                        struct superblock_security_struct *sbsec,
                        const struct cred *cred)
 {
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = selinux_cred(cred);
        int rc;
 
        rc = avc_has_perm(&selinux_state,
@@ -520,7 +476,7 @@ static int may_context_mount_inode_relabel(u32 sid,
                        struct superblock_security_struct *sbsec,
                        const struct cred *cred)
 {
-       const struct task_security_struct *tsec = cred->security;
+       const struct task_security_struct *tsec = selinux_cred(cred);
        int rc;
        rc = avc_has_perm(&selinux_state,
                          tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
@@ -1374,7 +1330,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
 static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
 {
        struct superblock_security_struct *sbsec = NULL;
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
        u32 task_sid, sid = 0;
        u16 sclass;
        struct dentry *dentry;
@@ -1621,7 +1577,7 @@ static inline u32 signal_to_av(int sig)
 
 /* Check whether a task is allowed to use a capability. */
 static int cred_has_capability(const struct cred *cred,
-                              int cap, int audit, bool initns)
+                              int cap, unsigned int opts, bool initns)
 {
        struct common_audit_data ad;
        struct av_decision avd;
@@ -1648,7 +1604,7 @@ static int cred_has_capability(const struct cred *cred,
 
        rc = avc_has_perm_noaudit(&selinux_state,
                                  sid, sid, sclass, av, 0, &avd);
-       if (audit == SECURITY_CAP_AUDIT) {
+       if (!(opts & CAP_OPT_NOAUDIT)) {
                int rc2 = avc_audit(&selinux_state,
                                    sid, sid, sclass, av, &avd, rc, &ad, 0);
                if (rc2)
@@ -1674,7 +1630,7 @@ static int inode_has_perm(const struct cred *cred,
                return 0;
 
        sid = cred_sid(cred);
-       isec = inode->i_security;
+       isec = selinux_inode(inode);
 
        return avc_has_perm(&selinux_state,
                            sid, isec->sid, isec->sclass, perms, adp);
@@ -1740,7 +1696,7 @@ static int file_has_perm(const struct cred *cred,
                         struct file *file,
                         u32 av)
 {
-       struct file_security_struct *fsec = file->f_security;
+       struct file_security_struct *fsec = selinux_file(file);
        struct inode *inode = file_inode(file);
        struct common_audit_data ad;
        u32 sid = cred_sid(cred);
@@ -1806,7 +1762,7 @@ static int may_create(struct inode *dir,
                      struct dentry *dentry,
                      u16 tclass)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
        u32 sid, newsid;
@@ -1828,7 +1784,7 @@ static int may_create(struct inode *dir,
        if (rc)
                return rc;
 
-       rc = selinux_determine_inode_label(current_security(), dir,
+       rc = selinux_determine_inode_label(selinux_cred(current_cred()), dir,
                                           &dentry->d_name, tclass, &newsid);
        if (rc)
                return rc;
@@ -2084,7 +2040,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
                                        struct file *file)
 {
        u32 sid = task_sid(to);
-       struct file_security_struct *fsec = file->f_security;
+       struct file_security_struct *fsec = selinux_file(file);
        struct dentry *dentry = file->f_path.dentry;
        struct inode_security_struct *isec;
        struct common_audit_data ad;
@@ -2168,9 +2124,9 @@ static int selinux_capset(struct cred *new, const struct cred *old,
  */
 
 static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
-                          int cap, int audit)
+                          int cap, unsigned int opts)
 {
-       return cred_has_capability(cred, cap, audit, ns == &init_user_ns);
+       return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
 }
 
 static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
@@ -2244,7 +2200,7 @@ static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
        int rc, cap_sys_admin = 0;
 
        rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
-                                SECURITY_CAP_NOAUDIT, true);
+                                CAP_OPT_NOAUDIT, true);
        if (rc == 0)
                cap_sys_admin = 1;
 
@@ -2335,8 +2291,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
        if (bprm->called_set_creds)
                return 0;
 
-       old_tsec = current_security();
-       new_tsec = bprm->cred->security;
+       old_tsec = selinux_cred(current_cred());
+       new_tsec = selinux_cred(bprm->cred);
        isec = inode_security(inode);
 
        /* Default to the current task SID. */
@@ -2500,7 +2456,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
        struct rlimit *rlim, *initrlim;
        int rc, i;
 
-       new_tsec = bprm->cred->security;
+       new_tsec = selinux_cred(bprm->cred);
        if (new_tsec->sid == new_tsec->osid)
                return;
 
@@ -2543,7 +2499,7 @@ static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
  */
 static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct itimerval itimer;
        u32 osid, sid;
        int rc, i;
@@ -2780,7 +2736,7 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode,
        u32 newsid;
        int rc;
 
-       rc = selinux_determine_inode_label(current_security(),
+       rc = selinux_determine_inode_label(selinux_cred(current_cred()),
                                           d_inode(dentry->d_parent), name,
                                           inode_mode_to_security_class(mode),
                                           &newsid);
@@ -2800,14 +2756,14 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
        int rc;
        struct task_security_struct *tsec;
 
-       rc = selinux_determine_inode_label(old->security,
+       rc = selinux_determine_inode_label(selinux_cred(old),
                                           d_inode(dentry->d_parent), name,
                                           inode_mode_to_security_class(mode),
                                           &newsid);
        if (rc)
                return rc;
 
-       tsec = new->security;
+       tsec = selinux_cred(new);
        tsec->create_sid = newsid;
        return 0;
 }
@@ -2817,7 +2773,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
                                       const char **name,
                                       void **value, size_t *len)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct superblock_security_struct *sbsec;
        u32 newsid, clen;
        int rc;
@@ -2827,7 +2783,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 
        newsid = tsec->create_sid;
 
-       rc = selinux_determine_inode_label(current_security(),
+       rc = selinux_determine_inode_label(selinux_cred(current_cred()),
                dir, qstr,
                inode_mode_to_security_class(inode->i_mode),
                &newsid);
@@ -2836,7 +2792,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 
        /* Possibly defer initialization to selinux_complete_init. */
        if (sbsec->flags & SE_SBINITIALIZED) {
-               struct inode_security_struct *isec = inode->i_security;
+               struct inode_security_struct *isec = selinux_inode(inode);
                isec->sclass = inode_mode_to_security_class(inode->i_mode);
                isec->sid = newsid;
                isec->initialized = LABEL_INITIALIZED;
@@ -2936,7 +2892,7 @@ static noinline int audit_inode_permission(struct inode *inode,
                                           unsigned flags)
 {
        struct common_audit_data ad;
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
        int rc;
 
        ad.type = LSM_AUDIT_DATA_INODE;
@@ -3031,11 +2987,11 @@ static int selinux_inode_getattr(const struct path *path)
 static bool has_cap_mac_admin(bool audit)
 {
        const struct cred *cred = current_cred();
-       int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT;
+       unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT;
 
-       if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit))
+       if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts))
                return false;
-       if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true))
+       if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true))
                return false;
        return true;
 }
@@ -3289,7 +3245,7 @@ static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
                        return -ENOMEM;
        }
 
-       tsec = new_creds->security;
+       tsec = selinux_cred(new_creds);
        /* Get label from overlay inode and set it in create_sid */
        selinux_inode_getsecid(d_inode(src), &sid);
        tsec->create_sid = sid;
@@ -3330,7 +3286,7 @@ static int selinux_revalidate_file_permission(struct file *file, int mask)
 static int selinux_file_permission(struct file *file, int mask)
 {
        struct inode *inode = file_inode(file);
-       struct file_security_struct *fsec = file->f_security;
+       struct file_security_struct *fsec = selinux_file(file);
        struct inode_security_struct *isec;
        u32 sid = current_sid();
 
@@ -3352,11 +3308,6 @@ static int selinux_file_alloc_security(struct file *file)
        return file_alloc_security(file);
 }
 
-static void selinux_file_free_security(struct file *file)
-{
-       file_free_security(file);
-}
-
 /*
  * Check whether a task has the ioctl permission and cmd
  * operation to an inode.
@@ -3365,7 +3316,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
                u32 requested, u16 cmd)
 {
        struct common_audit_data ad;
-       struct file_security_struct *fsec = file->f_security;
+       struct file_security_struct *fsec = selinux_file(file);
        struct inode *inode = file_inode(file);
        struct inode_security_struct *isec;
        struct lsm_ioctlop_audit ioctl;
@@ -3435,7 +3386,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
        case KDSKBENT:
        case KDSKBSENT:
                error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
-                                           SECURITY_CAP_AUDIT, true);
+                                           CAP_OPT_NONE, true);
                break;
 
        /* default case assumes that the command will go
@@ -3617,7 +3568,7 @@ static void selinux_file_set_fowner(struct file *file)
 {
        struct file_security_struct *fsec;
 
-       fsec = file->f_security;
+       fsec = selinux_file(file);
        fsec->fown_sid = current_sid();
 }
 
@@ -3632,7 +3583,7 @@ static int selinux_file_send_sigiotask(struct task_struct *tsk,
        /* struct fown_struct is never outside the context of a struct file */
        file = container_of(fown, struct file, f_owner);
 
-       fsec = file->f_security;
+       fsec = selinux_file(file);
 
        if (!signum)
                perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
@@ -3656,7 +3607,7 @@ static int selinux_file_open(struct file *file)
        struct file_security_struct *fsec;
        struct inode_security_struct *isec;
 
-       fsec = file->f_security;
+       fsec = selinux_file(file);
        isec = inode_security(file_inode(file));
        /*
         * Save inode label and policy sequence number
@@ -3689,53 +3640,16 @@ static int selinux_task_alloc(struct task_struct *task,
                            sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
 }
 
-/*
- * allocate the SELinux part of blank credentials
- */
-static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
-{
-       struct task_security_struct *tsec;
-
-       tsec = kzalloc(sizeof(struct task_security_struct), gfp);
-       if (!tsec)
-               return -ENOMEM;
-
-       cred->security = tsec;
-       return 0;
-}
-
-/*
- * detach and free the LSM part of a set of credentials
- */
-static void selinux_cred_free(struct cred *cred)
-{
-       struct task_security_struct *tsec = cred->security;
-
-       /*
-        * cred->security == NULL if security_cred_alloc_blank() or
-        * security_prepare_creds() returned an error.
-        */
-       BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
-       cred->security = (void *) 0x7UL;
-       kfree(tsec);
-}
-
 /*
  * prepare a new set of credentials for modification
  */
 static int selinux_cred_prepare(struct cred *new, const struct cred *old,
                                gfp_t gfp)
 {
-       const struct task_security_struct *old_tsec;
-       struct task_security_struct *tsec;
-
-       old_tsec = old->security;
+       const struct task_security_struct *old_tsec = selinux_cred(old);
+       struct task_security_struct *tsec = selinux_cred(new);
 
-       tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
-       if (!tsec)
-               return -ENOMEM;
-
-       new->security = tsec;
+       *tsec = *old_tsec;
        return 0;
 }
 
@@ -3744,8 +3658,8 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old,
  */
 static void selinux_cred_transfer(struct cred *new, const struct cred *old)
 {
-       const struct task_security_struct *old_tsec = old->security;
-       struct task_security_struct *tsec = new->security;
+       const struct task_security_struct *old_tsec = selinux_cred(old);
+       struct task_security_struct *tsec = selinux_cred(new);
 
        *tsec = *old_tsec;
 }
@@ -3761,7 +3675,7 @@ static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
  */
 static int selinux_kernel_act_as(struct cred *new, u32 secid)
 {
-       struct task_security_struct *tsec = new->security;
+       struct task_security_struct *tsec = selinux_cred(new);
        u32 sid = current_sid();
        int ret;
 
@@ -3786,7 +3700,7 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
 static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
 {
        struct inode_security_struct *isec = inode_security(inode);
-       struct task_security_struct *tsec = new->security;
+       struct task_security_struct *tsec = selinux_cred(new);
        u32 sid = current_sid();
        int ret;
 
@@ -3832,7 +3746,7 @@ static int selinux_kernel_module_from_file(struct file *file)
        ad.type = LSM_AUDIT_DATA_FILE;
        ad.u.file = file;
 
-       fsec = file->f_security;
+       fsec = selinux_file(file);
        if (sid != fsec->sid) {
                rc = avc_has_perm(&selinux_state,
                                  sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
@@ -3998,7 +3912,7 @@ static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
 static void selinux_task_to_inode(struct task_struct *p,
                                  struct inode *inode)
 {
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
        u32 sid = task_sid(p);
 
        spin_lock(&isec->lock);
@@ -4335,7 +4249,7 @@ static int sock_has_perm(struct sock *sk, u32 perms)
 static int selinux_socket_create(int family, int type,
                                 int protocol, int kern)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        u32 newsid;
        u16 secclass;
        int rc;
@@ -4355,7 +4269,7 @@ static int selinux_socket_create(int family, int type,
 static int selinux_socket_post_create(struct socket *sock, int family,
                                      int type, int protocol, int kern)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
        struct sk_security_struct *sksec;
        u16 sclass = socket_type_to_security_class(family, type, protocol);
@@ -5236,7 +5150,7 @@ static int selinux_secmark_relabel_packet(u32 sid)
        const struct task_security_struct *__tsec;
        u32 tsid;
 
-       __tsec = current_security();
+       __tsec = selinux_cred(current_cred());
        tsid = __tsec->sid;
 
        return avc_has_perm(&selinux_state,
@@ -5711,51 +5625,22 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
        return selinux_nlmsg_perm(sk, skb);
 }
 
-static int ipc_alloc_security(struct kern_ipc_perm *perm,
-                             u16 sclass)
+static void ipc_init_security(struct ipc_security_struct *isec, u16 sclass)
 {
-       struct ipc_security_struct *isec;
-
-       isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
-       if (!isec)
-               return -ENOMEM;
-
        isec->sclass = sclass;
        isec->sid = current_sid();
-       perm->security = isec;
-
-       return 0;
-}
-
-static void ipc_free_security(struct kern_ipc_perm *perm)
-{
-       struct ipc_security_struct *isec = perm->security;
-       perm->security = NULL;
-       kfree(isec);
 }
 
 static int msg_msg_alloc_security(struct msg_msg *msg)
 {
        struct msg_security_struct *msec;
 
-       msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
-       if (!msec)
-               return -ENOMEM;
-
+       msec = selinux_msg_msg(msg);
        msec->sid = SECINITSID_UNLABELED;
-       msg->security = msec;
 
        return 0;
 }
 
-static void msg_msg_free_security(struct msg_msg *msg)
-{
-       struct msg_security_struct *msec = msg->security;
-
-       msg->security = NULL;
-       kfree(msec);
-}
-
 static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
                        u32 perms)
 {
@@ -5763,7 +5648,7 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
        struct common_audit_data ad;
        u32 sid = current_sid();
 
-       isec = ipc_perms->security;
+       isec = selinux_ipc(ipc_perms);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = ipc_perms->key;
@@ -5777,11 +5662,6 @@ static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
        return msg_msg_alloc_security(msg);
 }
 
-static void selinux_msg_msg_free_security(struct msg_msg *msg)
-{
-       msg_msg_free_security(msg);
-}
-
 /* message queue security operations */
 static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
 {
@@ -5790,11 +5670,8 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(msq, SECCLASS_MSGQ);
-       if (rc)
-               return rc;
-
-       isec = msq->security;
+       isec = selinux_ipc(msq);
+       ipc_init_security(isec, SECCLASS_MSGQ);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
@@ -5802,16 +5679,7 @@ static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
        rc = avc_has_perm(&selinux_state,
                          sid, isec->sid, SECCLASS_MSGQ,
                          MSGQ__CREATE, &ad);
-       if (rc) {
-               ipc_free_security(msq);
-               return rc;
-       }
-       return 0;
-}
-
-static void selinux_msg_queue_free_security(struct kern_ipc_perm *msq)
-{
-       ipc_free_security(msq);
+       return rc;
 }
 
 static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
@@ -5820,7 +5688,7 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
 
-       isec = msq->security;
+       isec = selinux_ipc(msq);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
@@ -5869,8 +5737,8 @@ static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *m
        u32 sid = current_sid();
        int rc;
 
-       isec = msq->security;
-       msec = msg->security;
+       isec = selinux_ipc(msq);
+       msec = selinux_msg_msg(msg);
 
        /*
         * First time through, need to assign label to the message
@@ -5917,8 +5785,8 @@ static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *m
        u32 sid = task_sid(target);
        int rc;
 
-       isec = msq->security;
-       msec = msg->security;
+       isec = selinux_ipc(msq);
+       msec = selinux_msg_msg(msg);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = msq->key;
@@ -5941,11 +5809,8 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(shp, SECCLASS_SHM);
-       if (rc)
-               return rc;
-
-       isec = shp->security;
+       isec = selinux_ipc(shp);
+       ipc_init_security(isec, SECCLASS_SHM);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = shp->key;
@@ -5953,16 +5818,7 @@ static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
        rc = avc_has_perm(&selinux_state,
                          sid, isec->sid, SECCLASS_SHM,
                          SHM__CREATE, &ad);
-       if (rc) {
-               ipc_free_security(shp);
-               return rc;
-       }
-       return 0;
-}
-
-static void selinux_shm_free_security(struct kern_ipc_perm *shp)
-{
-       ipc_free_security(shp);
+       return rc;
 }
 
 static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
@@ -5971,7 +5827,7 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
 
-       isec = shp->security;
+       isec = selinux_ipc(shp);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = shp->key;
@@ -6038,11 +5894,8 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
        u32 sid = current_sid();
        int rc;
 
-       rc = ipc_alloc_security(sma, SECCLASS_SEM);
-       if (rc)
-               return rc;
-
-       isec = sma->security;
+       isec = selinux_ipc(sma);
+       ipc_init_security(isec, SECCLASS_SEM);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = sma->key;
@@ -6050,16 +5903,7 @@ static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
        rc = avc_has_perm(&selinux_state,
                          sid, isec->sid, SECCLASS_SEM,
                          SEM__CREATE, &ad);
-       if (rc) {
-               ipc_free_security(sma);
-               return rc;
-       }
-       return 0;
-}
-
-static void selinux_sem_free_security(struct kern_ipc_perm *sma)
-{
-       ipc_free_security(sma);
+       return rc;
 }
 
 static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
@@ -6068,7 +5912,7 @@ static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
        struct common_audit_data ad;
        u32 sid = current_sid();
 
-       isec = sma->security;
+       isec = selinux_ipc(sma);
 
        ad.type = LSM_AUDIT_DATA_IPC;
        ad.u.ipc_id = sma->key;
@@ -6154,7 +5998,7 @@ static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 
 static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
 {
-       struct ipc_security_struct *isec = ipcp->security;
+       struct ipc_security_struct *isec = selinux_ipc(ipcp);
        *secid = isec->sid;
 }
 
@@ -6173,7 +6017,7 @@ static int selinux_getprocattr(struct task_struct *p,
        unsigned len;
 
        rcu_read_lock();
-       __tsec = __task_cred(p)->security;
+       __tsec = selinux_cred(__task_cred(p));
 
        if (current != p) {
                error = avc_has_perm(&selinux_state,
@@ -6296,7 +6140,7 @@ static int selinux_setprocattr(const char *name, void *value, size_t size)
           operation.  See selinux_bprm_set_creds for the execve
           checks and may_create for the file creation checks. The
           operation will then fail if the context is not permitted. */
-       tsec = new->security;
+       tsec = selinux_cred(new);
        if (!strcmp(name, "exec")) {
                tsec->exec_sid = sid;
        } else if (!strcmp(name, "fscreate")) {
@@ -6380,7 +6224,7 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
 
 static void selinux_inode_invalidate_secctx(struct inode *inode)
 {
-       struct inode_security_struct *isec = inode->i_security;
+       struct inode_security_struct *isec = selinux_inode(inode);
 
        spin_lock(&isec->lock);
        isec->initialized = LABEL_INVALID;
@@ -6425,7 +6269,7 @@ static int selinux_key_alloc(struct key *k, const struct cred *cred,
        if (!ksec)
                return -ENOMEM;
 
-       tsec = cred->security;
+       tsec = selinux_cred(cred);
        if (tsec->keycreate_sid)
                ksec->sid = tsec->keycreate_sid;
        else
@@ -6688,6 +6532,14 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
 }
 #endif
 
+struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
+       .lbs_cred = sizeof(struct task_security_struct),
+       .lbs_file = sizeof(struct file_security_struct),
+       .lbs_inode = sizeof(struct inode_security_struct),
+       .lbs_ipc = sizeof(struct ipc_security_struct),
+       .lbs_msg_msg = sizeof(struct msg_security_struct),
+};
+
 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
        LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
@@ -6757,7 +6609,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
        LSM_HOOK_INIT(file_permission, selinux_file_permission),
        LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
-       LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
        LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
        LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
        LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
@@ -6771,8 +6622,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(file_open, selinux_file_open),
 
        LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
-       LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank),
-       LSM_HOOK_INIT(cred_free, selinux_cred_free),
        LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
        LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
        LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
@@ -6800,24 +6649,20 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
 
        LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
-       LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security),
 
        LSM_HOOK_INIT(msg_queue_alloc_security,
                        selinux_msg_queue_alloc_security),
-       LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security),
        LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
        LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
        LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
        LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
 
        LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
-       LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security),
        LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
        LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
        LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),
 
        LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
-       LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security),
        LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
        LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
        LSM_HOOK_INIT(sem_semop, selinux_sem_semop),
@@ -6928,16 +6773,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
 static __init int selinux_init(void)
 {
-       if (!security_module_enable("selinux")) {
-               selinux_enabled = 0;
-               return 0;
-       }
-
-       if (!selinux_enabled) {
-               pr_info("SELinux:  Disabled at boot.\n");
-               return 0;
-       }
-
        pr_info("SELinux:  Initializing.\n");
 
        memset(&selinux_state, 0, sizeof(selinux_state));
@@ -6951,12 +6786,6 @@ static __init int selinux_init(void)
 
        default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
 
-       sel_inode_cache = kmem_cache_create("selinux_inode_security",
-                                           sizeof(struct inode_security_struct),
-                                           0, SLAB_PANIC, NULL);
-       file_security_cache = kmem_cache_create("selinux_file_security",
-                                           sizeof(struct file_security_struct),
-                                           0, SLAB_PANIC, NULL);
        avc_init();
 
        avtab_cache_init();
@@ -6999,6 +6828,9 @@ void selinux_complete_init(void)
    all processes and objects when they are created. */
 DEFINE_LSM(selinux) = {
        .name = "selinux",
+       .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+       .enabled = &selinux_enabled,
+       .blobs = &selinux_blob_sizes,
        .init = selinux_init,
 };
 
index 1bdf973433cc20c7d5dc74fe8172047ce965d48a..36e1d44c0209421e4eefc98c956a5888a322a380 100644 (file)
@@ -1,9 +1,6 @@
 /*
  * SELinux support for the Audit LSM hooks
  *
- * Most of below header was moved from include/linux/selinux.h which
- * is released under below copyrights:
- *
  * Author: James Morris <jmorris@redhat.com>
  *
  * Copyright (C) 2005 Red Hat, Inc., James Morris <jmorris@redhat.com>
index cc5e26b0161b462108e6261a4e4a87cfafccf934..231262d8eac9189e8dec1576f9a25264d8633567 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/binfmts.h>
 #include <linux/in.h>
 #include <linux/spinlock.h>
+#include <linux/lsm_hooks.h>
+#include <linux/msg.h>
 #include <net/net_namespace.h>
 #include "flask.h"
 #include "avc.h"
@@ -56,10 +58,7 @@ enum label_initialized {
 
 struct inode_security_struct {
        struct inode *inode;    /* back pointer to inode object */
-       union {
-               struct list_head list;  /* list of inode_security_struct */
-               struct rcu_head rcu;    /* for freeing the inode_security_struct */
-       };
+       struct list_head list;  /* list of inode_security_struct */
        u32 task_sid;           /* SID of creating task */
        u32 sid;                /* SID of this object */
        u16 sclass;             /* security class of this object */
@@ -158,4 +157,35 @@ struct bpf_security_struct {
        u32 sid;  /*SID of bpf obj creater*/
 };
 
+extern struct lsm_blob_sizes selinux_blob_sizes;
+static inline struct task_security_struct *selinux_cred(const struct cred *cred)
+{
+       return cred->security + selinux_blob_sizes.lbs_cred;
+}
+
+static inline struct file_security_struct *selinux_file(const struct file *file)
+{
+       return file->f_security + selinux_blob_sizes.lbs_file;
+}
+
+static inline struct inode_security_struct *selinux_inode(
+                                               const struct inode *inode)
+{
+       if (unlikely(!inode->i_security))
+               return NULL;
+       return inode->i_security + selinux_blob_sizes.lbs_inode;
+}
+
+static inline struct msg_security_struct *selinux_msg_msg(
+                                               const struct msg_msg *msg_msg)
+{
+       return msg_msg->security + selinux_blob_sizes.lbs_msg_msg;
+}
+
+static inline struct ipc_security_struct *selinux_ipc(
+                                               const struct kern_ipc_perm *ipc)
+{
+       return ipc->security + selinux_blob_sizes.lbs_ipc;
+}
+
 #endif /* _SELINUX_OBJSEC_H_ */
index f3a5a138a096d8cb7d1d42cd23e07eecbbd4a2a0..145ee62f205a632a24e85d010e48dad600dfaa9a 100644 (file)
@@ -1378,7 +1378,7 @@ static int sel_make_bools(struct selinux_fs_info *fsi)
                        goto out;
                }
 
-               isec = (struct inode_security_struct *)inode->i_security;
+               isec = selinux_inode(inode);
                ret = security_genfs_sid(fsi->state, "selinuxfs", page,
                                         SECCLASS_FILE, &sid);
                if (ret) {
@@ -1953,7 +1953,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        inode->i_ino = ++fsi->last_ino;
-       isec = (struct inode_security_struct *)inode->i_security;
+       isec = selinux_inode(inode);
        isec->sid = SECINITSID_DEVNULL;
        isec->sclass = SECCLASS_CHR_FILE;
        isec->initialized = LABEL_INITIALIZED;
index dd44126c8d1445ab4f26e225a2fd8537c88bbf1a..d6e7b4856d931a3687449310f1508a950d177697 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/sched.h>
 #include <linux/audit.h>
 #include <linux/mutex.h>
-#include <linux/selinux.h>
 #include <linux/flex_array.h>
 #include <linux/vmalloc.h>
 #include <net/netlabel.h>
index bd7d18bdb147a8cad2003a41db60a94a19444fb4..7c57cb7e4146c9b56d7dd40a086c3eaecf5fca77 100644 (file)
@@ -79,7 +79,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
                                   gfp_t gfp)
 {
        int rc;
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
        struct xfrm_sec_ctx *ctx = NULL;
        u32 str_len;
 
@@ -138,7 +138,7 @@ static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
  */
 static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
 {
-       const struct task_security_struct *tsec = current_security();
+       const struct task_security_struct *tsec = selinux_cred(current_cred());
 
        if (!ctx)
                return 0;
index f7db791fb5660ad14479af3d4b48e104d8bc37ed..9c7c95a5c4974c73ee48007ebc49ac47d560d6d4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/list.h>
 #include <linux/rculist.h>
 #include <linux/lsm_audit.h>
+#include <linux/msg.h>
 
 /*
  * Use IPv6 port labeling if IPv6 is enabled and secmarks
@@ -336,6 +337,7 @@ extern struct smack_known *smack_syslog_label;
 extern struct smack_known *smack_unconfined;
 #endif
 extern int smack_ptrace_rule;
+extern struct lsm_blob_sizes smack_blob_sizes;
 
 extern struct smack_known smack_known_floor;
 extern struct smack_known smack_known_hat;
@@ -356,12 +358,38 @@ extern struct list_head smack_onlycap_list;
 #define SMACK_HASH_SLOTS 16
 extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
 
+static inline struct task_smack *smack_cred(const struct cred *cred)
+{
+       return cred->security + smack_blob_sizes.lbs_cred;
+}
+
+static inline struct smack_known **smack_file(const struct file *file)
+{
+       return (struct smack_known **)(file->f_security +
+                                      smack_blob_sizes.lbs_file);
+}
+
+static inline struct inode_smack *smack_inode(const struct inode *inode)
+{
+       return inode->i_security + smack_blob_sizes.lbs_inode;
+}
+
+static inline struct smack_known **smack_msg_msg(const struct msg_msg *msg)
+{
+       return msg->security + smack_blob_sizes.lbs_msg_msg;
+}
+
+static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
+{
+       return ipc->security + smack_blob_sizes.lbs_ipc;
+}
+
 /*
  * Is the directory transmuting?
  */
 static inline int smk_inode_transmutable(const struct inode *isp)
 {
-       struct inode_smack *sip = isp->i_security;
+       struct inode_smack *sip = smack_inode(isp);
        return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
 }
 
@@ -370,7 +398,7 @@ static inline int smk_inode_transmutable(const struct inode *isp)
  */
 static inline struct smack_known *smk_of_inode(const struct inode *isp)
 {
-       struct inode_smack *sip = isp->i_security;
+       struct inode_smack *sip = smack_inode(isp);
        return sip->smk_inode;
 }
 
@@ -382,13 +410,19 @@ static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
        return tsp->smk_task;
 }
 
-static inline struct smack_known *smk_of_task_struct(const struct task_struct *t)
+static inline struct smack_known *smk_of_task_struct(
+                                               const struct task_struct *t)
 {
        struct smack_known *skp;
+       const struct cred *cred;
 
        rcu_read_lock();
-       skp = smk_of_task(__task_cred(t)->security);
+
+       cred = __task_cred(t);
+       skp = smk_of_task(smack_cred(cred));
+
        rcu_read_unlock();
+
        return skp;
 }
 
@@ -405,7 +439,7 @@ static inline struct smack_known *smk_of_forked(const struct task_smack *tsp)
  */
 static inline struct smack_known *smk_of_current(void)
 {
-       return smk_of_task(current_security());
+       return smk_of_task(smack_cred(current_cred()));
 }
 
 /*
index 9a4c0ad46518d12d38564a703fdc51f3b202a5ae..fe2ce3a658220b6ba5810ef11952960667eac1ce 100644 (file)
@@ -275,7 +275,7 @@ out_audit:
 int smk_curacc(struct smack_known *obj_known,
               u32 mode, struct smk_audit_info *a)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_tskacc(tsp, obj_known, mode, a);
 }
@@ -635,12 +635,12 @@ DEFINE_MUTEX(smack_onlycap_lock);
  */
 bool smack_privileged_cred(int cap, const struct cred *cred)
 {
-       struct task_smack *tsp = cred->security;
+       struct task_smack *tsp = smack_cred(cred);
        struct smack_known *skp = tsp->smk_task;
        struct smack_known_list_elem *sklep;
        int rc;
 
-       rc = cap_capable(cred, &init_user_ns, cap, SECURITY_CAP_AUDIT);
+       rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE);
        if (rc)
                return false;
 
index 430d4f35e55c0f2a77cfd81c3f3685b8c8390500..2309c696c6c800e7ebafe6c0e1c5ee95b59e5484 100644 (file)
@@ -139,7 +139,7 @@ static int smk_bu_note(char *note, struct smack_known *sskp,
 static int smk_bu_current(char *note, struct smack_known *oskp,
                          int mode, int rc)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
        char acc[SMK_NUM_ACCESS_TYPE + 1];
 
        if (rc <= 0)
@@ -160,7 +160,7 @@ static int smk_bu_current(char *note, struct smack_known *oskp,
 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
 static int smk_bu_task(struct task_struct *otp, int mode, int rc)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
        struct smack_known *smk_task = smk_of_task_struct(otp);
        char acc[SMK_NUM_ACCESS_TYPE + 1];
 
@@ -182,8 +182,8 @@ static int smk_bu_task(struct task_struct *otp, int mode, int rc)
 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
 static int smk_bu_inode(struct inode *inode, int mode, int rc)
 {
-       struct task_smack *tsp = current_security();
-       struct inode_smack *isp = inode->i_security;
+       struct task_smack *tsp = smack_cred(current_cred());
+       struct inode_smack *isp = smack_inode(inode);
        char acc[SMK_NUM_ACCESS_TYPE + 1];
 
        if (isp->smk_flags & SMK_INODE_IMPURE)
@@ -212,10 +212,10 @@ static int smk_bu_inode(struct inode *inode, int mode, int rc)
 #ifdef CONFIG_SECURITY_SMACK_BRINGUP
 static int smk_bu_file(struct file *file, int mode, int rc)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
        struct smack_known *sskp = tsp->smk_task;
        struct inode *inode = file_inode(file);
-       struct inode_smack *isp = inode->i_security;
+       struct inode_smack *isp = smack_inode(inode);
        char acc[SMK_NUM_ACCESS_TYPE + 1];
 
        if (isp->smk_flags & SMK_INODE_IMPURE)
@@ -242,10 +242,10 @@ static int smk_bu_file(struct file *file, int mode, int rc)
 static int smk_bu_credfile(const struct cred *cred, struct file *file,
                                int mode, int rc)
 {
-       struct task_smack *tsp = cred->security;
+       struct task_smack *tsp = smack_cred(cred);
        struct smack_known *sskp = tsp->smk_task;
        struct inode *inode = file_inode(file);
-       struct inode_smack *isp = inode->i_security;
+       struct inode_smack *isp = smack_inode(inode);
        char acc[SMK_NUM_ACCESS_TYPE + 1];
 
        if (isp->smk_flags & SMK_INODE_IMPURE)
@@ -305,50 +305,35 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
 }
 
 /**
- * new_inode_smack - allocate an inode security blob
+ * init_inode_smack - initialize an inode security blob
+ * @isp: the blob to initialize
  * @skp: a pointer to the Smack label entry to use in the blob
  *
- * Returns the new blob or NULL if there's no memory available
  */
-static struct inode_smack *new_inode_smack(struct smack_known *skp)
+static void init_inode_smack(struct inode *inode, struct smack_known *skp)
 {
-       struct inode_smack *isp;
-
-       isp = kmem_cache_zalloc(smack_inode_cache, GFP_NOFS);
-       if (isp == NULL)
-               return NULL;
+       struct inode_smack *isp = smack_inode(inode);
 
        isp->smk_inode = skp;
        isp->smk_flags = 0;
        mutex_init(&isp->smk_lock);
-
-       return isp;
 }
 
 /**
- * new_task_smack - allocate a task security blob
+ * init_task_smack - initialize a task security blob
+ * @tsp: blob to initialize
  * @task: a pointer to the Smack label for the running task
  * @forked: a pointer to the Smack label for the forked task
- * @gfp: type of the memory for the allocation
  *
- * Returns the new blob or NULL if there's no memory available
  */
-static struct task_smack *new_task_smack(struct smack_known *task,
-                                       struct smack_known *forked, gfp_t gfp)
+static void init_task_smack(struct task_smack *tsp, struct smack_known *task,
+                                       struct smack_known *forked)
 {
-       struct task_smack *tsp;
-
-       tsp = kzalloc(sizeof(struct task_smack), gfp);
-       if (tsp == NULL)
-               return NULL;
-
        tsp->smk_task = task;
        tsp->smk_forked = forked;
        INIT_LIST_HEAD(&tsp->smk_rules);
        INIT_LIST_HEAD(&tsp->smk_relabel);
        mutex_init(&tsp->smk_rules_lock);
-
-       return tsp;
 }
 
 /**
@@ -448,7 +433,7 @@ static int smk_ptrace_rule_check(struct task_struct *tracer,
 
        rcu_read_lock();
        tracercred = __task_cred(tracer);
-       tsp = tracercred->security;
+       tsp = smack_cred(tracercred);
        tracer_known = smk_of_task(tsp);
 
        if ((mode & PTRACE_MODE_ATTACH) &&
@@ -515,7 +500,7 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
        int rc;
        struct smack_known *skp;
 
-       skp = smk_of_task(current_security());
+       skp = smk_of_task(smack_cred(current_cred()));
 
        rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
        return rc;
@@ -718,6 +703,13 @@ static int smack_set_mnt_opts(struct super_block *sb,
        if (sp->smk_flags & SMK_SB_INITIALIZED)
                return 0;
 
+       if (inode->i_security == NULL) {
+               int rc = lsm_inode_alloc(inode);
+
+               if (rc)
+                       return rc;
+       }
+
        if (!smack_privileged(CAP_MAC_ADMIN)) {
                /*
                 * Unprivileged mounts don't get to specify Smack values.
@@ -782,17 +774,12 @@ static int smack_set_mnt_opts(struct super_block *sb,
        /*
         * Initialize the root inode.
         */
-       isp = inode->i_security;
-       if (isp == NULL) {
-               isp = new_inode_smack(sp->smk_root);
-               if (isp == NULL)
-                       return -ENOMEM;
-               inode->i_security = isp;
-       } else
-               isp->smk_inode = sp->smk_root;
+       init_inode_smack(inode, sp->smk_root);
 
-       if (transmute)
+       if (transmute) {
+               isp = smack_inode(inode);
                isp->smk_flags |= SMK_INODE_TRANSMUTE;
+       }
 
        return 0;
 }
@@ -831,7 +818,7 @@ static int smack_sb_statfs(struct dentry *dentry)
 static int smack_bprm_set_creds(struct linux_binprm *bprm)
 {
        struct inode *inode = file_inode(bprm->file);
-       struct task_smack *bsp = bprm->cred->security;
+       struct task_smack *bsp = smack_cred(bprm->cred);
        struct inode_smack *isp;
        struct superblock_smack *sbsp;
        int rc;
@@ -839,7 +826,7 @@ static int smack_bprm_set_creds(struct linux_binprm *bprm)
        if (bprm->called_set_creds)
                return 0;
 
-       isp = inode->i_security;
+       isp = smack_inode(inode);
        if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
                return 0;
 
@@ -890,48 +877,10 @@ static int smack_inode_alloc_security(struct inode *inode)
 {
        struct smack_known *skp = smk_of_current();
 
-       inode->i_security = new_inode_smack(skp);
-       if (inode->i_security == NULL)
-               return -ENOMEM;
+       init_inode_smack(inode, skp);
        return 0;
 }
 
-/**
- * smack_inode_free_rcu - Free inode_smack blob from cache
- * @head: the rcu_head for getting inode_smack pointer
- *
- *  Call back function called from call_rcu() to free
- *  the i_security blob pointer in inode
- */
-static void smack_inode_free_rcu(struct rcu_head *head)
-{
-       struct inode_smack *issp;
-
-       issp = container_of(head, struct inode_smack, smk_rcu);
-       kmem_cache_free(smack_inode_cache, issp);
-}
-
-/**
- * smack_inode_free_security - free an inode blob using call_rcu()
- * @inode: the inode with a blob
- *
- * Clears the blob pointer in inode using RCU
- */
-static void smack_inode_free_security(struct inode *inode)
-{
-       struct inode_smack *issp = inode->i_security;
-
-       /*
-        * The inode may still be referenced in a path walk and
-        * a call to smack_inode_permission() can be made
-        * after smack_inode_free_security() is called.
-        * To avoid race condition free the i_security via RCU
-        * and leave the current inode->i_security pointer intact.
-        * The inode will be freed after the RCU grace period too.
-        */
-       call_rcu(&issp->smk_rcu, smack_inode_free_rcu);
-}
-
 /**
  * smack_inode_init_security - copy out the smack from an inode
  * @inode: the newly created inode
@@ -947,7 +896,7 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
                                     const struct qstr *qstr, const char **name,
                                     void **value, size_t *len)
 {
-       struct inode_smack *issp = inode->i_security;
+       struct inode_smack *issp = smack_inode(inode);
        struct smack_known *skp = smk_of_current();
        struct smack_known *isp = smk_of_inode(inode);
        struct smack_known *dsp = smk_of_inode(dir);
@@ -1285,7 +1234,7 @@ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
                                      const void *value, size_t size, int flags)
 {
        struct smack_known *skp;
-       struct inode_smack *isp = d_backing_inode(dentry)->i_security;
+       struct inode_smack *isp = smack_inode(d_backing_inode(dentry));
 
        if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
                isp->smk_flags |= SMK_INODE_TRANSMUTE;
@@ -1366,7 +1315,7 @@ static int smack_inode_removexattr(struct dentry *dentry, const char *name)
        if (rc != 0)
                return rc;
 
-       isp = d_backing_inode(dentry)->i_security;
+       isp = smack_inode(d_backing_inode(dentry));
        /*
         * Don't do anything special for these.
         *      XATTR_NAME_SMACKIPIN
@@ -1498,24 +1447,12 @@ static void smack_inode_getsecid(struct inode *inode, u32 *secid)
  */
 static int smack_file_alloc_security(struct file *file)
 {
-       struct smack_known *skp = smk_of_current();
+       struct smack_known **blob = smack_file(file);
 
-       file->f_security = skp;
+       *blob = smk_of_current();
        return 0;
 }
 
-/**
- * smack_file_free_security - clear a file security blob
- * @file: the object
- *
- * The security blob for a file is a pointer to the master
- * label list, so no memory is freed.
- */
-static void smack_file_free_security(struct file *file)
-{
-       file->f_security = NULL;
-}
-
 /**
  * smack_file_ioctl - Smack check on ioctls
  * @file: the object
@@ -1653,7 +1590,7 @@ static int smack_mmap_file(struct file *file,
        if (unlikely(IS_PRIVATE(file_inode(file))))
                return 0;
 
-       isp = file_inode(file)->i_security;
+       isp = smack_inode(file_inode(file));
        if (isp->smk_mmap == NULL)
                return 0;
        sbsp = file_inode(file)->i_sb->s_security;
@@ -1662,7 +1599,7 @@ static int smack_mmap_file(struct file *file,
                return -EACCES;
        mkp = isp->smk_mmap;
 
-       tsp = current_security();
+       tsp = smack_cred(current_cred());
        skp = smk_of_current();
        rc = 0;
 
@@ -1740,7 +1677,9 @@ static int smack_mmap_file(struct file *file,
  */
 static void smack_file_set_fowner(struct file *file)
 {
-       file->f_security = smk_of_current();
+       struct smack_known **blob = smack_file(file);
+
+       *blob = smk_of_current();
 }
 
 /**
@@ -1757,8 +1696,9 @@ static void smack_file_set_fowner(struct file *file)
 static int smack_file_send_sigiotask(struct task_struct *tsk,
                                     struct fown_struct *fown, int signum)
 {
+       struct smack_known **blob;
        struct smack_known *skp;
-       struct smack_known *tkp = smk_of_task(tsk->cred->security);
+       struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred));
        const struct cred *tcred;
        struct file *file;
        int rc;
@@ -1770,7 +1710,8 @@ static int smack_file_send_sigiotask(struct task_struct *tsk,
        file = container_of(fown, struct file, f_owner);
 
        /* we don't log here as rc can be overriden */
-       skp = file->f_security;
+       blob = smack_file(file);
+       skp = *blob;
        rc = smk_access(skp, tkp, MAY_DELIVER, NULL);
        rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc);
 
@@ -1811,7 +1752,7 @@ static int smack_file_receive(struct file *file)
        if (inode->i_sb->s_magic == SOCKFS_MAGIC) {
                sock = SOCKET_I(inode);
                ssp = sock->sk->sk_security;
-               tsp = current_security();
+               tsp = smack_cred(current_cred());
                /*
                 * If the receiving process can't write to the
                 * passed socket or if the passed socket can't
@@ -1853,7 +1794,7 @@ static int smack_file_receive(struct file *file)
  */
 static int smack_file_open(struct file *file)
 {
-       struct task_smack *tsp = file->f_cred->security;
+       struct task_smack *tsp = smack_cred(file->f_cred);
        struct inode *inode = file_inode(file);
        struct smk_audit_info ad;
        int rc;
@@ -1881,14 +1822,7 @@ static int smack_file_open(struct file *file)
  */
 static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
-       struct task_smack *tsp;
-
-       tsp = new_task_smack(NULL, NULL, gfp);
-       if (tsp == NULL)
-               return -ENOMEM;
-
-       cred->security = tsp;
-
+       init_task_smack(smack_cred(cred), NULL, NULL);
        return 0;
 }
 
@@ -1900,15 +1834,11 @@ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
  */
 static void smack_cred_free(struct cred *cred)
 {
-       struct task_smack *tsp = cred->security;
+       struct task_smack *tsp = smack_cred(cred);
        struct smack_rule *rp;
        struct list_head *l;
        struct list_head *n;
 
-       if (tsp == NULL)
-               return;
-       cred->security = NULL;
-
        smk_destroy_label_list(&tsp->smk_relabel);
 
        list_for_each_safe(l, n, &tsp->smk_rules) {
@@ -1916,7 +1846,6 @@ static void smack_cred_free(struct cred *cred)
                list_del(&rp->list);
                kfree(rp);
        }
-       kfree(tsp);
 }
 
 /**
@@ -1930,15 +1859,11 @@ static void smack_cred_free(struct cred *cred)
 static int smack_cred_prepare(struct cred *new, const struct cred *old,
                              gfp_t gfp)
 {
-       struct task_smack *old_tsp = old->security;
-       struct task_smack *new_tsp;
+       struct task_smack *old_tsp = smack_cred(old);
+       struct task_smack *new_tsp = smack_cred(new);
        int rc;
 
-       new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp);
-       if (new_tsp == NULL)
-               return -ENOMEM;
-
-       new->security = new_tsp;
+       init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task);
 
        rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp);
        if (rc != 0)
@@ -1946,10 +1871,7 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
 
        rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
                                gfp);
-       if (rc != 0)
-               return rc;
-
-       return 0;
+       return rc;
 }
 
 /**
@@ -1961,15 +1883,14 @@ static int smack_cred_prepare(struct cred *new, const struct cred *old,
  */
 static void smack_cred_transfer(struct cred *new, const struct cred *old)
 {
-       struct task_smack *old_tsp = old->security;
-       struct task_smack *new_tsp = new->security;
+       struct task_smack *old_tsp = smack_cred(old);
+       struct task_smack *new_tsp = smack_cred(new);
 
        new_tsp->smk_task = old_tsp->smk_task;
        new_tsp->smk_forked = old_tsp->smk_task;
        mutex_init(&new_tsp->smk_rules_lock);
        INIT_LIST_HEAD(&new_tsp->smk_rules);
 
-
        /* cbs copy rule list */
 }
 
@@ -1980,12 +1901,12 @@ static void smack_cred_transfer(struct cred *new, const struct cred *old)
  *
  * Sets the secid to contain a u32 version of the smack label.
  */
-static void smack_cred_getsecid(const struct cred *c, u32 *secid)
+static void smack_cred_getsecid(const struct cred *cred, u32 *secid)
 {
        struct smack_known *skp;
 
        rcu_read_lock();
-       skp = smk_of_task(c->security);
+       skp = smk_of_task(smack_cred(cred));
        *secid = skp->smk_secid;
        rcu_read_unlock();
 }
@@ -1999,7 +1920,7 @@ static void smack_cred_getsecid(const struct cred *c, u32 *secid)
  */
 static int smack_kernel_act_as(struct cred *new, u32 secid)
 {
-       struct task_smack *new_tsp = new->security;
+       struct task_smack *new_tsp = smack_cred(new);
 
        new_tsp->smk_task = smack_from_secid(secid);
        return 0;
@@ -2016,8 +1937,8 @@ static int smack_kernel_act_as(struct cred *new, u32 secid)
 static int smack_kernel_create_files_as(struct cred *new,
                                        struct inode *inode)
 {
-       struct inode_smack *isp = inode->i_security;
-       struct task_smack *tsp = new->security;
+       struct inode_smack *isp = smack_inode(inode);
+       struct task_smack *tsp = smack_cred(new);
 
        tsp->smk_forked = isp->smk_inode;
        tsp->smk_task = tsp->smk_forked;
@@ -2201,7 +2122,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
         * specific behavior. This is not clean. For one thing
         * we can't take privilege into account.
         */
-       skp = smk_of_task(cred->security);
+       skp = smk_of_task(smack_cred(cred));
        rc = smk_access(skp, tkp, MAY_DELIVER, &ad);
        rc = smk_bu_note("USB signal", skp, tkp, MAY_DELIVER, rc);
        return rc;
@@ -2216,7 +2137,7 @@ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info,
  */
 static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
 {
-       struct inode_smack *isp = inode->i_security;
+       struct inode_smack *isp = smack_inode(inode);
        struct smack_known *skp = smk_of_task_struct(p);
 
        isp->smk_inode = skp;
@@ -2679,7 +2600,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
                                   const void *value, size_t size, int flags)
 {
        struct smack_known *skp;
-       struct inode_smack *nsp = inode->i_security;
+       struct inode_smack *nsp = smack_inode(inode);
        struct socket_smack *ssp;
        struct socket *sock;
        int rc = 0;
@@ -2888,23 +2809,12 @@ static int smack_flags_to_may(int flags)
  */
 static int smack_msg_msg_alloc_security(struct msg_msg *msg)
 {
-       struct smack_known *skp = smk_of_current();
+       struct smack_known **blob = smack_msg_msg(msg);
 
-       msg->security = skp;
+       *blob = smk_of_current();
        return 0;
 }
 
-/**
- * smack_msg_msg_free_security - Clear the security blob for msg_msg
- * @msg: the object
- *
- * Clears the blob pointer
- */
-static void smack_msg_msg_free_security(struct msg_msg *msg)
-{
-       msg->security = NULL;
-}
-
 /**
  * smack_of_ipc - the smack pointer for the ipc
  * @isp: the object
@@ -2913,7 +2823,9 @@ static void smack_msg_msg_free_security(struct msg_msg *msg)
  */
 static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp)
 {
-       return (struct smack_known *)isp->security;
+       struct smack_known **blob = smack_ipc(isp);
+
+       return *blob;
 }
 
 /**
@@ -2924,23 +2836,12 @@ static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp)
  */
 static int smack_ipc_alloc_security(struct kern_ipc_perm *isp)
 {
-       struct smack_known *skp = smk_of_current();
+       struct smack_known **blob = smack_ipc(isp);
 
-       isp->security = skp;
+       *blob = smk_of_current();
        return 0;
 }
 
-/**
- * smack_ipc_free_security - Clear the security blob for ipc
- * @isp: the object
- *
- * Clears the blob pointer
- */
-static void smack_ipc_free_security(struct kern_ipc_perm *isp)
-{
-       isp->security = NULL;
-}
-
 /**
  * smk_curacc_shm : check if current has access on shm
  * @isp : the object
@@ -3238,7 +3139,8 @@ static int smack_msg_queue_msgrcv(struct kern_ipc_perm *isp, struct msg_msg *msg
  */
 static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
 {
-       struct smack_known *iskp = ipp->security;
+       struct smack_known **blob = smack_ipc(ipp);
+       struct smack_known *iskp = *blob;
        int may = smack_flags_to_may(flag);
        struct smk_audit_info ad;
        int rc;
@@ -3259,7 +3161,8 @@ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
  */
 static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
 {
-       struct smack_known *iskp = ipp->security;
+       struct smack_known **blob = smack_ipc(ipp);
+       struct smack_known *iskp = *blob;
 
        *secid = iskp->smk_secid;
 }
@@ -3287,7 +3190,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
        if (inode == NULL)
                return;
 
-       isp = inode->i_security;
+       isp = smack_inode(inode);
 
        mutex_lock(&isp->smk_lock);
        /*
@@ -3390,13 +3293,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
                 */
                final = &smack_known_star;
                /*
-                * Fall through.
-                *
                 * If a smack value has been set we want to use it,
                 * but since tmpfs isn't giving us the opportunity
                 * to set mount options simulate setting the
                 * superblock default.
                 */
+               /* Fall through */
        default:
                /*
                 * This isn't an understood special case.
@@ -3528,7 +3430,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
  */
 static int smack_setprocattr(const char *name, void *value, size_t size)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
        struct cred *new;
        struct smack_known *skp;
        struct smack_known_list_elem *sklep;
@@ -3569,7 +3471,7 @@ static int smack_setprocattr(const char *name, void *value, size_t size)
        if (new == NULL)
                return -ENOMEM;
 
-       tsp = new->security;
+       tsp = smack_cred(new);
        tsp->smk_task = skp;
        /*
         * process can change its label only once
@@ -4214,7 +4116,7 @@ static void smack_inet_csk_clone(struct sock *sk,
 static int smack_key_alloc(struct key *key, const struct cred *cred,
                           unsigned long flags)
 {
-       struct smack_known *skp = smk_of_task(cred->security);
+       struct smack_known *skp = smk_of_task(smack_cred(cred));
 
        key->security = skp;
        return 0;
@@ -4245,7 +4147,7 @@ static int smack_key_permission(key_ref_t key_ref,
 {
        struct key *keyp;
        struct smk_audit_info ad;
-       struct smack_known *tkp = smk_of_task(cred->security);
+       struct smack_known *tkp = smk_of_task(smack_cred(cred));
        int request = 0;
        int rc;
 
@@ -4520,12 +4422,12 @@ static int smack_inode_copy_up(struct dentry *dentry, struct cred **new)
                        return -ENOMEM;
        }
 
-       tsp = new_creds->security;
+       tsp = smack_cred(new_creds);
 
        /*
         * Get label from overlay inode and set it in create_sid
         */
-       isp = d_inode(dentry->d_parent)->i_security;
+       isp = smack_inode(d_inode(dentry->d_parent));
        skp = isp->smk_inode;
        tsp->smk_task = skp;
        *new = new_creds;
@@ -4548,8 +4450,8 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
                                        const struct cred *old,
                                        struct cred *new)
 {
-       struct task_smack *otsp = old->security;
-       struct task_smack *ntsp = new->security;
+       struct task_smack *otsp = smack_cred(old);
+       struct task_smack *ntsp = smack_cred(new);
        struct inode_smack *isp;
        int may;
 
@@ -4562,7 +4464,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
        /*
         * the attribute of the containing directory
         */
-       isp = d_inode(dentry->d_parent)->i_security;
+       isp = smack_inode(d_inode(dentry->d_parent));
 
        if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
                rcu_read_lock();
@@ -4582,6 +4484,14 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
        return 0;
 }
 
+struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
+       .lbs_cred = sizeof(struct task_smack),
+       .lbs_file = sizeof(struct smack_known *),
+       .lbs_inode = sizeof(struct inode_smack),
+       .lbs_ipc = sizeof(struct smack_known *),
+       .lbs_msg_msg = sizeof(struct smack_known *),
+};
+
 static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
        LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
@@ -4597,7 +4507,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds),
 
        LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security),
-       LSM_HOOK_INIT(inode_free_security, smack_inode_free_security),
        LSM_HOOK_INIT(inode_init_security, smack_inode_init_security),
        LSM_HOOK_INIT(inode_link, smack_inode_link),
        LSM_HOOK_INIT(inode_unlink, smack_inode_unlink),
@@ -4616,7 +4525,6 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),
 
        LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
-       LSM_HOOK_INIT(file_free_security, smack_file_free_security),
        LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
        LSM_HOOK_INIT(file_lock, smack_file_lock),
        LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),
@@ -4652,23 +4560,19 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(ipc_getsecid, smack_ipc_getsecid),
 
        LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security),
-       LSM_HOOK_INIT(msg_msg_free_security, smack_msg_msg_free_security),
 
        LSM_HOOK_INIT(msg_queue_alloc_security, smack_ipc_alloc_security),
-       LSM_HOOK_INIT(msg_queue_free_security, smack_ipc_free_security),
        LSM_HOOK_INIT(msg_queue_associate, smack_msg_queue_associate),
        LSM_HOOK_INIT(msg_queue_msgctl, smack_msg_queue_msgctl),
        LSM_HOOK_INIT(msg_queue_msgsnd, smack_msg_queue_msgsnd),
        LSM_HOOK_INIT(msg_queue_msgrcv, smack_msg_queue_msgrcv),
 
        LSM_HOOK_INIT(shm_alloc_security, smack_ipc_alloc_security),
-       LSM_HOOK_INIT(shm_free_security, smack_ipc_free_security),
        LSM_HOOK_INIT(shm_associate, smack_shm_associate),
        LSM_HOOK_INIT(shm_shmctl, smack_shm_shmctl),
        LSM_HOOK_INIT(shm_shmat, smack_shm_shmat),
 
        LSM_HOOK_INIT(sem_alloc_security, smack_ipc_alloc_security),
-       LSM_HOOK_INIT(sem_free_security, smack_ipc_free_security),
        LSM_HOOK_INIT(sem_associate, smack_sem_associate),
        LSM_HOOK_INIT(sem_semctl, smack_sem_semctl),
        LSM_HOOK_INIT(sem_semop, smack_sem_semop),
@@ -4759,23 +4663,23 @@ static __init void init_smack_known_list(void)
  */
 static __init int smack_init(void)
 {
-       struct cred *cred;
+       struct cred *cred = (struct cred *) current->cred;
        struct task_smack *tsp;
 
-       if (!security_module_enable("smack"))
-               return 0;
-
        smack_inode_cache = KMEM_CACHE(inode_smack, 0);
        if (!smack_inode_cache)
                return -ENOMEM;
 
-       tsp = new_task_smack(&smack_known_floor, &smack_known_floor,
-                               GFP_KERNEL);
-       if (tsp == NULL) {
-               kmem_cache_destroy(smack_inode_cache);
-               return -ENOMEM;
-       }
+       /*
+        * Set the security state for the initial task.
+        */
+       tsp = smack_cred(cred);
+       init_task_smack(tsp, &smack_known_floor, &smack_known_floor);
 
+       /*
+        * Register with LSM
+        */
+       security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
        smack_enabled = 1;
 
        pr_info("Smack:  Initializing.\n");
@@ -4789,20 +4693,9 @@ static __init int smack_init(void)
        pr_info("Smack:  IPv6 Netfilter enabled.\n");
 #endif
 
-       /*
-        * Set the security state for the initial task.
-        */
-       cred = (struct cred *) current->cred;
-       cred->security = tsp;
-
        /* initialize the smack_known_list */
        init_smack_known_list();
 
-       /*
-        * Register with LSM
-        */
-       security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
-
        return 0;
 }
 
@@ -4812,5 +4705,7 @@ static __init int smack_init(void)
  */
 DEFINE_LSM(smack) = {
        .name = "smack",
+       .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+       .blobs = &smack_blob_sizes,
        .init = smack_init,
 };
index 06b517075ec06acad0b213d4aa27eec10986f436..faf2ea3968b33f9cc69b778100532c3f3bef1b47 100644 (file)
@@ -2208,14 +2208,14 @@ static const struct file_operations smk_logging_ops = {
 
 static void *load_self_seq_start(struct seq_file *s, loff_t *pos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_seq_start(s, pos, &tsp->smk_rules);
 }
 
 static void *load_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_seq_next(s, v, pos, &tsp->smk_rules);
 }
@@ -2262,7 +2262,7 @@ static int smk_open_load_self(struct inode *inode, struct file *file)
 static ssize_t smk_write_load_self(struct file *file, const char __user *buf,
                              size_t count, loff_t *ppos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules,
                                    &tsp->smk_rules_lock, SMK_FIXED24_FMT);
@@ -2414,14 +2414,14 @@ static const struct file_operations smk_load2_ops = {
 
 static void *load_self2_seq_start(struct seq_file *s, loff_t *pos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_seq_start(s, pos, &tsp->smk_rules);
 }
 
 static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_seq_next(s, v, pos, &tsp->smk_rules);
 }
@@ -2467,7 +2467,7 @@ static int smk_open_load_self2(struct inode *inode, struct file *file)
 static ssize_t smk_write_load_self2(struct file *file, const char __user *buf,
                              size_t count, loff_t *ppos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules,
                                    &tsp->smk_rules_lock, SMK_LONG_FMT);
@@ -2681,14 +2681,14 @@ static const struct file_operations smk_syslog_ops = {
 
 static void *relabel_self_seq_start(struct seq_file *s, loff_t *pos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_seq_start(s, pos, &tsp->smk_relabel);
 }
 
 static void *relabel_self_seq_next(struct seq_file *s, void *v, loff_t *pos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
 
        return smk_seq_next(s, v, pos, &tsp->smk_relabel);
 }
@@ -2736,7 +2736,7 @@ static int smk_open_relabel_self(struct inode *inode, struct file *file)
 static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
                                size_t count, loff_t *ppos)
 {
-       struct task_smack *tsp = current_security();
+       struct task_smack *tsp = smack_cred(current_cred());
        char *data;
        int rc;
        LIST_HEAD(list_tmp);
index 479b03a7a17effb75a81212f48fa16580dc7fc3a..3c96e8402e94d516f9665e4a544496c5ea87572e 100644 (file)
@@ -32,6 +32,7 @@ static char *tomoyo_print_bprm(struct linux_binprm *bprm,
        int argv_count = bprm->argc;
        int envp_count = bprm->envc;
        bool truncated = false;
+
        if (!buffer)
                return NULL;
        len = snprintf(buffer, tomoyo_buffer_len - 1, "argv[]={ ");
@@ -49,6 +50,7 @@ static char *tomoyo_print_bprm(struct linux_binprm *bprm,
                while (offset < PAGE_SIZE) {
                        const char *kaddr = dump->data;
                        const unsigned char c = kaddr[offset++];
+
                        if (cp == last_start)
                                *cp++ = '"';
                        if (cp >= buffer + tomoyo_buffer_len - 32) {
@@ -154,19 +156,18 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
        char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
        int pos;
        u8 i;
+
        if (!buffer)
                return NULL;
 
        tomoyo_convert_time(ktime_get_real_seconds(), &stamp);
 
        pos = snprintf(buffer, tomoyo_buffer_len - 1,
-                      "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s "
-                      "granted=%s (global-pid=%u) task={ pid=%u ppid=%u "
-                      "uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u "
-                      "fsuid=%u fsgid=%u }", stamp.year, stamp.month,
-                      stamp.day, stamp.hour, stamp.min, stamp.sec, r->profile,
-                      tomoyo_mode[r->mode], tomoyo_yesno(r->granted), gpid,
-                      tomoyo_sys_getpid(), tomoyo_sys_getppid(),
+                      "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s granted=%s (global-pid=%u) task={ pid=%u ppid=%u uid=%u gid=%u euid=%u egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
+                      stamp.year, stamp.month, stamp.day, stamp.hour,
+                      stamp.min, stamp.sec, r->profile, tomoyo_mode[r->mode],
+                      tomoyo_yesno(r->granted), gpid, tomoyo_sys_getpid(),
+                      tomoyo_sys_getppid(),
                       from_kuid(&init_user_ns, current_uid()),
                       from_kgid(&init_user_ns, current_gid()),
                       from_kuid(&init_user_ns, current_euid()),
@@ -185,6 +186,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
                struct tomoyo_mini_stat *stat;
                unsigned int dev;
                umode_t mode;
+
                if (!obj->stat_valid[i])
                        continue;
                stat = &obj->stat[i];
@@ -193,8 +195,8 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
                if (i & 1) {
                        pos += snprintf(buffer + pos,
                                        tomoyo_buffer_len - 1 - pos,
-                                       " path%u.parent={ uid=%u gid=%u "
-                                       "ino=%lu perm=0%o }", (i >> 1) + 1,
+                                       " path%u.parent={ uid=%u gid=%u ino=%lu perm=0%o }",
+                                       (i >> 1) + 1,
                                        from_kuid(&init_user_ns, stat->uid),
                                        from_kgid(&init_user_ns, stat->gid),
                                        (unsigned long)stat->ino,
@@ -202,8 +204,8 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r)
                        continue;
                }
                pos += snprintf(buffer + pos, tomoyo_buffer_len - 1 - pos,
-                               " path%u={ uid=%u gid=%u ino=%lu major=%u"
-                               " minor=%u perm=0%o type=%s", (i >> 1) + 1,
+                               " path%u={ uid=%u gid=%u ino=%lu major=%u minor=%u perm=0%o type=%s",
+                               (i >> 1) + 1,
                                from_kuid(&init_user_ns, stat->uid),
                                from_kgid(&init_user_ns, stat->gid),
                                (unsigned long)stat->ino,
@@ -249,6 +251,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
        const char *symlink = NULL;
        int pos;
        const char *domainname = r->domain->domainname->name;
+
        header = tomoyo_print_header(r);
        if (!header)
                return NULL;
@@ -256,6 +259,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
        len += strlen(domainname) + strlen(header) + 10;
        if (r->ee) {
                struct file *file = r->ee->bprm->file;
+
                realpath = tomoyo_realpath_from_path(&file->f_path);
                bprm_info = tomoyo_print_bprm(r->ee->bprm, &r->ee->dump);
                if (!realpath || !bprm_info)
@@ -275,6 +279,7 @@ char *tomoyo_init_log(struct tomoyo_request_info *r, int len, const char *fmt,
        pos = snprintf(buf, len, "%s", header);
        if (realpath) {
                struct linux_binprm *bprm = r->ee->bprm;
+
                pos += snprintf(buf + pos, len - pos,
                                " exec={ realpath=\"%s\" argc=%d envc=%d %s }",
                                realpath, bprm->argc, bprm->envc, bprm_info);
@@ -328,6 +333,7 @@ static bool tomoyo_get_audit(const struct tomoyo_policy_namespace *ns,
        const u8 category = tomoyo_index2category[index] +
                TOMOYO_MAX_MAC_INDEX;
        struct tomoyo_profile *p;
+
        if (!tomoyo_policy_loaded)
                return false;
        p = tomoyo_profile(ns, profile);
@@ -362,6 +368,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
        char *buf;
        struct tomoyo_log *entry;
        bool quota_exceeded = false;
+
        if (!tomoyo_get_audit(r->domain->ns, r->profile, r->type,
                              r->matched_acl, r->granted))
                goto out;
@@ -413,6 +420,7 @@ void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
 {
        va_list args;
        int len;
+
        va_start(args, fmt);
        len = vsnprintf((char *) &len, 1, fmt, args) + 1;
        va_end(args);
@@ -431,6 +439,7 @@ void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...)
 void tomoyo_read_log(struct tomoyo_io_buffer *head)
 {
        struct tomoyo_log *ptr = NULL;
+
        if (head->r.w_pos)
                return;
        kfree(head->read_buf);
index c598aa00d5e3170206eca0914216eec52ee3fef9..57988d95d33de2050bacd73cfc6252cf8d836861 100644 (file)
@@ -197,6 +197,7 @@ static void tomoyo_addprintf(char *buffer, int len, const char *fmt, ...)
 {
        va_list args;
        const int pos = strlen(buffer);
+
        va_start(args, fmt);
        vsnprintf(buffer + pos, len - pos - 1, fmt, args);
        va_end(args);
@@ -214,6 +215,7 @@ static bool tomoyo_flush(struct tomoyo_io_buffer *head)
        while (head->r.w_pos) {
                const char *w = head->r.w[0];
                size_t len = strlen(w);
+
                if (len) {
                        if (len > head->read_user_buf_avail)
                                len = head->read_user_buf_avail;
@@ -279,6 +281,7 @@ static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt,
        size_t len;
        size_t pos = head->r.avail;
        int size = head->readbuf_size - pos;
+
        if (size <= 0)
                return;
        va_start(args, fmt);
@@ -344,13 +347,14 @@ static bool tomoyo_namespace_enabled;
 void tomoyo_init_policy_namespace(struct tomoyo_policy_namespace *ns)
 {
        unsigned int idx;
+
        for (idx = 0; idx < TOMOYO_MAX_ACL_GROUPS; idx++)
                INIT_LIST_HEAD(&ns->acl_group[idx]);
        for (idx = 0; idx < TOMOYO_MAX_GROUP; idx++)
                INIT_LIST_HEAD(&ns->group_list[idx]);
        for (idx = 0; idx < TOMOYO_MAX_POLICY; idx++)
                INIT_LIST_HEAD(&ns->policy_list[idx]);
-       ns->profile_version = 20110903;
+       ns->profile_version = 20150505;
        tomoyo_namespace_enabled = !list_empty(&tomoyo_namespace_list);
        list_add_tail_rcu(&ns->namespace_list, &tomoyo_namespace_list);
 }
@@ -433,6 +437,7 @@ static void tomoyo_print_number_union_nospace
                u8 min_type = ptr->value_type[0];
                const u8 max_type = ptr->value_type[1];
                char buffer[128];
+
                buffer[0] = '\0';
                for (i = 0; i < 2; i++) {
                        switch (min_type) {
@@ -487,6 +492,7 @@ static struct tomoyo_profile *tomoyo_assign_profile
 {
        struct tomoyo_profile *ptr;
        struct tomoyo_profile *entry;
+
        if (profile >= TOMOYO_MAX_PROFILES)
                return NULL;
        ptr = ns->profile_ptr[profile];
@@ -530,6 +536,7 @@ struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
 {
        static struct tomoyo_profile tomoyo_null_profile;
        struct tomoyo_profile *ptr = ns->profile_ptr[profile];
+
        if (!ptr)
                ptr = &tomoyo_null_profile;
        return ptr;
@@ -546,6 +553,7 @@ struct tomoyo_profile *tomoyo_profile(const struct tomoyo_policy_namespace *ns,
 static s8 tomoyo_find_yesno(const char *string, const char *find)
 {
        const char *cp = strstr(string, find);
+
        if (cp) {
                cp += strlen(find);
                if (!strncmp(cp, "=yes", 4))
@@ -569,6 +577,7 @@ static void tomoyo_set_uint(unsigned int *i, const char *string,
                            const char *find)
 {
        const char *cp = strstr(string, find);
+
        if (cp)
                sscanf(cp + strlen(find), "=%u", i);
 }
@@ -587,6 +596,7 @@ static int tomoyo_set_mode(char *name, const char *value,
 {
        u8 i;
        u8 config;
+
        if (!strcmp(name, "CONFIG")) {
                i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
                config = profile->default_config;
@@ -595,10 +605,12 @@ static int tomoyo_set_mode(char *name, const char *value,
                for (i = 0; i < TOMOYO_MAX_MAC_INDEX
                             + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
                        int len = 0;
+
                        if (i < TOMOYO_MAX_MAC_INDEX) {
                                const u8 c = tomoyo_index2category[i];
                                const char *category =
                                        tomoyo_category_keywords[c];
+
                                len = strlen(category);
                                if (strncmp(name, category, len) ||
                                    name[len++] != ':' || name[len++] != ':')
@@ -618,6 +630,7 @@ static int tomoyo_set_mode(char *name, const char *value,
                config = TOMOYO_CONFIG_USE_DEFAULT;
        } else {
                u8 mode;
+
                for (mode = 0; mode < 4; mode++)
                        if (strstr(value, tomoyo_mode[mode]))
                                /*
@@ -664,6 +677,7 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
        unsigned int i;
        char *cp;
        struct tomoyo_profile *profile;
+
        if (sscanf(data, "PROFILE_VERSION=%u", &head->w.ns->profile_version)
            == 1)
                return 0;
@@ -683,6 +697,7 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
                const struct tomoyo_path_info *new_comment
                        = tomoyo_get_name(cp);
                const struct tomoyo_path_info *old_comment;
+
                if (!new_comment)
                        return -ENOMEM;
                spin_lock(&lock);
@@ -732,6 +747,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
        struct tomoyo_policy_namespace *ns =
                container_of(head->r.ns, typeof(*ns), namespace_list);
        const struct tomoyo_profile *profile;
+
        if (head->r.eof)
                return;
  next:
@@ -760,6 +776,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                        u8 i;
                        const struct tomoyo_path_info *comment =
                                profile->comment;
+
                        tomoyo_print_namespace(head);
                        tomoyo_io_printf(head, "%u-COMMENT=", index);
                        tomoyo_set_string(head, comment ? comment->name : "");
@@ -788,6 +805,7 @@ static void tomoyo_read_profile(struct tomoyo_io_buffer *head)
                              + TOMOYO_MAX_MAC_CATEGORY_INDEX; head->r.bit++) {
                        const u8 i = head->r.bit;
                        const u8 config = profile->config[i];
+
                        if (config == TOMOYO_CONFIG_USE_DEFAULT)
                                continue;
                        tomoyo_print_namespace(head);
@@ -847,10 +865,10 @@ static int tomoyo_update_manager_entry(const char *manager,
        struct tomoyo_acl_param param = {
                /* .ns = &tomoyo_kernel_namespace, */
                .is_delete = is_delete,
-               .list = &tomoyo_kernel_namespace.
-               policy_list[TOMOYO_ID_MANAGER],
+               .list = &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER],
        };
        int error = is_delete ? -ENOENT : -ENOMEM;
+
        if (!tomoyo_correct_domain(manager) &&
            !tomoyo_correct_word(manager))
                return -EINVAL;
@@ -894,10 +912,10 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer *head)
 {
        if (head->r.eof)
                return;
-       list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.
-                            policy_list[TOMOYO_ID_MANAGER]) {
+       list_for_each_cookie(head->r.acl, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER]) {
                struct tomoyo_manager *ptr =
                        list_entry(head->r.acl, typeof(*ptr), head.list);
+
                if (ptr->head.is_deleted)
                        continue;
                if (!tomoyo_flush(head))
@@ -933,8 +951,7 @@ static bool tomoyo_manager(void)
        exe = tomoyo_get_exe();
        if (!exe)
                return false;
-       list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.
-                               policy_list[TOMOYO_ID_MANAGER], head.list) {
+       list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace.policy_list[TOMOYO_ID_MANAGER], head.list) {
                if (!ptr->head.is_deleted &&
                    (!tomoyo_pathcmp(domainname, ptr->manager) ||
                     !strcmp(exe, ptr->manager->name))) {
@@ -945,9 +962,10 @@ static bool tomoyo_manager(void)
        if (!found) { /* Reduce error messages. */
                static pid_t last_pid;
                const pid_t pid = current->pid;
+
                if (last_pid != pid) {
-                       printk(KERN_WARNING "%s ( %s ) is not permitted to "
-                              "update policies.\n", domainname->name, exe);
+                       pr_warn("%s ( %s ) is not permitted to update policies.\n",
+                               domainname->name, exe);
                        last_pid = pid;
                }
        }
@@ -974,19 +992,21 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
        unsigned int pid;
        struct tomoyo_domain_info *domain = NULL;
        bool global_pid = false;
+
        if (strncmp(data, "select ", 7))
                return false;
        data += 7;
        if (sscanf(data, "pid=%u", &pid) == 1 ||
            (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
                struct task_struct *p;
+
                rcu_read_lock();
                if (global_pid)
                        p = find_task_by_pid_ns(pid, &init_pid_ns);
                else
                        p = find_task_by_vpid(pid);
                if (p)
-                       domain = tomoyo_real_domain(p);
+                       domain = tomoyo_task(p)->domain_info;
                rcu_read_unlock();
        } else if (!strncmp(data, "domain=", 7)) {
                if (tomoyo_domain_def(data + 7))
@@ -1020,10 +1040,11 @@ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head,
  * Returns true if @a == @b, false otherwise.
  */
 static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
-                             const struct tomoyo_acl_info *b)
+                                const struct tomoyo_acl_info *b)
 {
        const struct tomoyo_task_acl *p1 = container_of(a, typeof(*p1), head);
        const struct tomoyo_task_acl *p2 = container_of(b, typeof(*p2), head);
+
        return p1->domainname == p2->domainname;
 }
 
@@ -1039,11 +1060,13 @@ static bool tomoyo_same_task_acl(const struct tomoyo_acl_info *a,
 static int tomoyo_write_task(struct tomoyo_acl_param *param)
 {
        int error = -EINVAL;
+
        if (tomoyo_str_starts(&param->data, "manual_domain_transition ")) {
                struct tomoyo_task_acl e = {
                        .head.type = TOMOYO_TYPE_MANUAL_TASK_ACL,
                        .domainname = tomoyo_get_domainname(param),
                };
+
                if (e.domainname)
                        error = tomoyo_update_domain(&e.head, sizeof(e), param,
                                                     tomoyo_same_task_acl,
@@ -1110,7 +1133,7 @@ static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns,
        };
        static const struct {
                const char *keyword;
-               int (*write) (struct tomoyo_acl_param *);
+               int (*write)(struct tomoyo_acl_param *param);
        } tomoyo_callback[5] = {
                { "file ", tomoyo_write_file },
                { "network inet ", tomoyo_write_inet_network },
@@ -1151,9 +1174,11 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
        struct tomoyo_domain_info *domain = head->w.domain;
        const bool is_delete = head->w.is_delete;
        bool is_select = !is_delete && tomoyo_str_starts(&data, "select ");
-       unsigned int profile;
+       unsigned int idx;
+
        if (*data == '<') {
                int ret = 0;
+
                domain = NULL;
                if (is_delete)
                        ret = tomoyo_delete_domain(data);
@@ -1167,23 +1192,27 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
        if (!domain)
                return -EINVAL;
        ns = domain->ns;
-       if (sscanf(data, "use_profile %u", &profile) == 1
-           && profile < TOMOYO_MAX_PROFILES) {
-               if (!tomoyo_policy_loaded || ns->profile_ptr[profile])
-                       domain->profile = (u8) profile;
+       if (sscanf(data, "use_profile %u", &idx) == 1
+           && idx < TOMOYO_MAX_PROFILES) {
+               if (!tomoyo_policy_loaded || ns->profile_ptr[idx])
+                       if (!is_delete)
+                               domain->profile = (u8) idx;
                return 0;
        }
-       if (sscanf(data, "use_group %u\n", &profile) == 1
-           && profile < TOMOYO_MAX_ACL_GROUPS) {
+       if (sscanf(data, "use_group %u\n", &idx) == 1
+           && idx < TOMOYO_MAX_ACL_GROUPS) {
                if (!is_delete)
-                       domain->group = (u8) profile;
+                       set_bit(idx, domain->group);
+               else
+                       clear_bit(idx, domain->group);
                return 0;
        }
-       for (profile = 0; profile < TOMOYO_MAX_DOMAIN_INFO_FLAGS; profile++) {
-               const char *cp = tomoyo_dif[profile];
+       for (idx = 0; idx < TOMOYO_MAX_DOMAIN_INFO_FLAGS; idx++) {
+               const char *cp = tomoyo_dif[idx];
+
                if (strncmp(data, cp, strlen(cp) - 1))
                        continue;
-               domain->flags[profile] = !is_delete;
+               domain->flags[idx] = !is_delete;
                return 0;
        }
        return tomoyo_write_domain2(ns, &domain->acl_info_list, data,
@@ -1225,9 +1254,11 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
                        const struct tomoyo_envp *envp =
                                (typeof(envp)) (argv + cond->argc);
                        u16 skip;
+
                        for (skip = 0; skip < head->r.cond_index; skip++) {
                                const u8 left = condp->left;
                                const u8 right = condp->right;
+
                                condp++;
                                switch (left) {
                                case TOMOYO_ARGV_ENTRY:
@@ -1253,6 +1284,7 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
                                const u8 match = condp->equals;
                                const u8 left = condp->left;
                                const u8 right = condp->right;
+
                                if (!tomoyo_flush(head))
                                        return false;
                                condp++;
@@ -1262,8 +1294,7 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
                                case TOMOYO_ARGV_ENTRY:
                                        tomoyo_io_printf(head,
                                                         "exec.argv[%lu]%s=\"",
-                                                        argv->index, argv->
-                                                        is_not ? "!" : "");
+                                                        argv->index, argv->is_not ? "!" : "");
                                        tomoyo_set_string(head,
                                                          argv->value->name);
                                        tomoyo_set_string(head, "\"");
@@ -1274,12 +1305,10 @@ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head,
                                                          "exec.envp[\"");
                                        tomoyo_set_string(head,
                                                          envp->name->name);
-                                       tomoyo_io_printf(head, "\"]%s=", envp->
-                                                        is_not ? "!" : "");
+                                       tomoyo_io_printf(head, "\"]%s=", envp->is_not ? "!" : "");
                                        if (envp->value) {
                                                tomoyo_set_string(head, "\"");
-                                               tomoyo_set_string(head, envp->
-                                                                 value->name);
+                                               tomoyo_set_string(head, envp->value->name);
                                                tomoyo_set_string(head, "\"");
                                        } else {
                                                tomoyo_set_string(head,
@@ -1375,6 +1404,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
                struct tomoyo_path_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
                const u16 perm = ptr->perm;
+
                for (bit = 0; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
                        if (!(perm & (1 << bit)))
                                continue;
@@ -1395,6 +1425,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
        } else if (acl_type == TOMOYO_TYPE_MANUAL_TASK_ACL) {
                struct tomoyo_task_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
+
                tomoyo_set_group(head, "task ");
                tomoyo_set_string(head, "manual_domain_transition ");
                tomoyo_set_string(head, ptr->domainname->name);
@@ -1404,6 +1435,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
                struct tomoyo_path2_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
                const u8 perm = ptr->perm;
+
                for (bit = 0; bit < TOMOYO_MAX_PATH2_OPERATION; bit++) {
                        if (!(perm & (1 << bit)))
                                continue;
@@ -1424,6 +1456,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
                struct tomoyo_path_number_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
                const u8 perm = ptr->perm;
+
                for (bit = 0; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION; bit++) {
                        if (!(perm & (1 << bit)))
                                continue;
@@ -1444,6 +1477,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
                struct tomoyo_mkdev_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
                const u8 perm = ptr->perm;
+
                for (bit = 0; bit < TOMOYO_MAX_MKDEV_OPERATION; bit++) {
                        if (!(perm & (1 << bit)))
                                continue;
@@ -1490,6 +1524,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
                                          ->name);
                } else {
                        char buf[128];
+
                        tomoyo_print_ip(buf, sizeof(buf), &ptr->address);
                        tomoyo_io_printf(head, "%s", buf);
                }
@@ -1519,6 +1554,7 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
        } else if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
                struct tomoyo_mount_acl *ptr =
                        container_of(acl, typeof(*ptr), head);
+
                tomoyo_set_group(head, "file mount");
                tomoyo_print_name_union(head, &ptr->dev_name);
                tomoyo_print_name_union(head, &ptr->dir_name);
@@ -1562,6 +1598,7 @@ static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head,
        list_for_each_cookie(head->r.acl, list) {
                struct tomoyo_acl_info *ptr =
                        list_entry(head->r.acl, typeof(*ptr), list);
+
                if (!tomoyo_print_entry(head, ptr))
                        return false;
        }
@@ -1583,8 +1620,9 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
        list_for_each_cookie(head->r.domain, &tomoyo_domain_list) {
                struct tomoyo_domain_info *domain =
                        list_entry(head->r.domain, typeof(*domain), list);
+               u8 i;
+
                switch (head->r.step) {
-                       u8 i;
                case 0:
                        if (domain->is_deleted &&
                            !head->r.print_this_domain_only)
@@ -1594,22 +1632,33 @@ static void tomoyo_read_domain(struct tomoyo_io_buffer *head)
                        tomoyo_set_lf(head);
                        tomoyo_io_printf(head, "use_profile %u\n",
                                         domain->profile);
-                       tomoyo_io_printf(head, "use_group %u\n",
-                                        domain->group);
                        for (i = 0; i < TOMOYO_MAX_DOMAIN_INFO_FLAGS; i++)
                                if (domain->flags[i])
                                        tomoyo_set_string(head, tomoyo_dif[i]);
+                       head->r.index = 0;
                        head->r.step++;
-                       tomoyo_set_lf(head);
                        /* fall through */
                case 1:
+                       while (head->r.index < TOMOYO_MAX_ACL_GROUPS) {
+                               i = head->r.index++;
+                               if (!test_bit(i, domain->group))
+                                       continue;
+                               tomoyo_io_printf(head, "use_group %u\n", i);
+                               if (!tomoyo_flush(head))
+                                       return;
+                       }
+                       head->r.index = 0;
+                       head->r.step++;
+                       tomoyo_set_lf(head);
+                       /* fall through */
+               case 2:
                        if (!tomoyo_read_domain2(head, &domain->acl_info_list))
                                return;
                        head->r.step++;
                        if (!tomoyo_set_lf(head))
                                return;
                        /* fall through */
-               case 2:
+               case 3:
                        head->r.step = 0;
                        if (head->r.print_this_domain_only)
                                goto done;
@@ -1668,7 +1717,7 @@ static void tomoyo_read_pid(struct tomoyo_io_buffer *head)
        else
                p = find_task_by_vpid(pid);
        if (p)
-               domain = tomoyo_real_domain(p);
+               domain = tomoyo_task(p)->domain_info;
        rcu_read_unlock();
        if (!domain)
                return;
@@ -1711,6 +1760,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
                .data = head->write_buf,
        };
        u8 i;
+
        if (tomoyo_str_starts(&param.data, "aggregator "))
                return tomoyo_write_aggregator(&param);
        for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
@@ -1722,6 +1772,7 @@ static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
        if (tomoyo_str_starts(&param.data, "acl_group ")) {
                unsigned int group;
                char *data;
+
                group = simple_strtoul(param.data, &data, 10);
                if (group < TOMOYO_MAX_ACL_GROUPS && *data++ == ' ')
                        return tomoyo_write_domain2
@@ -1746,12 +1797,15 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
        struct tomoyo_policy_namespace *ns =
                container_of(head->r.ns, typeof(*ns), namespace_list);
        struct list_head *list = &ns->group_list[idx];
+
        list_for_each_cookie(head->r.group, list) {
                struct tomoyo_group *group =
                        list_entry(head->r.group, typeof(*group), head.list);
+
                list_for_each_cookie(head->r.acl, &group->member_list) {
                        struct tomoyo_acl_head *ptr =
                                list_entry(head->r.acl, typeof(*ptr), list);
+
                        if (ptr->is_deleted)
                                continue;
                        if (!tomoyo_flush(head))
@@ -1771,10 +1825,10 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx)
                                                           head)->number);
                        } else if (idx == TOMOYO_ADDRESS_GROUP) {
                                char buffer[128];
-
                                struct tomoyo_address_group *member =
                                        container_of(ptr, typeof(*member),
                                                     head);
+
                                tomoyo_print_ip(buffer, sizeof(buffer),
                                                &member->address);
                                tomoyo_io_printf(head, " %s", buffer);
@@ -1802,6 +1856,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
        struct tomoyo_policy_namespace *ns =
                container_of(head->r.ns, typeof(*ns), namespace_list);
        struct list_head *list = &ns->policy_list[idx];
+
        list_for_each_cookie(head->r.acl, list) {
                struct tomoyo_acl_head *acl =
                        container_of(head->r.acl, typeof(*acl), list);
@@ -1814,6 +1869,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
                        {
                                struct tomoyo_transition_control *ptr =
                                        container_of(acl, typeof(*ptr), head);
+
                                tomoyo_print_namespace(head);
                                tomoyo_set_string(head, tomoyo_transition_type
                                                  [ptr->type]);
@@ -1829,6 +1885,7 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int idx)
                        {
                                struct tomoyo_aggregator *ptr =
                                        container_of(acl, typeof(*ptr), head);
+
                                tomoyo_print_namespace(head);
                                tomoyo_set_string(head, "aggregator ");
                                tomoyo_set_string(head,
@@ -1858,6 +1915,7 @@ static void tomoyo_read_exception(struct tomoyo_io_buffer *head)
 {
        struct tomoyo_policy_namespace *ns =
                container_of(head->r.ns, typeof(*ns), namespace_list);
+
        if (head->r.eof)
                return;
        while (head->r.step < TOMOYO_MAX_POLICY &&
@@ -1921,6 +1979,7 @@ static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
 static int tomoyo_truncate(char *str)
 {
        char *start = str;
+
        while (*(unsigned char *) str > (unsigned char) ' ')
                str++;
        *str = '\0';
@@ -1943,6 +2002,7 @@ static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *header)
        char *symlink = NULL;
        char *cp = strchr(header, '\n');
        int len;
+
        if (!cp)
                return;
        cp = strchr(cp + 1, '\n');
@@ -2002,6 +2062,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
        static unsigned int tomoyo_serial;
        struct tomoyo_query entry = { };
        bool quota_exceeded = false;
+
        va_start(args, fmt);
        len = vsnprintf((char *) &len, 1, fmt, args) + 1;
        va_end(args);
@@ -2063,8 +2124,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
                    (tomoyo_answer_wait, entry.answer ||
                     !atomic_read(&tomoyo_query_observers), HZ))
                        break;
-               else
-                       entry.timer++;
+               entry.timer++;
        }
        spin_lock(&tomoyo_query_list_lock);
        list_del(&entry.list);
@@ -2100,6 +2160,7 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid
 {
        struct tomoyo_query *ptr;
        struct tomoyo_domain_info *domain = NULL;
+
        spin_lock(&tomoyo_query_list_lock);
        list_for_each_entry(ptr, &tomoyo_query_list, list) {
                if (ptr->serial != serial)
@@ -2142,15 +2203,15 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
        unsigned int pos = 0;
        size_t len = 0;
        char *buf;
+
        if (head->r.w_pos)
                return;
-       if (head->read_buf) {
-               kfree(head->read_buf);
-               head->read_buf = NULL;
-       }
+       kfree(head->read_buf);
+       head->read_buf = NULL;
        spin_lock(&tomoyo_query_list_lock);
        list_for_each(tmp, &tomoyo_query_list) {
                struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+
                if (pos++ != head->r.query_index)
                        continue;
                len = ptr->query_len;
@@ -2168,6 +2229,7 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head)
        spin_lock(&tomoyo_query_list_lock);
        list_for_each(tmp, &tomoyo_query_list) {
                struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+
                if (pos++ != head->r.query_index)
                        continue;
                /*
@@ -2202,9 +2264,11 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
        struct list_head *tmp;
        unsigned int serial;
        unsigned int answer;
+
        spin_lock(&tomoyo_query_list_lock);
        list_for_each(tmp, &tomoyo_query_list) {
                struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+
                ptr->timer = 0;
        }
        spin_unlock(&tomoyo_query_list_lock);
@@ -2213,6 +2277,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
        spin_lock(&tomoyo_query_list_lock);
        list_for_each(tmp, &tomoyo_query_list) {
                struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list);
+
                if (ptr->serial != serial)
                        continue;
                ptr->answer = answer;
@@ -2235,7 +2300,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
 static void tomoyo_read_version(struct tomoyo_io_buffer *head)
 {
        if (!head->r.eof) {
-               tomoyo_io_printf(head, "2.5.0");
+               tomoyo_io_printf(head, "2.6.0");
                head->r.eof = true;
        }
 }
@@ -2287,6 +2352,7 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
 {
        u8 i;
        unsigned int total = 0;
+
        if (head->r.eof)
                return;
        for (i = 0; i < TOMOYO_MAX_POLICY_STAT; i++) {
@@ -2295,9 +2361,9 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
                                 tomoyo_stat_updated[i]);
                if (tomoyo_stat_modified[i]) {
                        struct tomoyo_time stamp;
+
                        tomoyo_convert_time(tomoyo_stat_modified[i], &stamp);
-                       tomoyo_io_printf(head, " (Last: %04u/%02u/%02u "
-                                        "%02u:%02u:%02u)",
+                       tomoyo_io_printf(head, " (Last: %04u/%02u/%02u %02u:%02u:%02u)",
                                         stamp.year, stamp.month, stamp.day,
                                         stamp.hour, stamp.min, stamp.sec);
                }
@@ -2305,6 +2371,7 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer *head)
        }
        for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++) {
                unsigned int used = tomoyo_memory_used[i];
+
                total += used;
                tomoyo_io_printf(head, "Memory used by %-22s %10u",
                                 tomoyo_memory_headers[i], used);
@@ -2329,6 +2396,7 @@ static int tomoyo_write_stat(struct tomoyo_io_buffer *head)
 {
        char *data = head->write_buf;
        u8 i;
+
        if (tomoyo_str_starts(&data, "Memory used by "))
                for (i = 0; i < TOMOYO_MAX_MEMORY_STAT; i++)
                        if (tomoyo_str_starts(&data, tomoyo_memory_headers[i]))
@@ -2457,6 +2525,7 @@ int tomoyo_open_control(const u8 type, struct file *file)
 __poll_t tomoyo_poll_control(struct file *file, poll_table *wait)
 {
        struct tomoyo_io_buffer *head = file->private_data;
+
        if (head->poll)
                return head->poll(file, wait) | EPOLLOUT | EPOLLWRNORM;
        return EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;
@@ -2472,6 +2541,7 @@ __poll_t tomoyo_poll_control(struct file *file, poll_table *wait)
 static inline void tomoyo_set_namespace_cursor(struct tomoyo_io_buffer *head)
 {
        struct list_head *ns;
+
        if (head->type != TOMOYO_EXCEPTIONPOLICY &&
            head->type != TOMOYO_PROFILE)
                return;
@@ -2517,7 +2587,7 @@ ssize_t tomoyo_read_control(struct tomoyo_io_buffer *head, char __user *buffer,
        int idx;
 
        if (!head->read)
-               return -ENOSYS;
+               return -EINVAL;
        if (mutex_lock_interruptible(&head->io_sem))
                return -EINTR;
        head->read_user_buf = buffer;
@@ -2557,6 +2627,7 @@ static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line)
            head->type == TOMOYO_PROFILE) {
                if (*line == '<') {
                        char *cp = strchr(line, ' ');
+
                        if (cp) {
                                *cp++ = '\0';
                                head->w.ns = tomoyo_assign_namespace(line);
@@ -2589,8 +2660,9 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
        size_t avail_len = buffer_len;
        char *cp0 = head->write_buf;
        int idx;
+
        if (!head->write)
-               return -ENOSYS;
+               return -EINVAL;
        if (!access_ok(buffer, buffer_len))
                return -EFAULT;
        if (mutex_lock_interruptible(&head->io_sem))
@@ -2600,9 +2672,11 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
        /* Read a line and dispatch it to the policy handler. */
        while (avail_len > 0) {
                char c;
+
                if (head->w.avail >= head->writebuf_size - 1) {
                        const int len = head->writebuf_size * 2;
                        char *cp = kzalloc(len, GFP_NOFS);
+
                        if (!cp) {
                                error = -ENOMEM;
                                break;
@@ -2701,30 +2775,32 @@ void tomoyo_check_profile(void)
 {
        struct tomoyo_domain_info *domain;
        const int idx = tomoyo_read_lock();
+
        tomoyo_policy_loaded = true;
-       printk(KERN_INFO "TOMOYO: 2.5.0\n");
+       pr_info("TOMOYO: 2.6.0\n");
        list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
                const u8 profile = domain->profile;
-               const struct tomoyo_policy_namespace *ns = domain->ns;
-               if (ns->profile_version != 20110903)
-                       printk(KERN_ERR
-                              "Profile version %u is not supported.\n",
+               struct tomoyo_policy_namespace *ns = domain->ns;
+
+               if (ns->profile_version == 20110903) {
+                       pr_info_once("Converting profile version from %u to %u.\n",
+                                    20110903, 20150505);
+                       ns->profile_version = 20150505;
+               }
+               if (ns->profile_version != 20150505)
+                       pr_err("Profile version %u is not supported.\n",
                               ns->profile_version);
                else if (!ns->profile_ptr[profile])
-                       printk(KERN_ERR
-                              "Profile %u (used by '%s') is not defined.\n",
+                       pr_err("Profile %u (used by '%s') is not defined.\n",
                               profile, domain->domainname->name);
                else
                        continue;
-               printk(KERN_ERR
-                      "Userland tools for TOMOYO 2.5 must be installed and "
-                      "policy must be initialized.\n");
-               printk(KERN_ERR "Please see http://tomoyo.sourceforge.jp/2.5/ "
-                      "for more information.\n");
+               pr_err("Userland tools for TOMOYO 2.6 must be installed and policy must be initialized.\n");
+               pr_err("Please see https://tomoyo.osdn.jp/2.6/ for more information.\n");
                panic("STOP!");
        }
        tomoyo_read_unlock(idx);
-       printk(KERN_INFO "Mandatory Access Control activated.\n");
+       pr_info("Mandatory Access Control activated.\n");
 }
 
 /**
@@ -2743,9 +2819,11 @@ void __init tomoyo_load_builtin_policy(void)
 #include "builtin-policy.h"
        u8 i;
        const int idx = tomoyo_read_lock();
+
        for (i = 0; i < 5; i++) {
                struct tomoyo_io_buffer head = { };
                char *start = "";
+
                switch (i) {
                case 0:
                        start = tomoyo_builtin_profile;
@@ -2775,6 +2853,7 @@ void __init tomoyo_load_builtin_policy(void)
                }
                while (1) {
                        char *end = strchr(start, '\n');
+
                        if (!end)
                                break;
                        *end = '\0';
index 539bcdd30bb8deb22f9cd27e45258fe5e4a3d4a1..050473df5809f13f467c4cdebffd981a773948a9 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef _SECURITY_TOMOYO_COMMON_H
 #define _SECURITY_TOMOYO_COMMON_H
 
+#define pr_fmt(fmt) fmt
+
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -29,6 +31,7 @@
 #include <linux/in.h>
 #include <linux/in6.h>
 #include <linux/un.h>
+#include <linux/lsm_hooks.h>
 #include <net/sock.h>
 #include <net/af_unix.h>
 #include <net/ip.h>
@@ -681,11 +684,12 @@ struct tomoyo_domain_info {
        const struct tomoyo_path_info *domainname;
        /* Namespace for this domain. Never NULL. */
        struct tomoyo_policy_namespace *ns;
+       /* Group numbers to use.   */
+       unsigned long group[TOMOYO_MAX_ACL_GROUPS / BITS_PER_LONG];
        u8 profile;        /* Profile number to use. */
-       u8 group;          /* Group number to use.   */
        bool is_deleted;   /* Delete flag.           */
        bool flags[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
-       atomic_t users; /* Number of referring credentials. */
+       atomic_t users; /* Number of referring tasks. */
 };
 
 /*
@@ -787,9 +791,9 @@ struct tomoyo_acl_param {
  * interfaces.
  */
 struct tomoyo_io_buffer {
-       void (*read) (struct tomoyo_io_buffer *);
-       int (*write) (struct tomoyo_io_buffer *);
-       __poll_t (*poll) (struct file *file, poll_table *wait);
+       void (*read)(struct tomoyo_io_buffer *head);
+       int (*write)(struct tomoyo_io_buffer *head);
+       __poll_t (*poll)(struct file *file, poll_table *wait);
        /* Exclusive lock for this structure.   */
        struct mutex io_sem;
        char __user *read_user_buf;
@@ -906,12 +910,18 @@ struct tomoyo_policy_namespace {
        struct list_head acl_group[TOMOYO_MAX_ACL_GROUPS];
        /* List for connecting to tomoyo_namespace_list list. */
        struct list_head namespace_list;
-       /* Profile version. Currently only 20110903 is defined. */
+       /* Profile version. Currently only 20150505 is defined. */
        unsigned int profile_version;
        /* Name of this namespace (e.g. "<kernel>", "</usr/sbin/httpd>" ). */
        const char *name;
 };
 
+/* Structure for "struct task_struct"->security. */
+struct tomoyo_task {
+       struct tomoyo_domain_info *domain_info;
+       struct tomoyo_domain_info *old_domain_info;
+};
+
 /********** Function prototypes. **********/
 
 bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *address,
@@ -1020,6 +1030,7 @@ ssize_t tomoyo_write_control(struct tomoyo_io_buffer *head,
 struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param);
 struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
                                                const bool transit);
+struct tomoyo_domain_info *tomoyo_domain(void);
 struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
 struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
                                      const u8 idx);
@@ -1034,8 +1045,8 @@ void *tomoyo_commit_ok(void *data, const unsigned int size);
 void __init tomoyo_load_builtin_policy(void);
 void __init tomoyo_mm_init(void);
 void tomoyo_check_acl(struct tomoyo_request_info *r,
-                     bool (*check_entry) (struct tomoyo_request_info *,
-                                          const struct tomoyo_acl_info *));
+                     bool (*check_entry)(struct tomoyo_request_info *,
+                                         const struct tomoyo_acl_info *));
 void tomoyo_check_profile(void);
 void tomoyo_convert_time(time64_t time, struct tomoyo_time *stamp);
 void tomoyo_del_condition(struct list_head *element);
@@ -1062,6 +1073,7 @@ void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char *fmt,
 /********** External variable definitions. **********/
 
 extern bool tomoyo_policy_loaded;
+extern int tomoyo_enabled;
 extern const char * const tomoyo_condition_keyword
 [TOMOYO_MAX_CONDITION_KEYWORD];
 extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS];
@@ -1085,6 +1097,7 @@ extern struct tomoyo_domain_info tomoyo_kernel_domain;
 extern struct tomoyo_policy_namespace tomoyo_kernel_namespace;
 extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT];
 extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT];
+extern struct lsm_blob_sizes tomoyo_blob_sizes;
 
 /********** Inlined functions. **********/
 
@@ -1121,6 +1134,7 @@ static inline void tomoyo_read_unlock(int idx)
 static inline pid_t tomoyo_sys_getppid(void)
 {
        pid_t pid;
+
        rcu_read_lock();
        pid = task_tgid_vnr(rcu_dereference(current->real_parent));
        rcu_read_unlock();
@@ -1197,26 +1211,15 @@ static inline void tomoyo_put_group(struct tomoyo_group *group)
 }
 
 /**
- * tomoyo_domain - Get "struct tomoyo_domain_info" for current thread.
- *
- * Returns pointer to "struct tomoyo_domain_info" for current thread.
- */
-static inline struct tomoyo_domain_info *tomoyo_domain(void)
-{
-       return current_cred()->security;
-}
-
-/**
- * tomoyo_real_domain - Get "struct tomoyo_domain_info" for specified thread.
+ * tomoyo_task - Get "struct tomoyo_task" for specified thread.
  *
- * @task: Pointer to "struct task_struct".
+ * @task - Pointer to "struct task_struct".
  *
- * Returns pointer to "struct tomoyo_security" for specified thread.
+ * Returns pointer to "struct tomoyo_task" for specified thread.
  */
-static inline struct tomoyo_domain_info *tomoyo_real_domain(struct task_struct
-                                                           *task)
+static inline struct tomoyo_task *tomoyo_task(struct task_struct *task)
 {
-       return task_cred_xxx(task, security);
+       return task->security + tomoyo_blob_sizes.lbs_task;
 }
 
 /**
index 8d0e1b9c9c573b4fac3f8ca78b2c3e715a614eac..8f6d57c15df6ac42c91f76387317c7fbc348d2c5 100644 (file)
@@ -28,9 +28,11 @@ static bool tomoyo_argv(const unsigned int index, const char *arg_ptr,
 {
        int i;
        struct tomoyo_path_info arg;
+
        arg.name = arg_ptr;
        for (i = 0; i < argc; argv++, checked++, i++) {
                bool result;
+
                if (index != argv->index)
                        continue;
                *checked = 1;
@@ -62,12 +64,14 @@ static bool tomoyo_envp(const char *env_name, const char *env_value,
        int i;
        struct tomoyo_path_info name;
        struct tomoyo_path_info value;
+
        name.name = env_name;
        tomoyo_fill_path_info(&name);
        value.name = env_value;
        tomoyo_fill_path_info(&value);
        for (i = 0; i < envc; envp++, checked++, i++) {
                bool result;
+
                if (!tomoyo_path_matches_pattern(&name, envp->name))
                        continue;
                *checked = 1;
@@ -113,6 +117,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
        bool result = true;
        u8 local_checked[32];
        u8 *checked;
+
        if (argc + envc <= sizeof(local_checked)) {
                checked = local_checked;
                memset(local_checked, 0, sizeof(local_checked));
@@ -131,6 +136,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
                        /* Read. */
                        const char *kaddr = dump->data;
                        const unsigned char c = kaddr[offset++];
+
                        if (c && arg_len < TOMOYO_EXEC_TMPSIZE - 10) {
                                if (c == '\\') {
                                        arg_ptr[arg_len++] = '\\';
@@ -160,6 +166,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
                                argv_count--;
                        } else if (envp_count) {
                                char *cp = strchr(arg_ptr, '=');
+
                                if (cp) {
                                        *cp = '\0';
                                        if (!tomoyo_envp(arg_ptr, cp + 1,
@@ -182,6 +189,7 @@ static bool tomoyo_scan_bprm(struct tomoyo_execve *ee,
 out:
        if (result) {
                int i;
+
                /* Check not-yet-checked entries. */
                for (i = 0; i < argc; i++) {
                        if (checked[i])
@@ -229,6 +237,7 @@ static bool tomoyo_scan_exec_realpath(struct file *file,
 {
        bool result;
        struct tomoyo_path_info exe;
+
        if (!file)
                return false;
        exe.name = tomoyo_realpath_from_path(&file->f_path);
@@ -250,6 +259,7 @@ static bool tomoyo_scan_exec_realpath(struct file *file,
 static const struct tomoyo_path_info *tomoyo_get_dqword(char *start)
 {
        char *cp = start + strlen(start) - 1;
+
        if (cp == start || *start++ != '"' || *cp != '"')
                return NULL;
        *cp = '\0';
@@ -270,6 +280,7 @@ static bool tomoyo_parse_name_union_quoted(struct tomoyo_acl_param *param,
                                           struct tomoyo_name_union *ptr)
 {
        char *filename = param->data;
+
        if (*filename == '@')
                return tomoyo_parse_name_union(param, ptr);
        ptr->filename = tomoyo_get_dqword(filename);
@@ -310,6 +321,7 @@ static bool tomoyo_parse_envp(char *left, char *right,
        const struct tomoyo_path_info *name;
        const struct tomoyo_path_info *value;
        char *cp = left + strlen(left) - 1;
+
        if (*cp-- != ']' || *cp != '"')
                goto out;
        *cp = '\0';
@@ -364,6 +376,7 @@ static inline bool tomoyo_same_condition(const struct tomoyo_condition *a,
 static u8 tomoyo_condition_type(const char *word)
 {
        u8 i;
+
        for (i = 0; i < TOMOYO_MAX_CONDITION_KEYWORD; i++) {
                if (!strcmp(word, tomoyo_condition_keyword[i]))
                        break;
@@ -395,6 +408,7 @@ static struct tomoyo_condition *tomoyo_commit_condition
 {
        struct tomoyo_condition *ptr;
        bool found = false;
+
        if (mutex_lock_interruptible(&tomoyo_policy_lock)) {
                dprintk(KERN_WARNING "%u: %s failed\n", __LINE__, __func__);
                ptr = NULL;
@@ -442,12 +456,14 @@ static char *tomoyo_get_transit_preference(struct tomoyo_acl_param *param,
 {
        char * const pos = param->data;
        bool flag;
+
        if (*pos == '<') {
                e->transit = tomoyo_get_domainname(param);
                goto done;
        }
        {
                char *cp = strchr(pos, ' ');
+
                if (cp)
                        *cp = '\0';
                flag = tomoyo_correct_path(pos) || !strcmp(pos, "keep") ||
@@ -489,6 +505,7 @@ struct tomoyo_condition *tomoyo_get_condition(struct tomoyo_acl_param *param)
                tomoyo_get_transit_preference(param, &e);