OSDN Git Service

Merge tag 'selinux-pr-20200330' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 Mar 2020 22:07:55 +0000 (15:07 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 Mar 2020 22:07:55 +0000 (15:07 -0700)
Pull SELinux updates from Paul Moore:
 "We've got twenty SELinux patches for the v5.7 merge window, the
  highlights are below:

   - Deprecate setting /sys/fs/selinux/checkreqprot to 1.

     This flag was originally created to deal with legacy userspace and
     the READ_IMPLIES_EXEC personality flag. We changed the default from
     1 to 0 back in Linux v4.4 and now we are taking the next step of
     deprecating it, at some point in the future we will take the final
     step of rejecting 1.

   - Allow kernfs symlinks to inherit the SELinux label of the parent
     directory. In order to preserve backwards compatibility this is
     protected by the genfs_seclabel_symlinks SELinux policy capability.

   - Optimize how we store filename transitions in the kernel, resulting
     in some significant improvements to policy load times.

   - Do a better job calculating our internal hash table sizes which
     resulted in additional policy load improvements and likely general
     SELinux performance improvements as well.

   - Remove the unused initial SIDs (labels) and improve how we handle
     initial SIDs.

   - Enable per-file labeling for the bpf filesystem.

   - Ensure that we properly label NFS v4.2 filesystems to avoid a
     temporary unlabeled condition.

   - Add some missing XFS quota command types to the SELinux quota
     access controls.

   - Fix a problem where we were not updating the seq_file position
     index correctly in selinuxfs.

   - We consolidate some duplicated code into helper functions.

   - A number of list to array conversions.

   - Update Stephen Smalley's email address in MAINTAINERS"

* tag 'selinux-pr-20200330' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: clean up indentation issue with assignment statement
  NFS: Ensure security label is set for root inode
  MAINTAINERS: Update my email address
  selinux: avtab_init() and cond_policydb_init() return void
  selinux: clean up error path in policydb_init()
  selinux: remove unused initial SIDs and improve handling
  selinux: reduce the use of hard-coded hash sizes
  selinux: Add xfs quota command types
  selinux: optimize storage of filename transitions
  selinux: factor out loop body from filename_trans_read()
  security: selinux: allow per-file labeling for bpffs
  selinux: generalize evaluate_cond_node()
  selinux: convert cond_expr to array
  selinux: convert cond_av_list to array
  selinux: convert cond_list to array
  selinux: sel_avc_get_stat_idx should increase position index
  selinux: allow kernfs symlinks to inherit parent directory context
  selinux: simplify evaluate_cond_node()
  Documentation,selinux: deprecate setting checkreqprot to 1
  selinux: move status variables out of selinux_ss

26 files changed:
Documentation/ABI/obsolete/sysfs-selinux-checkreqprot [new file with mode: 0644]
Documentation/admin-guide/kernel-parameters.txt
MAINTAINERS
fs/nfs/getroot.c
fs/nfs/nfs4proc.c
fs/nfs/super.c
include/linux/nfs_xdr.h
scripts/selinux/genheaders/genheaders.c
security/selinux/Kconfig
security/selinux/Makefile
security/selinux/hooks.c
security/selinux/include/conditional.h
security/selinux/include/initial_sid_to_string.h
security/selinux/include/security.h
security/selinux/selinuxfs.c
security/selinux/ss/avtab.c
security/selinux/ss/avtab.h
security/selinux/ss/conditional.c
security/selinux/ss/conditional.h
security/selinux/ss/hashtab.c
security/selinux/ss/hashtab.h
security/selinux/ss/policydb.c
security/selinux/ss/policydb.h
security/selinux/ss/services.c
security/selinux/ss/services.h
security/selinux/status.c [moved from security/selinux/ss/status.c with 81% similarity]

diff --git a/Documentation/ABI/obsolete/sysfs-selinux-checkreqprot b/Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
new file mode 100644 (file)
index 0000000..49ed9c8
--- /dev/null
@@ -0,0 +1,23 @@
+What:          /sys/fs/selinux/checkreqprot
+Date:          April 2005 (predates git)
+KernelVersion: 2.6.12-rc2 (predates git)
+Contact:       selinux@vger.kernel.org
+Description:
+
+       The selinuxfs "checkreqprot" node allows SELinux to be configured
+       to check the protection requested by userspace for mmap/mprotect
+       calls instead of the actual protection applied by the kernel.
+       This was a compatibility mechanism for legacy userspace and
+       for the READ_IMPLIES_EXEC personality flag.  However, if set to
+       1, it weakens security by allowing mappings to be made executable
+       without authorization by policy.  The default value of checkreqprot
+       at boot was changed starting in Linux v4.4 to 0 (i.e. check the
+       actual protection), and Android and Linux distributions have been
+       explicitly writing a "0" to /sys/fs/selinux/checkreqprot during
+       initialization for some time.  Support for setting checkreqprot to 1
+       will be removed in a future kernel release, at which point the kernel
+       will always cease using checkreqprot internally and will always
+       check the actual protections being applied upon mmap/mprotect calls.
+       The checkreqprot selinuxfs node will remain for backward compatibility
+       but will discard writes of the "0" value and will reject writes of the
+       "1" value when this mechanism is removed.
index 24799f1..ed73df5 100644 (file)
                        Default value is set via a kernel config option.
                        Value can be changed at runtime via
                                /sys/fs/selinux/checkreqprot.
+                       Setting checkreqprot to 1 is deprecated.
 
        cio_ignore=     [S390]
                        See Documentation/s390/common_io.rst for details.
index fe43e1c..78c782a 100644 (file)
@@ -15027,7 +15027,7 @@ X:      security/selinux/
 
 SELINUX SECURITY MODULE
 M:     Paul Moore <paul@paul-moore.com>
-M:     Stephen Smalley <sds@tycho.nsa.gov>
+M:     Stephen Smalley <stephen.smalley.work@gmail.com>
 M:     Eric Paris <eparis@parisplace.org>
 L:     selinux@vger.kernel.org
 W:     https://selinuxproject.org
@@ -15039,6 +15039,7 @@ F:      security/selinux/
 F:     scripts/selinux/
 F:     Documentation/admin-guide/LSM/SELinux.rst
 F:     Documentation/ABI/obsolete/sysfs-selinux-disable
+F:     Documentation/ABI/obsolete/sysfs-selinux-checkreqprot
 
 SENSABLE PHANTOM
 M:     Jiri Slaby <jirislaby@gmail.com>
index b012c26..aaeeb46 100644 (file)
@@ -73,6 +73,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
        struct inode *inode;
        char *name;
        int error = -ENOMEM;
+       unsigned long kflags = 0, kflags_out = 0;
 
        name = kstrdup(fc->source, GFP_KERNEL);
        if (!name)
@@ -83,11 +84,14 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
        if (fsinfo.fattr == NULL)
                goto out_name;
 
+       fsinfo.fattr->label = nfs4_label_alloc(server, GFP_KERNEL);
+       if (IS_ERR(fsinfo.fattr->label))
+               goto out_fattr;
        error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
        if (error < 0) {
                dprintk("nfs_get_root: getattr error = %d\n", -error);
                nfs_errorf(fc, "NFS: Couldn't getattr on root");
-               goto out_fattr;
+               goto out_label;
        }
 
        inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr, NULL);
@@ -95,12 +99,12 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
                dprintk("nfs_get_root: get root inode failed\n");
                error = PTR_ERR(inode);
                nfs_errorf(fc, "NFS: Couldn't get root inode");
-               goto out_fattr;
+               goto out_label;
        }
 
        error = nfs_superblock_set_dummy_root(s, inode);
        if (error != 0)
-               goto out_fattr;
+               goto out_label;
 
        /* root dentries normally start off anonymous and get spliced in later
         * if the dentry tree reaches them; however if the dentry already
@@ -111,7 +115,7 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
                dprintk("nfs_get_root: get root dentry failed\n");
                error = PTR_ERR(root);
                nfs_errorf(fc, "NFS: Couldn't get root dentry");
-               goto out_fattr;
+               goto out_label;
        }
 
        security_d_instantiate(root, inode);
@@ -123,12 +127,39 @@ int nfs_get_root(struct super_block *s, struct fs_context *fc)
        }
        spin_unlock(&root->d_lock);
        fc->root = root;
+       if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
+               kflags |= SECURITY_LSM_NATIVE_LABELS;
+       if (ctx->clone_data.sb) {
+               if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
+                       error = -ESTALE;
+                       goto error_splat_root;
+               }
+               /* clone lsm security options from the parent to the new sb */
+               error = security_sb_clone_mnt_opts(ctx->clone_data.sb,
+                                                  s, kflags, &kflags_out);
+       } else {
+               error = security_sb_set_mnt_opts(s, fc->security,
+                                                       kflags, &kflags_out);
+       }
+       if (error)
+               goto error_splat_root;
+       if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
+               !(kflags_out & SECURITY_LSM_NATIVE_LABELS))
+               NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
+
+       nfs_setsecurity(inode, fsinfo.fattr, fsinfo.fattr->label);
        error = 0;
 
+out_label:
+       nfs4_label_free(fsinfo.fattr->label);
 out_fattr:
        nfs_free_fattr(fsinfo.fattr);
 out_name:
        kfree(name);
 out:
        return error;
+error_splat_root:
+       dput(fc->root);
+       fc->root = NULL;
+       goto out_label;
 }
index 69b7ab7..cb34e84 100644 (file)
@@ -4002,7 +4002,7 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
 {
        int error;
        struct nfs_fattr *fattr = info->fattr;
-       struct nfs4_label *label = NULL;
+       struct nfs4_label *label = fattr->label;
 
        error = nfs4_server_capabilities(server, mntfh);
        if (error < 0) {
@@ -4010,23 +4010,17 @@ static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
                return error;
        }
 
-       label = nfs4_label_alloc(server, GFP_KERNEL);
-       if (IS_ERR(label))
-               return PTR_ERR(label);
-
        error = nfs4_proc_getattr(server, mntfh, fattr, label, NULL);
        if (error < 0) {
                dprintk("nfs4_get_root: getattr error = %d\n", -error);
-               goto err_free_label;
+               goto out;
        }
 
        if (fattr->valid & NFS_ATTR_FATTR_FSID &&
            !nfs_fsid_equal(&server->fsid, &fattr->fsid))
                memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
 
-err_free_label:
-       nfs4_label_free(label);
-
+out:
        return error;
 }
 
index dada09b..bb14bed 100644 (file)
@@ -1179,7 +1179,6 @@ int nfs_get_tree_common(struct fs_context *fc)
        struct super_block *s;
        int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super;
        struct nfs_server *server = ctx->server;
-       unsigned long kflags = 0, kflags_out = 0;
        int error;
 
        ctx->server = NULL;
@@ -1239,26 +1238,6 @@ int nfs_get_tree_common(struct fs_context *fc)
                goto error_splat_super;
        }
 
-       if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
-               kflags |= SECURITY_LSM_NATIVE_LABELS;
-       if (ctx->clone_data.sb) {
-               if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
-                       error = -ESTALE;
-                       goto error_splat_root;
-               }
-               /* clone any lsm security options from the parent to the new sb */
-               error = security_sb_clone_mnt_opts(ctx->clone_data.sb, s, kflags,
-                               &kflags_out);
-       } else {
-               error = security_sb_set_mnt_opts(s, fc->security,
-                                                       kflags, &kflags_out);
-       }
-       if (error)
-               goto error_splat_root;
-       if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
-               !(kflags_out & SECURITY_LSM_NATIVE_LABELS))
-               NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
-
        s->s_flags |= SB_ACTIVE;
        error = 0;
 
@@ -1268,10 +1247,6 @@ out:
 out_err_nosb:
        nfs_free_server(server);
        goto out;
-
-error_splat_root:
-       dput(fc->root);
-       fc->root = NULL;
 error_splat_super:
        deactivate_locked_super(s);
        goto out;
index 94c77ed..6838c14 100644 (file)
@@ -75,6 +75,7 @@ struct nfs_fattr {
        struct nfs4_string      *owner_name;
        struct nfs4_string      *group_name;
        struct nfs4_threshold   *mdsthreshold;  /* pNFS threshold hints */
+       struct nfs4_label       *label;
 };
 
 #define NFS_ATTR_FATTR_TYPE            (1U << 0)
index 544ca12..f355b3e 100644 (file)
@@ -67,8 +67,12 @@ int main(int argc, char *argv[])
        }
 
        isids_len = sizeof(initial_sid_to_string) / sizeof (char *);
-       for (i = 1; i < isids_len; i++)
-               initial_sid_to_string[i] = stoupperx(initial_sid_to_string[i]);
+       for (i = 1; i < isids_len; i++) {
+               const char *s = initial_sid_to_string[i];
+
+               if (s)
+                       initial_sid_to_string[i] = stoupperx(s);
+       }
 
        fprintf(fout, "/* This file is automatically generated.  Do not edit. */\n");
        fprintf(fout, "#ifndef _SELINUX_FLASK_H_\n#define _SELINUX_FLASK_H_\n\n");
@@ -82,7 +86,8 @@ int main(int argc, char *argv[])
 
        for (i = 1; i < isids_len; i++) {
                const char *s = initial_sid_to_string[i];
-               fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i);
+               if (s)
+                       fprintf(fout, "#define SECINITSID_%-39s %2d\n", s, i);
        }
        fprintf(fout, "\n#define SECINITSID_NUM %d\n", i-1);
        fprintf(fout, "\nstatic inline bool security_is_socket_class(u16 kern_tclass)\n");
index 1014cb0..9e921fc 100644 (file)
@@ -88,6 +88,9 @@ config SECURITY_SELINUX_CHECKREQPROT_VALUE
          'checkreqprot=' boot parameter.  It may also be changed at runtime
          via /sys/fs/selinux/checkreqprot if authorized by policy.
 
+         WARNING: this option is deprecated and will be removed in a future
+         kernel release.
+
          If you are unsure how to answer this question, answer 0.
 
 config SECURITY_SELINUX_SIDTAB_HASH_BITS
index 2000f95..0c77ede 100644 (file)
@@ -6,9 +6,9 @@
 obj-$(CONFIG_SECURITY_SELINUX) := selinux.o
 
 selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o \
-            netnode.o netport.o \
+            netnode.o netport.o status.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
+            ss/policydb.o ss/services.o ss/conditional.o ss/mls.o
 
 selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
 
index 1659b59..0b4e321 100644 (file)
@@ -142,8 +142,11 @@ static int __init checkreqprot_setup(char *str)
 {
        unsigned long checkreqprot;
 
-       if (!kstrtoul(str, 0, &checkreqprot))
+       if (!kstrtoul(str, 0, &checkreqprot)) {
                selinux_checkreqprot_boot = checkreqprot ? 1 : 0;
+               if (checkreqprot)
+                       pr_warn("SELinux: checkreqprot set to 1 via kernel parameter.  This is deprecated and will be rejected in a future kernel release.\n");
+       }
        return 1;
 }
 __setup("checkreqprot=", checkreqprot_setup);
@@ -699,6 +702,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
        if (!strcmp(sb->s_type->name, "debugfs") ||
            !strcmp(sb->s_type->name, "tracefs") ||
            !strcmp(sb->s_type->name, "binder") ||
+           !strcmp(sb->s_type->name, "bpf") ||
            !strcmp(sb->s_type->name, "pstore"))
                sbsec->flags |= SE_SBGENFS;
 
@@ -1475,7 +1479,9 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                /* Default to the fs superblock SID. */
                sid = sbsec->sid;
 
-               if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
+               if ((sbsec->flags & SE_SBGENFS) &&
+                    (!S_ISLNK(inode->i_mode) ||
+                     selinux_policycap_genfs_seclabel_symlinks())) {
                        /* We must have a dentry to determine the label on
                         * procfs inodes */
                        if (opt_dentry) {
@@ -2139,11 +2145,18 @@ static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
        case Q_QUOTAOFF:
        case Q_SETINFO:
        case Q_SETQUOTA:
+       case Q_XQUOTAOFF:
+       case Q_XQUOTAON:
+       case Q_XSETQLIM:
                rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
                break;
        case Q_GETFMT:
        case Q_GETINFO:
        case Q_GETQUOTA:
+       case Q_XGETQUOTA:
+       case Q_XGETQSTAT:
+       case Q_XGETQSTATV:
+       case Q_XGETNEXTQUOTA:
                rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
                break;
        default:
@@ -7161,6 +7174,7 @@ static __init int selinux_init(void)
        selinux_state.checkreqprot = selinux_checkreqprot_boot;
        selinux_ss_init(&selinux_state.ss);
        selinux_avc_init(&selinux_state.avc);
+       mutex_init(&selinux_state.status_lock);
 
        /* Set the security state for the initial task. */
        cred_init_security();
index 0ab316f..539ab35 100644 (file)
 #include "security.h"
 
 int security_get_bools(struct selinux_state *state,
-                      int *len, char ***names, int **values);
+                      u32 *len, char ***names, int **values);
 
-int security_set_bools(struct selinux_state *state,
-                      int len, int *values);
+int security_set_bools(struct selinux_state *state, u32 len, int *values);
 
-int security_get_bool_value(struct selinux_state *state,
-                           int index);
+int security_get_bool_value(struct selinux_state *state, u32 index);
 
 #endif
index 4f93f69..5d332ae 100644 (file)
@@ -1,34 +1,33 @@
 /* SPDX-License-Identifier: GPL-2.0 */
-/* This file is automatically generated.  Do not edit. */
 static const char *initial_sid_to_string[] =
 {
-    "null",
-    "kernel",
-    "security",
-    "unlabeled",
-    "fs",
-    "file",
-    "file_labels",
-    "init",
-    "any_socket",
-    "port",
-    "netif",
-    "netmsg",
-    "node",
-    "igmp_packet",
-    "icmp_socket",
-    "tcp_socket",
-    "sysctl_modprobe",
-    "sysctl",
-    "sysctl_fs",
-    "sysctl_kernel",
-    "sysctl_net",
-    "sysctl_net_unix",
-    "sysctl_vm",
-    "sysctl_dev",
-    "kmod",
-    "policy",
-    "scmp_packet",
-    "devnull",
+       NULL,
+       "kernel",
+       "security",
+       "unlabeled",
+       NULL,
+       "file",
+       NULL,
+       NULL,
+       "any_socket",
+       "port",
+       "netif",
+       "netmsg",
+       "node",
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       "devnull",
 };
 
index a39f956..d6036c0 100644 (file)
@@ -79,6 +79,7 @@ enum {
        POLICYDB_CAPABILITY_ALWAYSNETWORK,
        POLICYDB_CAPABILITY_CGROUPSECLABEL,
        POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION,
+       POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS,
        __POLICYDB_CAPABILITY_MAX
 };
 #define POLICYDB_CAPABILITY_MAX (__POLICYDB_CAPABILITY_MAX - 1)
@@ -108,6 +109,10 @@ struct selinux_state {
        bool checkreqprot;
        bool initialized;
        bool policycap[__POLICYDB_CAPABILITY_MAX];
+
+       struct page *status_page;
+       struct mutex status_lock;
+
        struct selinux_avc *avc;
        struct selinux_ss *ss;
 } __randomize_layout;
@@ -209,6 +214,13 @@ static inline bool selinux_policycap_nnp_nosuid_transition(void)
        return state->policycap[POLICYDB_CAPABILITY_NNP_NOSUID_TRANSITION];
 }
 
+static inline bool selinux_policycap_genfs_seclabel_symlinks(void)
+{
+       struct selinux_state *state = &selinux_state;
+
+       return state->policycap[POLICYDB_CAPABILITY_GENFS_SECLABEL_SYMLINKS];
+}
+
 int security_mls_enabled(struct selinux_state *state);
 int security_load_policy(struct selinux_state *state,
                         void *data, size_t len);
index 79c7109..4781314 100644 (file)
@@ -668,6 +668,14 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
        if (sscanf(page, "%u", &new_value) != 1)
                goto out;
 
+       if (new_value) {
+               char comm[sizeof(current->comm)];
+
+               memcpy(comm, current->comm, sizeof(comm));
+               pr_warn_once("SELinux: %s (%d) set checkreqprot to 1. This is deprecated and will be rejected in a future kernel release.\n",
+                            comm, current->pid);
+       }
+
        fsi->state->checkreqprot = new_value ? 1 : 0;
        length = count;
 out:
@@ -1327,14 +1335,14 @@ static void sel_remove_entries(struct dentry *de)
 
 static int sel_make_bools(struct selinux_fs_info *fsi)
 {
-       int i, ret;
+       int ret;
        ssize_t len;
        struct dentry *dentry = NULL;
        struct dentry *dir = fsi->bool_dir;
        struct inode *inode = NULL;
        struct inode_security_struct *isec;
        char **names = NULL, *page;
-       int num;
+       u32 i, num;
        int *values = NULL;
        u32 sid;
 
@@ -1536,6 +1544,7 @@ static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx)
                *idx = cpu + 1;
                return &per_cpu(avc_cache_stats, cpu);
        }
+       (*idx)++;
        return NULL;
 }
 
@@ -1692,7 +1701,11 @@ static int sel_make_initcon_files(struct dentry *dir)
        for (i = 1; i <= SECINITSID_NUM; i++) {
                struct inode *inode;
                struct dentry *dentry;
-               dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
+               const char *s = security_get_initial_sid_context(i);
+
+               if (!s)
+                       continue;
+               dentry = d_alloc_name(dir, s);
                if (!dentry)
                        return -ENOMEM;
 
index 8c58007..01b300a 100644 (file)
@@ -299,12 +299,11 @@ void avtab_destroy(struct avtab *h)
        h->mask = 0;
 }
 
-int avtab_init(struct avtab *h)
+void avtab_init(struct avtab *h)
 {
        kvfree(h->htable);
        h->htable = NULL;
        h->nel = 0;
-       return 0;
 }
 
 int avtab_alloc(struct avtab *h, u32 nrules)
index 837e938..5fdcb66 100644 (file)
@@ -87,7 +87,7 @@ struct avtab {
        u32 mask;       /* mask to compute hash func */
 };
 
-int avtab_init(struct avtab *);
+void avtab_init(struct avtab *h);
 int avtab_alloc(struct avtab *, u32);
 struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *k);
 void avtab_destroy(struct avtab *h);
index 70c378e..939a74f 100644 (file)
  */
 static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
 {
-
-       struct cond_expr *cur;
+       u32 i;
        int s[COND_EXPR_MAXDEPTH];
        int sp = -1;
 
-       for (cur = expr; cur; cur = cur->next) {
-               switch (cur->expr_type) {
+       for (i = 0; i < expr->len; i++) {
+               struct cond_expr_node *node = &expr->nodes[i];
+
+               switch (node->expr_type) {
                case COND_BOOL:
                        if (sp == (COND_EXPR_MAXDEPTH - 1))
                                return -1;
                        sp++;
-                       s[sp] = p->bool_val_to_struct[cur->bool - 1]->state;
+                       s[sp] = p->bool_val_to_struct[node->bool - 1]->state;
                        break;
                case COND_NOT:
                        if (sp < 0)
@@ -85,90 +86,76 @@ static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
  * list appropriately. If the result of the expression is undefined
  * all of the rules are disabled for safety.
  */
-int evaluate_cond_node(struct policydb *p, struct cond_node *node)
+static void evaluate_cond_node(struct policydb *p, struct cond_node *node)
 {
+       struct avtab_node *avnode;
        int new_state;
-       struct cond_av_list *cur;
+       u32 i;
 
-       new_state = cond_evaluate_expr(p, node->expr);
+       new_state = cond_evaluate_expr(p, &node->expr);
        if (new_state != node->cur_state) {
                node->cur_state = new_state;
                if (new_state == -1)
                        pr_err("SELinux: expression result was undefined - disabling all rules.\n");
                /* turn the rules on or off */
-               for (cur = node->true_list; cur; cur = cur->next) {
+               for (i = 0; i < node->true_list.len; i++) {
+                       avnode = node->true_list.nodes[i];
                        if (new_state <= 0)
-                               cur->node->key.specified &= ~AVTAB_ENABLED;
+                               avnode->key.specified &= ~AVTAB_ENABLED;
                        else
-                               cur->node->key.specified |= AVTAB_ENABLED;
+                               avnode->key.specified |= AVTAB_ENABLED;
                }
 
-               for (cur = node->false_list; cur; cur = cur->next) {
+               for (i = 0; i < node->false_list.len; i++) {
+                       avnode = node->false_list.nodes[i];
                        /* -1 or 1 */
                        if (new_state)
-                               cur->node->key.specified &= ~AVTAB_ENABLED;
+                               avnode->key.specified &= ~AVTAB_ENABLED;
                        else
-                               cur->node->key.specified |= AVTAB_ENABLED;
+                               avnode->key.specified |= AVTAB_ENABLED;
                }
        }
-       return 0;
 }
 
-int cond_policydb_init(struct policydb *p)
+void evaluate_cond_nodes(struct policydb *p)
 {
-       int rc;
+       u32 i;
 
-       p->bool_val_to_struct = NULL;
-       p->cond_list = NULL;
-
-       rc = avtab_init(&p->te_cond_avtab);
-       if (rc)
-               return rc;
-
-       return 0;
+       for (i = 0; i < p->cond_list_len; i++)
+               evaluate_cond_node(p, &p->cond_list[i]);
 }
 
-static void cond_av_list_destroy(struct cond_av_list *list)
+void cond_policydb_init(struct policydb *p)
 {
-       struct cond_av_list *cur, *next;
-       for (cur = list; cur; cur = next) {
-               next = cur->next;
-               /* the avtab_ptr_t node is destroy by the avtab */
-               kfree(cur);
-       }
+       p->bool_val_to_struct = NULL;
+       p->cond_list = NULL;
+       p->cond_list_len = 0;
+
+       avtab_init(&p->te_cond_avtab);
 }
 
 static void cond_node_destroy(struct cond_node *node)
 {
-       struct cond_expr *cur_expr, *next_expr;
-
-       for (cur_expr = node->expr; cur_expr; cur_expr = next_expr) {
-               next_expr = cur_expr->next;
-               kfree(cur_expr);
-       }
-       cond_av_list_destroy(node->true_list);
-       cond_av_list_destroy(node->false_list);
-       kfree(node);
+       kfree(node->expr.nodes);
+       /* the avtab_ptr_t nodes are destroyed by the avtab */
+       kfree(node->true_list.nodes);
+       kfree(node->false_list.nodes);
 }
 
-static void cond_list_destroy(struct cond_node *list)
+static void cond_list_destroy(struct policydb *p)
 {
-       struct cond_node *next, *cur;
-
-       if (list == NULL)
-               return;
+       u32 i;
 
-       for (cur = list; cur; cur = next) {
-               next = cur->next;
-               cond_node_destroy(cur);
-       }
+       for (i = 0; i < p->cond_list_len; i++)
+               cond_node_destroy(&p->cond_list[i]);
+       kfree(p->cond_list);
 }
 
 void cond_policydb_destroy(struct policydb *p)
 {
        kfree(p->bool_val_to_struct);
        avtab_destroy(&p->te_cond_avtab);
-       cond_list_destroy(p->cond_list);
+       cond_list_destroy(p);
 }
 
 int cond_init_bool_indexes(struct policydb *p)
@@ -260,19 +247,18 @@ err:
 
 struct cond_insertf_data {
        struct policydb *p;
+       struct avtab_node **dst;
        struct cond_av_list *other;
-       struct cond_av_list *head;
-       struct cond_av_list *tail;
 };
 
 static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum *d, void *ptr)
 {
        struct cond_insertf_data *data = ptr;
        struct policydb *p = data->p;
-       struct cond_av_list *other = data->other, *list, *cur;
+       struct cond_av_list *other = data->other;
        struct avtab_node *node_ptr;
-       u8 found;
-       int rc = -EINVAL;
+       u32 i;
+       bool found;
 
        /*
         * For type rules we have to make certain there aren't any
@@ -282,7 +268,7 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
        if (k->specified & AVTAB_TYPE) {
                if (avtab_search(&p->te_avtab, k)) {
                        pr_err("SELinux: type rule already exists outside of a conditional.\n");
-                       goto err;
+                       return -EINVAL;
                }
                /*
                 * If we are reading the false list other will be a pointer to
@@ -297,24 +283,24 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
                        if (node_ptr) {
                                if (avtab_search_node_next(node_ptr, k->specified)) {
                                        pr_err("SELinux: too many conflicting type rules.\n");
-                                       goto err;
+                                       return -EINVAL;
                                }
-                               found = 0;
-                               for (cur = other; cur; cur = cur->next) {
-                                       if (cur->node == node_ptr) {
-                                               found = 1;
+                               found = false;
+                               for (i = 0; i < other->len; i++) {
+                                       if (other->nodes[i] == node_ptr) {
+                                               found = true;
                                                break;
                                        }
                                }
                                if (!found) {
                                        pr_err("SELinux: conflicting type rules.\n");
-                                       goto err;
+                                       return -EINVAL;
                                }
                        }
                } else {
                        if (avtab_search(&p->te_cond_avtab, k)) {
                                pr_err("SELinux: conflicting type rules when adding type rule for true.\n");
-                               goto err;
+                               return -EINVAL;
                        }
                }
        }
@@ -322,39 +308,22 @@ static int cond_insertf(struct avtab *a, struct avtab_key *k, struct avtab_datum
        node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
        if (!node_ptr) {
                pr_err("SELinux: could not insert rule.\n");
-               rc = -ENOMEM;
-               goto err;
-       }
-
-       list = kzalloc(sizeof(*list), GFP_KERNEL);
-       if (!list) {
-               rc = -ENOMEM;
-               goto err;
+               return -ENOMEM;
        }
 
-       list->node = node_ptr;
-       if (!data->head)
-               data->head = list;
-       else
-               data->tail->next = list;
-       data->tail = list;
+       *data->dst = node_ptr;
        return 0;
-
-err:
-       cond_av_list_destroy(data->head);
-       data->head = NULL;
-       return rc;
 }
 
-static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list **ret_list, struct cond_av_list *other)
+static int cond_read_av_list(struct policydb *p, void *fp,
+                            struct cond_av_list *list,
+                            struct cond_av_list *other)
 {
-       int i, rc;
+       int rc;
        __le32 buf[1];
-       u32 len;
+       u32 i, len;
        struct cond_insertf_data data;
 
-       *ret_list = NULL;
-
        rc = next_entry(buf, fp, sizeof(u32));
        if (rc)
                return rc;
@@ -363,22 +332,28 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list *
        if (len == 0)
                return 0;
 
+       list->nodes = kcalloc(len, sizeof(*list->nodes), GFP_KERNEL);
+       if (!list->nodes)
+               return -ENOMEM;
+
        data.p = p;
        data.other = other;
-       data.head = NULL;
-       data.tail = NULL;
        for (i = 0; i < len; i++) {
+               data.dst = &list->nodes[i];
                rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
                                     &data);
-               if (rc)
+               if (rc) {
+                       kfree(list->nodes);
+                       list->nodes = NULL;
                        return rc;
+               }
        }
 
-       *ret_list = data.head;
+       list->len = len;
        return 0;
 }
 
-static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
+static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)
 {
        if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
                pr_err("SELinux: conditional expressions uses unknown operator.\n");
@@ -395,49 +370,43 @@ static int expr_isvalid(struct policydb *p, struct cond_expr *expr)
 static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
 {
        __le32 buf[2];
-       u32 len, i;
+       u32 i, len;
        int rc;
-       struct cond_expr *expr = NULL, *last = NULL;
 
        rc = next_entry(buf, fp, sizeof(u32) * 2);
        if (rc)
-               goto err;
+               return rc;
 
        node->cur_state = le32_to_cpu(buf[0]);
 
        /* expr */
        len = le32_to_cpu(buf[1]);
+       node->expr.nodes = kcalloc(len, sizeof(*node->expr.nodes), GFP_KERNEL);
+       if (!node->expr.nodes)
+               return -ENOMEM;
+
+       node->expr.len = len;
 
        for (i = 0; i < len; i++) {
+               struct cond_expr_node *expr = &node->expr.nodes[i];
+
                rc = next_entry(buf, fp, sizeof(u32) * 2);
                if (rc)
                        goto err;
 
-               rc = -ENOMEM;
-               expr = kzalloc(sizeof(*expr), GFP_KERNEL);
-               if (!expr)
-                       goto err;
-
                expr->expr_type = le32_to_cpu(buf[0]);
                expr->bool = le32_to_cpu(buf[1]);
 
-               if (!expr_isvalid(p, expr)) {
+               if (!expr_node_isvalid(p, expr)) {
                        rc = -EINVAL;
-                       kfree(expr);
                        goto err;
                }
-
-               if (i == 0)
-                       node->expr = expr;
-               else
-                       last->next = expr;
-               last = expr;
        }
 
        rc = cond_read_av_list(p, fp, &node->true_list, NULL);
        if (rc)
                goto err;
-       rc = cond_read_av_list(p, fp, &node->false_list, node->true_list);
+       rc = cond_read_av_list(p, fp, &node->false_list, &node->true_list);
        if (rc)
                goto err;
        return 0;
@@ -448,7 +417,6 @@ err:
 
 int cond_read_list(struct policydb *p, void *fp)
 {
-       struct cond_node *node, *last = NULL;
        __le32 buf[1];
        u32 i, len;
        int rc;
@@ -459,29 +427,24 @@ int cond_read_list(struct policydb *p, void *fp)
 
        len = le32_to_cpu(buf[0]);
 
+       p->cond_list = kcalloc(len, sizeof(*p->cond_list), GFP_KERNEL);
+       if (!p->cond_list)
+               return rc;
+
        rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
        if (rc)
                goto err;
 
-       for (i = 0; i < len; i++) {
-               rc = -ENOMEM;
-               node = kzalloc(sizeof(*node), GFP_KERNEL);
-               if (!node)
-                       goto err;
+       p->cond_list_len = len;
 
-               rc = cond_read_node(p, node, fp);
+       for (i = 0; i < len; i++) {
+               rc = cond_read_node(p, &p->cond_list[i], fp);
                if (rc)
                        goto err;
-
-               if (i == 0)
-                       p->cond_list = node;
-               else
-                       last->next = node;
-               last = node;
        }
        return 0;
 err:
-       cond_list_destroy(p->cond_list);
+       cond_list_destroy(p);
        p->cond_list = NULL;
        return rc;
 }
@@ -522,24 +485,16 @@ static int cond_write_av_list(struct policydb *p,
                              struct cond_av_list *list, struct policy_file *fp)
 {
        __le32 buf[1];
-       struct cond_av_list *cur_list;
-       u32 len;
+       u32 i;
        int rc;
 
-       len = 0;
-       for (cur_list = list; cur_list != NULL; cur_list = cur_list->next)
-               len++;
-
-       buf[0] = cpu_to_le32(len);
+       buf[0] = cpu_to_le32(list->len);
        rc = put_entry(buf, sizeof(u32), 1, fp);
        if (rc)
                return rc;
 
-       if (len == 0)
-               return 0;
-
-       for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) {
-               rc = avtab_write_item(p, cur_list->node, fp);
+       for (i = 0; i < list->len; i++) {
+               rc = avtab_write_item(p, list->nodes[i], fp);
                if (rc)
                        return rc;
        }
@@ -550,59 +505,51 @@ static int cond_write_av_list(struct policydb *p,
 static int cond_write_node(struct policydb *p, struct cond_node *node,
                    struct policy_file *fp)
 {
-       struct cond_expr *cur_expr;
        __le32 buf[2];
        int rc;
-       u32 len = 0;
+       u32 i;
 
        buf[0] = cpu_to_le32(node->cur_state);
        rc = put_entry(buf, sizeof(u32), 1, fp);
        if (rc)
                return rc;
 
-       for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next)
-               len++;
-
-       buf[0] = cpu_to_le32(len);
+       buf[0] = cpu_to_le32(node->expr.len);
        rc = put_entry(buf, sizeof(u32), 1, fp);
        if (rc)
                return rc;
 
-       for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) {
-               buf[0] = cpu_to_le32(cur_expr->expr_type);
-               buf[1] = cpu_to_le32(cur_expr->bool);
+       for (i = 0; i < node->expr.len; i++) {
+               buf[0] = cpu_to_le32(node->expr.nodes[i].expr_type);
+               buf[1] = cpu_to_le32(node->expr.nodes[i].bool);
                rc = put_entry(buf, sizeof(u32), 2, fp);
                if (rc)
                        return rc;
        }
 
-       rc = cond_write_av_list(p, node->true_list, fp);
+       rc = cond_write_av_list(p, &node->true_list, fp);
        if (rc)
                return rc;
-       rc = cond_write_av_list(p, node->false_list, fp);
+       rc = cond_write_av_list(p, &node->false_list, fp);
        if (rc)
                return rc;
 
        return 0;
 }
 
-int cond_write_list(struct policydb *p, struct cond_node *list, void *fp)
+int cond_write_list(struct policydb *p, void *fp)
 {
-       struct cond_node *cur;
-       u32 len;
+       u32 i;
        __le32 buf[1];
        int rc;
 
-       len = 0;
-       for (cur = list; cur != NULL; cur = cur->next)
-               len++;
-       buf[0] = cpu_to_le32(len);
+       buf[0] = cpu_to_le32(p->cond_list_len);
        rc = put_entry(buf, sizeof(u32), 1, fp);
        if (rc)
                return rc;
 
-       for (cur = list; cur != NULL; cur = cur->next) {
-               rc = cond_write_node(p, cur, fp);
+       for (i = 0; i < p->cond_list_len; i++) {
+               rc = cond_write_node(p, &p->cond_list[i], fp);
                if (rc)
                        return rc;
        }
index ec846e4..90c9c96 100644 (file)
@@ -19,7 +19,7 @@
  * A conditional expression is a list of operators and operands
  * in reverse polish notation.
  */
-struct cond_expr {
+struct cond_expr_node {
 #define COND_BOOL      1 /* plain bool */
 #define COND_NOT       2 /* !bool */
 #define COND_OR                3 /* bool || bool */
@@ -28,9 +28,13 @@ struct cond_expr {
 #define COND_EQ                6 /* bool == bool */
 #define COND_NEQ       7 /* bool != bool */
 #define COND_LAST      COND_NEQ
-       __u32 expr_type;
-       __u32 bool;
-       struct cond_expr *next;
+       u32 expr_type;
+       u32 bool;
+};
+
+struct cond_expr {
+       struct cond_expr_node *nodes;
+       u32 len;
 };
 
 /*
@@ -39,8 +43,8 @@ struct cond_expr {
  * struct is for that list.
  */
 struct cond_av_list {
-       struct avtab_node *node;
-       struct cond_av_list *next;
+       struct avtab_node **nodes;
+       u32 len;
 };
 
 /*
@@ -52,13 +56,12 @@ struct cond_av_list {
  */
 struct cond_node {
        int cur_state;
-       struct cond_expr *expr;
-       struct cond_av_list *true_list;
-       struct cond_av_list *false_list;
-       struct cond_node *next;
+       struct cond_expr expr;
+       struct cond_av_list true_list;
+       struct cond_av_list false_list;
 };
 
-int cond_policydb_init(struct policydb *p);
+void cond_policydb_init(struct policydb *p);
 void cond_policydb_destroy(struct policydb *p);
 
 int cond_init_bool_indexes(struct policydb *p);
@@ -69,12 +72,12 @@ int cond_index_bool(void *key, void *datum, void *datap);
 int cond_read_bool(struct policydb *p, struct hashtab *h, void *fp);
 int cond_read_list(struct policydb *p, void *fp);
 int cond_write_bool(void *key, void *datum, void *ptr);
-int cond_write_list(struct policydb *p, struct cond_node *list, void *fp);
+int cond_write_list(struct policydb *p, void *fp);
 
 void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
                struct av_decision *avd, struct extended_perms *xperms);
 void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
                struct extended_perms_decision *xpermd);
-int evaluate_cond_node(struct policydb *p, struct cond_node *node);
+void evaluate_cond_nodes(struct policydb *p);
 
 #endif /* _CONDITIONAL_H_ */
index ebfdaa3..883f19d 100644 (file)
 
 static struct kmem_cache *hashtab_node_cachep;
 
+/*
+ * Here we simply round the number of elements up to the nearest power of two.
+ * I tried also other options like rouding down or rounding to the closest
+ * power of two (up or down based on which is closer), but I was unable to
+ * find any significant difference in lookup/insert performance that would
+ * justify switching to a different (less intuitive) formula. It could be that
+ * a different formula is actually more optimal, but any future changes here
+ * should be supported with performance/memory usage data.
+ *
+ * The total memory used by the htable arrays (only) with Fedora policy loaded
+ * is approximately 163 KB at the time of writing.
+ */
+static u32 hashtab_compute_size(u32 nel)
+{
+       return nel == 0 ? 0 : roundup_pow_of_two(nel);
+}
+
 struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
                               int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
-                              u32 size)
+                              u32 nel_hint)
 {
        struct hashtab *p;
-       u32 i;
+       u32 i, size = hashtab_compute_size(nel_hint);
 
        p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p)
@@ -27,6 +44,9 @@ struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *
        p->nel = 0;
        p->hash_value = hash_value;
        p->keycmp = keycmp;
+       if (!size)
+               return p;
+
        p->htable = kmalloc_array(size, sizeof(*p->htable), GFP_KERNEL);
        if (!p->htable) {
                kfree(p);
@@ -46,7 +66,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)
 
        cond_resched();
 
-       if (!h || h->nel == HASHTAB_MAX_NODES)
+       if (!h || !h->size || h->nel == HASHTAB_MAX_NODES)
                return -EINVAL;
 
        hvalue = h->hash_value(h, key);
@@ -82,7 +102,7 @@ void *hashtab_search(struct hashtab *h, const void *key)
        u32 hvalue;
        struct hashtab_node *cur;
 
-       if (!h)
+       if (!h || !h->size)
                return NULL;
 
        hvalue = h->hash_value(h, key);
index 3e3e42b..dde54d9 100644 (file)
@@ -42,7 +42,7 @@ struct hashtab_info {
  */
 struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key),
                               int (*keycmp)(struct hashtab *h, const void *key1, const void *key2),
-                              u32 size);
+                              u32 nel_hint);
 
 /*
  * Inserts the specified (key, datum) pair into the specified hash table.
index 2aa7f2e..70ecdc7 100644 (file)
@@ -56,17 +56,6 @@ static const char *symtab_name[SYM_NUM] = {
 };
 #endif
 
-static unsigned int symtab_sizes[SYM_NUM] = {
-       2,
-       32,
-       16,
-       512,
-       128,
-       16,
-       16,
-       16,
-};
-
 struct policydb_compat_info {
        int version;
        int sym_num;
@@ -336,11 +325,17 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
 
 static int filenametr_destroy(void *key, void *datum, void *p)
 {
-       struct filename_trans *ft = key;
+       struct filename_trans_key *ft = key;
+       struct filename_trans_datum *next, *d = datum;
 
        kfree(ft->name);
        kfree(key);
-       kfree(datum);
+       do {
+               ebitmap_destroy(&d->stypes);
+               next = d->next;
+               kfree(d);
+               d = next;
+       } while (unlikely(d));
        cond_resched();
        return 0;
 }
@@ -406,12 +401,12 @@ out:
 
 static u32 filenametr_hash(struct hashtab *h, const void *k)
 {
-       const struct filename_trans *ft = k;
+       const struct filename_trans_key *ft = k;
        unsigned long hash;
        unsigned int byte_num;
        unsigned char focus;
 
-       hash = ft->stype ^ ft->ttype ^ ft->tclass;
+       hash = ft->ttype ^ ft->tclass;
 
        byte_num = 0;
        while ((focus = ft->name[byte_num++]))
@@ -421,14 +416,10 @@ static u32 filenametr_hash(struct hashtab *h, const void *k)
 
 static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
 {
-       const struct filename_trans *ft1 = k1;
-       const struct filename_trans *ft2 = k2;
+       const struct filename_trans_key *ft1 = k1;
+       const struct filename_trans_key *ft2 = k2;
        int v;
 
-       v = ft1->stype - ft2->stype;
-       if (v)
-               return v;
-
        v = ft1->ttype - ft2->ttype;
        if (v)
                return v;
@@ -472,54 +463,21 @@ static int rangetr_cmp(struct hashtab *h, const void *k1, const void *k2)
  */
 static int policydb_init(struct policydb *p)
 {
-       int i, rc;
-
        memset(p, 0, sizeof(*p));
 
-       for (i = 0; i < SYM_NUM; i++) {
-               rc = symtab_init(&p->symtab[i], symtab_sizes[i]);
-               if (rc)
-                       goto out;
-       }
-
-       rc = avtab_init(&p->te_avtab);
-       if (rc)
-               goto out;
-
-       rc = roles_init(p);
-       if (rc)
-               goto out;
-
-       rc = cond_policydb_init(p);
-       if (rc)
-               goto out;
+       avtab_init(&p->te_avtab);
+       cond_policydb_init(p);
 
        p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp,
-                                          (1 << 10));
-       if (!p->filename_trans) {
-               rc = -ENOMEM;
-               goto out;
-       }
-
-       p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
-       if (!p->range_tr) {
-               rc = -ENOMEM;
-               goto out;
-       }
+                                          (1 << 11));
+       if (!p->filename_trans)
+               return -ENOMEM;
 
        ebitmap_init(&p->filename_trans_ttypes);
        ebitmap_init(&p->policycaps);
        ebitmap_init(&p->permissive_map);
 
        return 0;
-out:
-       hashtab_destroy(p->filename_trans);
-       hashtab_destroy(p->range_tr);
-       for (i = 0; i < SYM_NUM; i++) {
-               hashtab_map(p->symtab[i].table, destroy_f[i], NULL);
-               hashtab_destroy(p->symtab[i].table);
-       }
-       return rc;
 }
 
 /*
@@ -865,29 +823,28 @@ int policydb_load_isids(struct policydb *p, struct sidtab *s)
 
        head = p->ocontexts[OCON_ISID];
        for (c = head; c; c = c->next) {
-               rc = -EINVAL;
-               if (!c->context[0].user) {
-                       pr_err("SELinux:  SID %s was never defined.\n",
-                               c->u.name);
-                       sidtab_destroy(s);
-                       goto out;
-               }
-               if (c->sid[0] == SECSID_NULL || c->sid[0] > SECINITSID_NUM) {
-                       pr_err("SELinux:  Initial SID %s out of range.\n",
-                               c->u.name);
+               u32 sid = c->sid[0];
+               const char *name = security_get_initial_sid_context(sid);
+
+               if (sid == SECSID_NULL) {
+                       pr_err("SELinux:  SID 0 was assigned a context.\n");
                        sidtab_destroy(s);
                        goto out;
                }
+
+               /* Ignore initial SIDs unused by this kernel. */
+               if (!name)
+                       continue;
+
                rc = context_add_hash(p, &c->context[0]);
                if (rc) {
                        sidtab_destroy(s);
                        goto out;
                }
-
-               rc = sidtab_set_initial(s, c->sid[0], &c->context[0]);
+               rc = sidtab_set_initial(s, sid, &c->context[0]);
                if (rc) {
                        pr_err("SELinux:  unable to load initial SID %s.\n",
-                               c->u.name);
+                              name);
                        sidtab_destroy(s);
                        goto out;
                }
@@ -1140,12 +1097,12 @@ static int common_read(struct policydb *p, struct hashtab *h, void *fp)
 
        len = le32_to_cpu(buf[0]);
        comdatum->value = le32_to_cpu(buf[1]);
+       nel = le32_to_cpu(buf[3]);
 
-       rc = symtab_init(&comdatum->permissions, PERM_SYMTAB_SIZE);
+       rc = symtab_init(&comdatum->permissions, nel);
        if (rc)
                goto bad;
        comdatum->permissions.nprim = le32_to_cpu(buf[2]);
-       nel = le32_to_cpu(buf[3]);
 
        rc = str_read(&key, GFP_KERNEL, fp, len);
        if (rc)
@@ -1262,10 +1219,9 @@ static int read_cons_helper(struct policydb *p,
                                if (rc)
                                        return rc;
                                if (p->policyvers >=
-                                       POLICYDB_VERSION_CONSTRAINT_NAMES) {
-                                               e->type_names = kzalloc(sizeof
-                                               (*e->type_names),
-                                               GFP_KERNEL);
+                                   POLICYDB_VERSION_CONSTRAINT_NAMES) {
+                                       e->type_names = kzalloc(sizeof
+                                               (*e->type_names), GFP_KERNEL);
                                        if (!e->type_names)
                                                return -ENOMEM;
                                        type_set_init(e->type_names);
@@ -1306,12 +1262,12 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
        len = le32_to_cpu(buf[0]);
        len2 = le32_to_cpu(buf[1]);
        cladatum->value = le32_to_cpu(buf[2]);
+       nel = le32_to_cpu(buf[4]);
 
-       rc = symtab_init(&cladatum->permissions, PERM_SYMTAB_SIZE);
+       rc = symtab_init(&cladatum->permissions, nel);
        if (rc)
                goto bad;
        cladatum->permissions.nprim = le32_to_cpu(buf[3]);
-       nel = le32_to_cpu(buf[4]);
 
        ncons = le32_to_cpu(buf[5]);
 
@@ -1824,6 +1780,11 @@ static int range_read(struct policydb *p, void *fp)
                return rc;
 
        nel = le32_to_cpu(buf[0]);
+
+       p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, nel);
+       if (!p->range_tr)
+               return -ENOMEM;
+
        for (i = 0; i < nel; i++) {
                rc = -ENOMEM;
                rt = kzalloc(sizeof(*rt), GFP_KERNEL);
@@ -1880,88 +1841,114 @@ out:
        return rc;
 }
 
-static int filename_trans_read(struct policydb *p, void *fp)
+static int filename_trans_read_one(struct policydb *p, void *fp)
 {
-       struct filename_trans *ft;
-       struct filename_trans_datum *otype;
-       char *name;
-       u32 nel, len;
+       struct filename_trans_key key, *ft = NULL;
+       struct filename_trans_datum *last, *datum = NULL;
+       char *name = NULL;
+       u32 len, stype, otype;
        __le32 buf[4];
-       int rc, i;
-
-       if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
-               return 0;
+       int rc;
 
+       /* length of the path component string */
        rc = next_entry(buf, fp, sizeof(u32));
        if (rc)
                return rc;
-       nel = le32_to_cpu(buf[0]);
+       len = le32_to_cpu(buf[0]);
 
-       for (i = 0; i < nel; i++) {
-               otype = NULL;
-               name = NULL;
+       /* path component string */
+       rc = str_read(&name, GFP_KERNEL, fp, len);
+       if (rc)
+               return rc;
 
-               rc = -ENOMEM;
-               ft = kzalloc(sizeof(*ft), GFP_KERNEL);
-               if (!ft)
-                       goto out;
+       rc = next_entry(buf, fp, sizeof(u32) * 4);
+       if (rc)
+               goto out;
 
-               rc = -ENOMEM;
-               otype = kmalloc(sizeof(*otype), GFP_KERNEL);
-               if (!otype)
-                       goto out;
+       stype = le32_to_cpu(buf[0]);
+       key.ttype = le32_to_cpu(buf[1]);
+       key.tclass = le32_to_cpu(buf[2]);
+       key.name = name;
 
-               /* length of the path component string */
-               rc = next_entry(buf, fp, sizeof(u32));
-               if (rc)
-                       goto out;
-               len = le32_to_cpu(buf[0]);
+       otype = le32_to_cpu(buf[3]);
 
-               /* path component string */
-               rc = str_read(&name, GFP_KERNEL, fp, len);
-               if (rc)
+       last = NULL;
+       datum = hashtab_search(p->filename_trans, &key);
+       while (datum) {
+               if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
+                       /* conflicting/duplicate rules are ignored */
+                       datum = NULL;
                        goto out;
-
-               ft->name = name;
-
-               rc = next_entry(buf, fp, sizeof(u32) * 4);
-               if (rc)
+               }
+               if (likely(datum->otype == otype))
+                       break;
+               last = datum;
+               datum = datum->next;
+       }
+       if (!datum) {
+               rc = -ENOMEM;
+               datum = kmalloc(sizeof(*datum), GFP_KERNEL);
+               if (!datum)
                        goto out;
 
-               ft->stype = le32_to_cpu(buf[0]);
-               ft->ttype = le32_to_cpu(buf[1]);
-               ft->tclass = le32_to_cpu(buf[2]);
-
-               otype->otype = le32_to_cpu(buf[3]);
+               ebitmap_init(&datum->stypes);
+               datum->otype = otype;
+               datum->next = NULL;
 
-               rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
-               if (rc)
-                       goto out;
+               if (unlikely(last)) {
+                       last->next = datum;
+               } else {
+                       rc = -ENOMEM;
+                       ft = kmemdup(&key, sizeof(key), GFP_KERNEL);
+                       if (!ft)
+                               goto out;
 
-               rc = hashtab_insert(p->filename_trans, ft, otype);
-               if (rc) {
-                       /*
-                        * Do not return -EEXIST to the caller, or the system
-                        * will not boot.
-                        */
-                       if (rc != -EEXIST)
+                       rc = hashtab_insert(p->filename_trans, ft, datum);
+                       if (rc)
                                goto out;
-                       /* But free memory to avoid memory leak. */
-                       kfree(ft);
-                       kfree(name);
-                       kfree(otype);
+                       name = NULL;
+
+                       rc = ebitmap_set_bit(&p->filename_trans_ttypes,
+                                            key.ttype, 1);
+                       if (rc)
+                               return rc;
                }
        }
-       hash_eval(p->filename_trans, "filenametr");
-       return 0;
+       kfree(name);
+       return ebitmap_set_bit(&datum->stypes, stype - 1, 1);
+
 out:
        kfree(ft);
        kfree(name);
-       kfree(otype);
-
+       kfree(datum);
        return rc;
 }
 
+static int filename_trans_read(struct policydb *p, void *fp)
+{
+       u32 nel;
+       __le32 buf[1];
+       int rc, i;
+
+       if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
+               return 0;
+
+       rc = next_entry(buf, fp, sizeof(u32));
+       if (rc)
+               return rc;
+       nel = le32_to_cpu(buf[0]);
+
+       p->filename_trans_count = nel;
+
+       for (i = 0; i < nel; i++) {
+               rc = filename_trans_read_one(p, fp);
+               if (rc)
+                       return rc;
+       }
+       hash_eval(p->filename_trans, "filenametr");
+       return 0;
+}
+
 static int genfs_read(struct policydb *p, void *fp)
 {
        int i, j, rc;
@@ -2390,6 +2377,17 @@ int policydb_read(struct policydb *p, void *fp)
                        goto bad;
                nprim = le32_to_cpu(buf[0]);
                nel = le32_to_cpu(buf[1]);
+
+               rc = symtab_init(&p->symtab[i], nel);
+               if (rc)
+                       goto out;
+
+               if (i == SYM_ROLES) {
+                       rc = roles_init(p);
+                       if (rc)
+                               goto out;
+               }
+
                for (j = 0; j < nel; j++) {
                        rc = read_f[i](p, p->symtab[i].table, fp);
                        if (rc)
@@ -3330,50 +3328,50 @@ static int range_write(struct policydb *p, void *fp)
 
 static int filename_write_helper(void *key, void *data, void *ptr)
 {
-       __le32 buf[4];
-       struct filename_trans *ft = key;
-       struct filename_trans_datum *otype = data;
+       struct filename_trans_key *ft = key;
+       struct filename_trans_datum *datum = data;
+       struct ebitmap_node *node;
        void *fp = ptr;
+       __le32 buf[4];
        int rc;
-       u32 len;
+       u32 bit, len = strlen(ft->name);
 
-       len = strlen(ft->name);
-       buf[0] = cpu_to_le32(len);
-       rc = put_entry(buf, sizeof(u32), 1, fp);
-       if (rc)
-               return rc;
+       do {
+               ebitmap_for_each_positive_bit(&datum->stypes, node, bit) {
+                       buf[0] = cpu_to_le32(len);
+                       rc = put_entry(buf, sizeof(u32), 1, fp);
+                       if (rc)
+                               return rc;
 
-       rc = put_entry(ft->name, sizeof(char), len, fp);
-       if (rc)
-               return rc;
+                       rc = put_entry(ft->name, sizeof(char), len, fp);
+                       if (rc)
+                               return rc;
 
-       buf[0] = cpu_to_le32(ft->stype);
-       buf[1] = cpu_to_le32(ft->ttype);
-       buf[2] = cpu_to_le32(ft->tclass);
-       buf[3] = cpu_to_le32(otype->otype);
+                       buf[0] = cpu_to_le32(bit + 1);
+                       buf[1] = cpu_to_le32(ft->ttype);
+                       buf[2] = cpu_to_le32(ft->tclass);
+                       buf[3] = cpu_to_le32(datum->otype);
 
-       rc = put_entry(buf, sizeof(u32), 4, fp);
-       if (rc)
-               return rc;
+                       rc = put_entry(buf, sizeof(u32), 4, fp);
+                       if (rc)
+                               return rc;
+               }
+
+               datum = datum->next;
+       } while (unlikely(datum));
 
        return 0;
 }
 
 static int filename_trans_write(struct policydb *p, void *fp)
 {
-       u32 nel;
        __le32 buf[1];
        int rc;
 
        if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
                return 0;
 
-       nel = 0;
-       rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
-       if (rc)
-               return rc;
-
-       buf[0] = cpu_to_le32(nel);
+       buf[0] = cpu_to_le32(p->filename_trans_count);
        rc = put_entry(buf, sizeof(u32), 1, fp);
        if (rc)
                return rc;
@@ -3483,7 +3481,7 @@ int policydb_write(struct policydb *p, void *fp)
        if (rc)
                return rc;
 
-       rc = cond_write_list(p, p->cond_list, fp);
+       rc = cond_write_list(p, fp);
        if (rc)
                return rc;
 
index 69b2419..72e2932 100644 (file)
@@ -89,15 +89,16 @@ struct role_trans {
        struct role_trans *next;
 };
 
-struct filename_trans {
-       u32 stype;              /* current process */
+struct filename_trans_key {
        u32 ttype;              /* parent dir context */
        u16 tclass;             /* class of new object */
        const char *name;       /* last path component */
 };
 
 struct filename_trans_datum {
-       u32 otype;              /* expected of new object */
+       struct ebitmap stypes;  /* bitmap of source types for this otype */
+       u32 otype;              /* resulting type of new object */
+       struct filename_trans_datum *next;      /* record for next otype*/
 };
 
 struct role_allow {
@@ -267,13 +268,15 @@ struct policydb {
        struct ebitmap filename_trans_ttypes;
        /* actual set of filename_trans rules */
        struct hashtab *filename_trans;
+       u32 filename_trans_count;
 
        /* bools indexed by (value - 1) */
        struct cond_bool_datum **bool_val_to_struct;
        /* type enforcement conditional access vectors and transitions */
        struct avtab te_cond_avtab;
-       /* linked list indexing te_cond_avtab by conditional */
+       /* array indexing te_cond_avtab by conditional */
        struct cond_node *cond_list;
+       u32 cond_list_len;
 
        /* role allows */
        struct role_allow *role_allow;
@@ -318,8 +321,6 @@ extern int policydb_role_isvalid(struct policydb *p, unsigned int role);
 extern int policydb_read(struct policydb *p, void *fp);
 extern int policydb_write(struct policydb *p, void *fp);
 
-#define PERM_SYMTAB_SIZE 32
-
 #define POLICYDB_CONFIG_MLS    1
 
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
index 216ce60..8ad34fd 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/in.h>
 #include <linux/sched.h>
 #include <linux/audit.h>
-#include <linux/mutex.h>
 #include <linux/vmalloc.h>
 #include <net/netlabel.h>
 
@@ -73,7 +72,8 @@ const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
        "extended_socket_class",
        "always_check_network",
        "cgroup_seclabel",
-       "nnp_nosuid_transition"
+       "nnp_nosuid_transition",
+       "genfs_seclabel_symlinks"
 };
 
 static struct selinux_ss selinux_ss;
@@ -81,7 +81,6 @@ static struct selinux_ss selinux_ss;
 void selinux_ss_init(struct selinux_ss **ss)
 {
        rwlock_init(&selinux_ss.policy_rwlock);
-       mutex_init(&selinux_ss.status_lock);
        *ss = &selinux_ss;
 }
 
@@ -1323,23 +1322,22 @@ static int security_sid_to_context_core(struct selinux_state *state,
        if (!selinux_initialized(state)) {
                if (sid <= SECINITSID_NUM) {
                        char *scontextp;
+                       const char *s = initial_sid_to_string[sid];
 
-                       *scontext_len = strlen(initial_sid_to_string[sid]) + 1;
+                       if (!s)
+                               return -EINVAL;
+                       *scontext_len = strlen(s) + 1;
                        if (!scontext)
-                               goto out;
-                       scontextp = kmemdup(initial_sid_to_string[sid],
-                                           *scontext_len, GFP_ATOMIC);
-                       if (!scontextp) {
-                               rc = -ENOMEM;
-                               goto out;
-                       }
+                               return 0;
+                       scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
+                       if (!scontextp)
+                               return -ENOMEM;
                        *scontext = scontextp;
-                       goto out;
+                       return 0;
                }
                pr_err("SELinux: %s:  called before initial "
                       "load_policy on unknown SID %d\n", __func__, sid);
-               rc = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
        read_lock(&state->ss->policy_rwlock);
        policydb = &state->ss->policydb;
@@ -1363,7 +1361,6 @@ static int security_sid_to_context_core(struct selinux_state *state,
 
 out_unlock:
        read_unlock(&state->ss->policy_rwlock);
-out:
        return rc;
 
 }
@@ -1553,7 +1550,9 @@ static int security_context_to_sid_core(struct selinux_state *state,
                int i;
 
                for (i = 1; i < SECINITSID_NUM; i++) {
-                       if (!strcmp(initial_sid_to_string[i], scontext2)) {
+                       const char *s = initial_sid_to_string[i];
+
+                       if (s && !strcmp(s, scontext2)) {
                                *sid = i;
                                goto out;
                        }
@@ -1693,8 +1692,8 @@ static void filename_compute_type(struct policydb *policydb,
                                  u32 stype, u32 ttype, u16 tclass,
                                  const char *objname)
 {
-       struct filename_trans ft;
-       struct filename_trans_datum *otype;
+       struct filename_trans_key ft;
+       struct filename_trans_datum *datum;
 
        /*
         * Most filename trans rules are going to live in specific directories
@@ -1704,14 +1703,18 @@ static void filename_compute_type(struct policydb *policydb,
        if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
                return;
 
-       ft.stype = stype;
        ft.ttype = ttype;
        ft.tclass = tclass;
        ft.name = objname;
 
-       otype = hashtab_search(policydb->filename_trans, &ft);
-       if (otype)
-               newcontext->type = otype->otype;
+       datum = hashtab_search(policydb->filename_trans, &ft);
+       while (datum) {
+               if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
+                       newcontext->type = datum->otype;
+                       return;
+               }
+               datum = datum->next;
+       }
 }
 
 static int security_compute_sid(struct selinux_state *state,
@@ -2868,10 +2871,11 @@ out:
 }
 
 int security_get_bools(struct selinux_state *state,
-                      int *len, char ***names, int **values)
+                      u32 *len, char ***names, int **values)
 {
        struct policydb *policydb;
-       int i, rc;
+       u32 i;
+       int rc;
 
        if (!selinux_initialized(state)) {
                *len = 0;
@@ -2925,12 +2929,11 @@ err:
 }
 
 
-int security_set_bools(struct selinux_state *state, int len, int *values)
+int security_set_bools(struct selinux_state *state, u32 len, int *values)
 {
        struct policydb *policydb;
-       int i, rc;
-       int lenp, seqno = 0;
-       struct cond_node *cur;
+       int rc;
+       u32 i, lenp, seqno = 0;
 
        write_lock_irq(&state->ss->policy_rwlock);
 
@@ -2958,11 +2961,7 @@ int security_set_bools(struct selinux_state *state, int len, int *values)
                        policydb->bool_val_to_struct[i]->state = 0;
        }
 
-       for (cur = policydb->cond_list; cur; cur = cur->next) {
-               rc = evaluate_cond_node(policydb, cur);
-               if (rc)
-                       goto out;
-       }
+       evaluate_cond_nodes(policydb);
 
        seqno = ++state->ss->latest_granting;
        rc = 0;
@@ -2978,11 +2977,11 @@ out:
 }
 
 int security_get_bool_value(struct selinux_state *state,
-                           int index)
+                           u32 index)
 {
        struct policydb *policydb;
        int rc;
-       int len;
+       u32 len;
 
        read_lock(&state->ss->policy_rwlock);
 
@@ -3002,10 +3001,10 @@ out:
 static int security_preserve_bools(struct selinux_state *state,
                                   struct policydb *policydb)
 {
-       int rc, nbools = 0, *bvalues = NULL, i;
+       int rc, *bvalues = NULL;
        char **bnames = NULL;
        struct cond_bool_datum *booldatum;
-       struct cond_node *cur;
+       u32 i, nbools = 0;
 
        rc = security_get_bools(state, &nbools, &bnames, &bvalues);
        if (rc)
@@ -3015,11 +3014,7 @@ static int security_preserve_bools(struct selinux_state *state,
                if (booldatum)
                        booldatum->state = bvalues[i];
        }
-       for (cur = policydb->cond_list; cur; cur = cur->next) {
-               rc = evaluate_cond_node(policydb, cur);
-               if (rc)
-                       goto out;
-       }
+       evaluate_cond_nodes(policydb);
 
 out:
        if (bnames) {
index c5896f3..e9bddf3 100644 (file)
@@ -29,8 +29,6 @@ struct selinux_ss {
        rwlock_t policy_rwlock;
        u32 latest_granting;
        struct selinux_map map;
-       struct page *status_page;
-       struct mutex status_lock;
 } __randomize_layout;
 
 void services_compute_xperms_drivers(struct extended_perms *xperms,
similarity index 81%
rename from security/selinux/ss/status.c
rename to security/selinux/status.c
index 3c554a4..4bc8f80 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/mm.h>
 #include <linux/mutex.h>
 #include "avc.h"
-#include "services.h"
+#include "security.h"
 
 /*
  * The selinux_status_page shall be exposed to userspace applications
@@ -44,12 +44,12 @@ struct page *selinux_kernel_status_page(struct selinux_state *state)
        struct selinux_kernel_status   *status;
        struct page                    *result = NULL;
 
-       mutex_lock(&state->ss->status_lock);
-       if (!state->ss->status_page) {
-               state->ss->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
+       mutex_lock(&state->status_lock);
+       if (!state->status_page) {
+               state->status_page = alloc_page(GFP_KERNEL|__GFP_ZERO);
 
-               if (state->ss->status_page) {
-                       status = page_address(state->ss->status_page);
+               if (state->status_page) {
+                       status = page_address(state->status_page);
 
                        status->version = SELINUX_KERNEL_STATUS_VERSION;
                        status->sequence = 0;
@@ -65,8 +65,8 @@ struct page *selinux_kernel_status_page(struct selinux_state *state)
                                !security_get_allow_unknown(state);
                }
        }
-       result = state->ss->status_page;
-       mutex_unlock(&state->ss->status_lock);
+       result = state->status_page;
+       mutex_unlock(&state->status_lock);
 
        return result;
 }
@@ -81,9 +81,9 @@ void selinux_status_update_setenforce(struct selinux_state *state,
 {
        struct selinux_kernel_status   *status;
 
-       mutex_lock(&state->ss->status_lock);
-       if (state->ss->status_page) {
-               status = page_address(state->ss->status_page);
+       mutex_lock(&state->status_lock);
+       if (state->status_page) {
+               status = page_address(state->status_page);
 
                status->sequence++;
                smp_wmb();
@@ -93,7 +93,7 @@ void selinux_status_update_setenforce(struct selinux_state *state,
                smp_wmb();
                status->sequence++;
        }
-       mutex_unlock(&state->ss->status_lock);
+       mutex_unlock(&state->status_lock);
 }
 
 /*
@@ -107,9 +107,9 @@ void selinux_status_update_policyload(struct selinux_state *state,
 {
        struct selinux_kernel_status   *status;
 
-       mutex_lock(&state->ss->status_lock);
-       if (state->ss->status_page) {
-               status = page_address(state->ss->status_page);
+       mutex_lock(&state->status_lock);
+       if (state->status_page) {
+               status = page_address(state->status_page);
 
                status->sequence++;
                smp_wmb();
@@ -120,5 +120,5 @@ void selinux_status_update_policyload(struct selinux_state *state,
                smp_wmb();
                status->sequence++;
        }
-       mutex_unlock(&state->ss->status_lock);
+       mutex_unlock(&state->status_lock);
 }