Merge tag 'apparmor-pr-2018-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 13 Apr 2018 22:38:53 +0000 (15:38 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 13 Apr 2018 22:38:53 +0000 (15:38 -0700)
Pull apparmor updates from John Johansen:
 "Features:
  - add base infrastructure for socket mediation. ABI bump and
    additional checks to ensure only v8 compliant policy uses socket af
    mediation.
  - improve and cleanup dfa verification
  - improve profile attachment logic
     - improve overlapping expression handling
     - add the xattr matching to the attachment logic
  - improve signal mediation handling with stacked labels
  - improve handling of no_new_privs in a label stack

  Cleanups and changes:
  - use dfa to parse string split
  - bounded version of label_parse
  - proper line wrap nulldfa.in
  - split context out into task and cred naming to better match usage
  - simplify code in aafs

  Bug fixes:
  - fix display of .ns_name for containers
  - fix resource audit messages when auditing peer
  - fix logging of the existence test for signals
  - fix resource audit messages when auditing peer
  - fix display of .ns_name for containers
  - fix an error code in verify_table_headers()
  - fix memory leak on buffer on error exit path
  - fix error returns checks by making size a ssize_t"

* tag 'apparmor-pr-2018-04-10' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (36 commits)
  apparmor: fix memory leak on buffer on error exit path
  apparmor: fix dangling symlinks to policy rawdata after replacement
  apparmor: Fix an error code in verify_table_headers()
  apparmor: fix error returns checks by making size a ssize_t
  apparmor: update MAINTAINERS file git and wiki locations
  apparmor: remove POLICY_MEDIATES_SAFE
  apparmor: add base infastructure for socket mediation
  apparmor: improve overlapping domain attachment resolution
  apparmor: convert attaching profiles via xattrs to use dfa matching
  apparmor: Add support for attaching profiles via xattr, presence and value
  apparmor: cleanup: simplify code to get ns symlink name
  apparmor: cleanup create_aafs() error path
  apparmor: dfa split verification of table headers
  apparmor: dfa add support for state differential encoding
  apparmor: dfa move character match into a macro
  apparmor: update domain transitions that are subsets of confinement at nnp
  apparmor: move context.h to cred.h
  apparmor: move task related defines and fns to task.X files
  apparmor: cleanup, drop unused fn __aa_task_is_confined()
  apparmor: cleanup fixup description of aa_replace_profiles
  ...

33 files changed:
MAINTAINERS
security/apparmor/.gitignore
security/apparmor/Makefile
security/apparmor/apparmorfs.c
security/apparmor/capability.c
security/apparmor/domain.c
security/apparmor/file.c
security/apparmor/include/apparmor.h
security/apparmor/include/audit.h
security/apparmor/include/cred.h [moved from security/apparmor/include/context.h with 70% similarity]
security/apparmor/include/label.h
security/apparmor/include/match.h
security/apparmor/include/net.h [new file with mode: 0644]
security/apparmor/include/perms.h
security/apparmor/include/policy.h
security/apparmor/include/policy_unpack.h
security/apparmor/include/sig_names.h
security/apparmor/include/task.h [new file with mode: 0644]
security/apparmor/ipc.c
security/apparmor/label.c
security/apparmor/lib.c
security/apparmor/lsm.c
security/apparmor/match.c
security/apparmor/mount.c
security/apparmor/net.c [new file with mode: 0644]
security/apparmor/nulldfa.in
security/apparmor/policy.c
security/apparmor/policy_ns.c
security/apparmor/policy_unpack.c
security/apparmor/procattr.c
security/apparmor/resource.c
security/apparmor/stacksplitdfa.in [new file with mode: 0644]
security/apparmor/task.c [moved from security/apparmor/context.c with 53% similarity]

index f79952e6f627a1e54a545549ce4c2c8954fe3b5c..9b091ef6579b0f8592e35cac37a4b7889570a347 100644 (file)
@@ -934,8 +934,8 @@ F:  drivers/char/apm-emulation.c
 APPARMOR SECURITY MODULE
 M:     John Johansen <john.johansen@canonical.com>
 L:     apparmor@lists.ubuntu.com (subscribers-only, general discussion)
-W:     apparmor.wiki.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git
+W:     wiki.apparmor.net
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
 S:     Supported
 F:     security/apparmor/
 F:     Documentation/admin-guide/LSM/apparmor.rst
index 9cdec70d72b8ed83c38ec3a271b9495b53975b2e..d5b291e94264f9784438ea38e3242ad7697cb510 100644 (file)
@@ -1,5 +1,6 @@
 #
 # Generated include files
 #
+net_names.h
 capability_names.h
 rlim_names.h
index 9a6b4033d52b8f5459a7ac49b7d7b05ef38a2967..ff23fcfefe196da8d7e09f18c9eb8a4c4a5c2c08 100644 (file)
@@ -3,13 +3,46 @@
 #
 obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
 
-apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \
+apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \
               path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
-              resource.o secid.o file.o policy_ns.o label.o mount.o
+              resource.o secid.o file.o policy_ns.o label.o mount.o net.o
 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
 
-clean-files := capability_names.h rlim_names.h
+clean-files := capability_names.h rlim_names.h net_names.h
 
+# Build a lower case string table of address family names
+# Transform lines from
+#    #define AF_LOCAL          1       /* POSIX name for AF_UNIX       */
+#    #define AF_INET           2       /* Internet IP Protocol         */
+# to
+#    [1] = "local",
+#    [2] = "inet",
+#
+# and build the securityfs entries for the mapping.
+# Transforms lines from
+#    #define AF_INET           2       /* Internet IP Protocol         */
+# to
+#    #define AA_SFS_AF_MASK "local inet"
+quiet_cmd_make-af = GEN     $@
+cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\
+       sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
+        's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+       echo "};" >> $@ ;\
+       printf '%s' '\#define AA_SFS_AF_MASK "' >> $@ ;\
+       sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \
+        's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\
+        $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
+
+# Build a lower case string table of sock type names
+# Transform lines from
+#    SOCK_STREAM       = 1,
+# to
+#    [1] = "stream",
+quiet_cmd_make-sock = GEN     $@
+cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\
+       sed $^ >>$@ -r -n \
+       -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\
+       echo "};" >> $@
 
 # Build a lower case string table of capability names
 # Transforms lines from
@@ -62,6 +95,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \
            tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@
 
 $(obj)/capability.o : $(obj)/capability_names.h
+$(obj)/net.o : $(obj)/net_names.h
 $(obj)/resource.o : $(obj)/rlim_names.h
 $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
                            $(src)/Makefile
@@ -69,3 +103,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \
 $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \
                      $(src)/Makefile
        $(call cmd,make-rlim)
+$(obj)/net_names.h : $(srctree)/include/linux/socket.h \
+                    $(srctree)/include/linux/net.h \
+                    $(src)/Makefile
+       $(call cmd,make-af)
+       $(call cmd,make-sock)
index a9428daa69f3096367d028adc6c48f1280d4e139..949dd8a48164a3efe2618356ddffc3a7c96d79cc 100644 (file)
 #include "include/apparmor.h"
 #include "include/apparmorfs.h"
 #include "include/audit.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/crypto.h"
 #include "include/ipc.h"
-#include "include/policy_ns.h"
 #include "include/label.h"
 #include "include/policy.h"
 #include "include/policy_ns.h"
@@ -120,9 +119,7 @@ static int aafs_count;
 
 static int aafs_show_path(struct seq_file *seq, struct dentry *dentry)
 {
-       struct inode *inode = d_inode(dentry);
-
-       seq_printf(seq, "%s:[%lu]", AAFS_NAME, inode->i_ino);
+       seq_printf(seq, "%s:[%lu]", AAFS_NAME, d_inode(dentry)->i_ino);
        return 0;
 }
 
@@ -313,6 +310,7 @@ static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
  * @name: name of dentry to create
  * @parent: parent directory for this dentry
  * @target: if symlink, symlink target string
+ * @private: private data
  * @iops: struct of inode_operations that should be used
  *
  * If @target parameter is %NULL, then the @iops parameter needs to be
@@ -321,17 +319,17 @@ static struct dentry *aafs_create_dir(const char *name, struct dentry *parent)
 static struct dentry *aafs_create_symlink(const char *name,
                                          struct dentry *parent,
                                          const char *target,
+                                         void *private,
                                          const struct inode_operations *iops)
 {
        struct dentry *dent;
        char *link = NULL;
 
        if (target) {
-               link = kstrdup(target, GFP_KERNEL);
                if (!link)
                        return ERR_PTR(-ENOMEM);
        }
-       dent = aafs_create(name, S_IFLNK | 0444, parent, NULL, link, NULL,
+       dent = aafs_create(name, S_IFLNK | 0444, parent, private, link, NULL,
                           iops);
        if (IS_ERR(dent))
                kfree(link);
@@ -622,7 +620,7 @@ static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
                        tmp = aa_compute_fperms(dfa, state, &cond);
                }
        } else if (profile->policy.dfa) {
-               if (!PROFILE_MEDIATES_SAFE(profile, *match_str))
+               if (!PROFILE_MEDIATES(profile, *match_str))
                        return; /* no change to current perms */
                dfa = profile->policy.dfa;
                state = aa_dfa_match_len(dfa, profile->policy.start[0],
@@ -1189,9 +1187,7 @@ static int seq_ns_level_show(struct seq_file *seq, void *v)
 static int seq_ns_name_show(struct seq_file *seq, void *v)
 {
        struct aa_label *label = begin_current_label_crit_section();
-
-       seq_printf(seq, "%s\n", aa_ns_name(labels_ns(label),
-                                          labels_ns(label), true));
+       seq_printf(seq, "%s\n", labels_ns(label)->base.name);
        end_current_label_crit_section(label);
 
        return 0;
@@ -1484,26 +1480,97 @@ static int profile_depth(struct aa_profile *profile)
        return depth;
 }
 
-static int gen_symlink_name(char *buffer, size_t bsize, int depth,
-                           const char *dirname, const char *fname)
+static char *gen_symlink_name(int depth, const char *dirname, const char *fname)
 {
+       char *buffer, *s;
        int error;
+       int size = depth * 6 + strlen(dirname) + strlen(fname) + 11;
+
+       s = buffer = kmalloc(size, GFP_KERNEL);
+       if (!buffer)
+               return ERR_PTR(-ENOMEM);
 
        for (; depth > 0; depth--) {
-               if (bsize < 7)
-                       return -ENAMETOOLONG;
-               strcpy(buffer, "../../");
-               buffer += 6;
-               bsize -= 6;
+               strcpy(s, "../../");
+               s += 6;
+               size -= 6;
        }
 
-       error = snprintf(buffer, bsize, "raw_data/%s/%s", dirname, fname);
-       if (error >= bsize || error < 0)
-               return -ENAMETOOLONG;
+       error = snprintf(s, size, "raw_data/%s/%s", dirname, fname);
+       if (error >= size || error < 0) {
+               kfree(buffer);
+               return ERR_PTR(-ENAMETOOLONG);
+       }
 
-       return 0;
+       return buffer;
+}
+
+static void rawdata_link_cb(void *arg)
+{
+       kfree(arg);
+}
+
+static const char *rawdata_get_link_base(struct dentry *dentry,
+                                        struct inode *inode,
+                                        struct delayed_call *done,
+                                        const char *name)
+{
+       struct aa_proxy *proxy = inode->i_private;
+       struct aa_label *label;
+       struct aa_profile *profile;
+       char *target;
+       int depth;
+
+       if (!dentry)
+               return ERR_PTR(-ECHILD);
+
+       label = aa_get_label_rcu(&proxy->label);
+       profile = labels_profile(label);
+       depth = profile_depth(profile);
+       target = gen_symlink_name(depth, profile->rawdata->name, name);
+       aa_put_label(label);
+
+       if (IS_ERR(target))
+               return target;
+
+       set_delayed_call(done, rawdata_link_cb, target);
+
+       return target;
+}
+
+static const char *rawdata_get_link_sha1(struct dentry *dentry,
+                                        struct inode *inode,
+                                        struct delayed_call *done)
+{
+       return rawdata_get_link_base(dentry, inode, done, "sha1");
+}
+
+static const char *rawdata_get_link_abi(struct dentry *dentry,
+                                       struct inode *inode,
+                                       struct delayed_call *done)
+{
+       return rawdata_get_link_base(dentry, inode, done, "abi");
+}
+
+static const char *rawdata_get_link_data(struct dentry *dentry,
+                                        struct inode *inode,
+                                        struct delayed_call *done)
+{
+       return rawdata_get_link_base(dentry, inode, done, "raw_data");
 }
 
+static const struct inode_operations rawdata_link_sha1_iops = {
+       .get_link       = rawdata_get_link_sha1,
+};
+
+static const struct inode_operations rawdata_link_abi_iops = {
+       .get_link       = rawdata_get_link_abi,
+};
+static const struct inode_operations rawdata_link_data_iops = {
+       .get_link       = rawdata_get_link_data,
+};
+
+
 /*
  * Requires: @profile->ns->lock held
  */
@@ -1574,34 +1641,28 @@ int __aafs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
        }
 
        if (profile->rawdata) {
-               char target[64];
-               int depth = profile_depth(profile);
-
-               error = gen_symlink_name(target, sizeof(target), depth,
-                                        profile->rawdata->name, "sha1");
-               if (error < 0)
-                       goto fail2;
-               dent = aafs_create_symlink("raw_sha1", dir, target, NULL);
+               dent = aafs_create_symlink("raw_sha1", dir, NULL,
+                                          profile->label.proxy,
+                                          &rawdata_link_sha1_iops);
                if (IS_ERR(dent))
                        goto fail;
+               aa_get_proxy(profile->label.proxy);
                profile->dents[AAFS_PROF_RAW_HASH] = dent;
 
-               error = gen_symlink_name(target, sizeof(target), depth,
-                                        profile->rawdata->name, "abi");
-               if (error < 0)
-                       goto fail2;
-               dent = aafs_create_symlink("raw_abi", dir, target, NULL);
+               dent = aafs_create_symlink("raw_abi", dir, NULL,
+                                          profile->label.proxy,
+                                          &rawdata_link_abi_iops);
                if (IS_ERR(dent))
                        goto fail;
+               aa_get_proxy(profile->label.proxy);
                profile->dents[AAFS_PROF_RAW_ABI] = dent;
 
-               error = gen_symlink_name(target, sizeof(target), depth,
-                                        profile->rawdata->name, "raw_data");
-               if (error < 0)
-                       goto fail2;
-               dent = aafs_create_symlink("raw_data", dir, target, NULL);
+               dent = aafs_create_symlink("raw_data", dir, NULL,
+                                          profile->label.proxy,
+                                          &rawdata_link_data_iops);
                if (IS_ERR(dent))
                        goto fail;
+               aa_get_proxy(profile->label.proxy);
                profile->dents[AAFS_PROF_RAW_DATA] = dent;
        }
 
@@ -2152,6 +2213,10 @@ static struct aa_sfs_entry aa_sfs_entry_signal[] = {
        { }
 };
 
+static struct aa_sfs_entry aa_sfs_entry_attach[] = {
+       AA_SFS_FILE_BOOLEAN("xattr", 1),
+       { }
+};
 static struct aa_sfs_entry aa_sfs_entry_domain[] = {
        AA_SFS_FILE_BOOLEAN("change_hat",       1),
        AA_SFS_FILE_BOOLEAN("change_hatv",      1),
@@ -2159,6 +2224,9 @@ static struct aa_sfs_entry aa_sfs_entry_domain[] = {
        AA_SFS_FILE_BOOLEAN("change_profile",   1),
        AA_SFS_FILE_BOOLEAN("stack",            1),
        AA_SFS_FILE_BOOLEAN("fix_binfmt_elf_mmap",      1),
+       AA_SFS_FILE_BOOLEAN("post_nnp_subset",  1),
+       AA_SFS_FILE_BOOLEAN("computed_longest_left",    1),
+       AA_SFS_DIR("attach_conditions",         aa_sfs_entry_attach),
        AA_SFS_FILE_STRING("version", "1.2"),
        { }
 };
@@ -2167,6 +2235,7 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = {
        AA_SFS_FILE_BOOLEAN("v5",       1),
        AA_SFS_FILE_BOOLEAN("v6",       1),
        AA_SFS_FILE_BOOLEAN("v7",       1),
+       AA_SFS_FILE_BOOLEAN("v8",       1),
        { }
 };
 
@@ -2202,6 +2271,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
        AA_SFS_DIR("policy",                    aa_sfs_entry_policy),
        AA_SFS_DIR("domain",                    aa_sfs_entry_domain),
        AA_SFS_DIR("file",                      aa_sfs_entry_file),
+       AA_SFS_DIR("network_v8",                aa_sfs_entry_network),
        AA_SFS_DIR("mount",                     aa_sfs_entry_mount),
        AA_SFS_DIR("namespaces",                aa_sfs_entry_ns),
        AA_SFS_FILE_U64("capability",           VFS_CAP_FLAGS_MASK),
@@ -2394,29 +2464,18 @@ static const char *policy_get_link(struct dentry *dentry,
        return NULL;
 }
 
-static int ns_get_name(char *buf, size_t size, struct aa_ns *ns,
-                      struct inode *inode)
-{
-       int res = snprintf(buf, size, "%s:[%lu]", AAFS_NAME, inode->i_ino);
-
-       if (res < 0 || res >= size)
-               res = -ENOENT;
-
-       return res;
-}
-
 static int policy_readlink(struct dentry *dentry, char __user *buffer,
                           int buflen)
 {
-       struct aa_ns *ns;
        char name[32];
        int res;
 
-       ns = aa_get_current_ns();
-       res = ns_get_name(name, sizeof(name), ns, d_inode(dentry));
-       if (res >= 0)
+       res = snprintf(name, sizeof(name), "%s:[%lu]", AAFS_NAME,
+                      d_inode(dentry)->i_ino);
+       if (res > 0 && res < sizeof(name))
                res = readlink_copy(buffer, buflen, name);
-       aa_put_ns(ns);
+       else
+               res = -ENOENT;
 
        return res;
 }
@@ -2460,34 +2519,26 @@ static int __init aa_create_aafs(void)
 
        dent = securityfs_create_file(".load", 0666, aa_sfs_entry.dentry,
                                      NULL, &aa_fs_profile_load);
-       if (IS_ERR(dent)) {
-               error = PTR_ERR(dent);
-               goto error;
-       }
+       if (IS_ERR(dent))
+               goto dent_error;
        ns_subload(root_ns) = dent;
 
        dent = securityfs_create_file(".replace", 0666, aa_sfs_entry.dentry,
                                      NULL, &aa_fs_profile_replace);
-       if (IS_ERR(dent)) {
-               error = PTR_ERR(dent);
-               goto error;
-       }
+       if (IS_ERR(dent))
+               goto dent_error;
        ns_subreplace(root_ns) = dent;
 
        dent = securityfs_create_file(".remove", 0666, aa_sfs_entry.dentry,
                                      NULL, &aa_fs_profile_remove);
-       if (IS_ERR(dent)) {
-               error = PTR_ERR(dent);
-               goto error;
-       }
+       if (IS_ERR(dent))
+               goto dent_error;
        ns_subremove(root_ns) = dent;
 
        dent = securityfs_create_file("revision", 0444, aa_sfs_entry.dentry,
                                      NULL, &aa_fs_ns_revision_fops);
-       if (IS_ERR(dent)) {
-               error = PTR_ERR(dent);
-               goto error;
-       }
+       if (IS_ERR(dent))
+               goto dent_error;
        ns_subrevision(root_ns) = dent;
 
        /* policy tree referenced by magic policy symlink */
@@ -2501,10 +2552,8 @@ static int __init aa_create_aafs(void)
        /* magic symlink similar to nsfs redirects based on task policy */
        dent = securityfs_create_symlink("policy", aa_sfs_entry.dentry,
                                         NULL, &policy_link_iops);
-       if (IS_ERR(dent)) {
-               error = PTR_ERR(dent);
-               goto error;
-       }
+       if (IS_ERR(dent))
+               goto dent_error;
 
        error = aa_mk_null_file(aa_sfs_entry.dentry);
        if (error)
@@ -2516,6 +2565,8 @@ static int __init aa_create_aafs(void)
        aa_info_message("AppArmor Filesystem Enabled");
        return 0;
 
+dent_error:
+       error = PTR_ERR(dent);
 error:
        aa_destroy_aafs();
        AA_ERROR("Error creating AppArmor securityfs\n");
index 67e347192a557f3d97b0ecb4f56873aa0a20b37b..253ef6e9d445355c0f1d3379d319a8e052541032 100644 (file)
@@ -19,7 +19,7 @@
 
 #include "include/apparmor.h"
 #include "include/capability.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/policy.h"
 #include "include/audit.h"
 
index 6a54d2ffa84012fc7fd27aef18c7fa0410e050e3..590b7e8cd21c5450b24dfc84ea6b82c39b3c7959 100644 (file)
 #include <linux/syscalls.h>
 #include <linux/tracehook.h>
 #include <linux/personality.h>
+#include <linux/xattr.h>
 
 #include "include/audit.h"
 #include "include/apparmorfs.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/domain.h"
 #include "include/file.h"
 #include "include/ipc.h"
@@ -301,8 +302,71 @@ static int change_profile_perms(struct aa_profile *profile,
        return label_match(profile, target, stack, start, true, request, perms);
 }
 
+/**
+ * aa_xattrs_match - check whether a file matches the xattrs defined in profile
+ * @bprm: binprm struct for the process to validate
+ * @profile: profile to match against (NOT NULL)
+ * @state: state to start match in
+ *
+ * Returns: number of extended attributes that matched, or < 0 on error
+ */
+static int aa_xattrs_match(const struct linux_binprm *bprm,
+                          struct aa_profile *profile, unsigned int state)
+{
+       int i;
+       ssize_t size;
+       struct dentry *d;
+       char *value = NULL;
+       int value_size = 0, ret = profile->xattr_count;
+
+       if (!bprm || !profile->xattr_count)
+               return 0;
+
+       /* transition from exec match to xattr set */
+       state = aa_dfa_null_transition(profile->xmatch, state);
+
+       d = bprm->file->f_path.dentry;
+
+       for (i = 0; i < profile->xattr_count; i++) {
+               size = vfs_getxattr_alloc(d, profile->xattrs[i], &value,
+                                         value_size, GFP_KERNEL);
+               if (size >= 0) {
+                       u32 perm;
+
+                       /* Check the xattr value, not just presence */
+                       state = aa_dfa_match_len(profile->xmatch, state, value,
+                                                size);
+                       perm = dfa_user_allow(profile->xmatch, state);
+                       if (!(perm & MAY_EXEC)) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+               }
+               /* transition to next element */
+               state = aa_dfa_null_transition(profile->xmatch, state);
+               if (size < 0) {
+                       /*
+                        * No xattr match, so verify if transition to
+                        * next element was valid. IFF so the xattr
+                        * was optional.
+                        */
+                       if (!state) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       /* don't count missing optional xattr as matched */
+                       ret--;
+               }
+       }
+
+out:
+       kfree(value);
+       return ret;
+}
+
 /**
  * __attach_match_ - find an attachment match
+ * @bprm - binprm structure of transitioning task
  * @name - to match against  (NOT NULL)
  * @head - profile list to walk  (NOT NULL)
  * @info - info message if there was an error (NOT NULL)
@@ -316,40 +380,80 @@ static int change_profile_perms(struct aa_profile *profile,
  *
  * Returns: profile or NULL if no match found
  */
-static struct aa_profile *__attach_match(const char *name,
+static struct aa_profile *__attach_match(const struct linux_binprm *bprm,
+                                        const char *name,
                                         struct list_head *head,
                                         const char **info)
 {
-       int len = 0;
+       int candidate_len = 0, candidate_xattrs = 0;
        bool conflict = false;
        struct aa_profile *profile, *candidate = NULL;
 
+       AA_BUG(!name);
+       AA_BUG(!head);
+
        list_for_each_entry_rcu(profile, head, base.list) {
                if (profile->label.flags & FLAG_NULL &&
                    &profile->label == ns_unconfined(profile->ns))
                        continue;
 
+               /* Find the "best" matching profile. Profiles must
+                * match the path and extended attributes (if any)
+                * associated with the file. A more specific path
+                * match will be preferred over a less specific one,
+                * and a match with more matching extended attributes
+                * will be preferred over one with fewer. If the best
+                * match has both the same level of path specificity
+                * and the same number of matching extended attributes
+                * as another profile, signal a conflict and refuse to
+                * match.
+                */
                if (profile->xmatch) {
-                       if (profile->xmatch_len >= len) {
-                               unsigned int state;
-                               u32 perm;
-
-                               state = aa_dfa_match(profile->xmatch,
-                                                    DFA_START, name);
-                               perm = dfa_user_allow(profile->xmatch, state);
-                               /* any accepting state means a valid match. */
-                               if (perm & MAY_EXEC) {
-                                       if (profile->xmatch_len == len) {
+                       unsigned int state, count;
+                       u32 perm;
+
+                       state = aa_dfa_leftmatch(profile->xmatch, DFA_START,
+                                                name, &count);
+                       perm = dfa_user_allow(profile->xmatch, state);
+                       /* any accepting state means a valid match. */
+                       if (perm & MAY_EXEC) {
+                               int ret;
+
+                               if (count < candidate_len)
+                                       continue;
+
+                               ret = aa_xattrs_match(bprm, profile, state);
+                               /* Fail matching if the xattrs don't match */
+                               if (ret < 0)
+                                       continue;
+
+                               /*
+                                * TODO: allow for more flexible best match
+                                *
+                                * The new match isn't more specific
+                                * than the current best match
+                                */
+                               if (count == candidate_len &&
+                                   ret <= candidate_xattrs) {
+                                       /* Match is equivalent, so conflict */
+                                       if (ret == candidate_xattrs)
                                                conflict = true;
-                                               continue;
-                                       }
-                                       candidate = profile;
-                                       len = profile->xmatch_len;
-                                       conflict = false;
+                                       continue;
                                }
+
+                               /* Either the same length with more matching
+                                * xattrs, or a longer match
+                                */
+                               candidate = profile;
+                               candidate_len = profile->xmatch_len;
+                               candidate_xattrs = ret;
+                               conflict = false;
                        }
                } else if (!strcmp(profile->base.name, name))
-                       /* exact non-re match, no more searching required */
+                       /*
+                        * old exact non-re match, without conditionals such
+                        * as xattrs. no more searching required
+                        */
                        return profile;
        }
 
@@ -363,6 +467,7 @@ static struct aa_profile *__attach_match(const char *name,
 
 /**
  * find_attach - do attachment search for unconfined processes
+ * @bprm - binprm structure of transitioning task
  * @ns: the current namespace  (NOT NULL)
  * @list: list to search  (NOT NULL)
  * @name: the executable name to match against  (NOT NULL)
@@ -370,13 +475,14 @@ static struct aa_profile *__attach_match(const char *name,
  *
  * Returns: label or NULL if no match found
  */
-static struct aa_label *find_attach(struct aa_ns *ns, struct list_head *list,
+static struct aa_label *find_attach(const struct linux_binprm *bprm,
+                                   struct aa_ns *ns, struct list_head *list,
                                    const char *name, const char **info)
 {
        struct aa_profile *profile;
 
        rcu_read_lock();
-       profile = aa_get_profile(__attach_match(name, list, info));
+       profile = aa_get_profile(__attach_match(bprm, name, list, info));
        rcu_read_unlock();
 
        return profile ? &profile->label : NULL;
@@ -432,6 +538,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
 /**
  * x_to_label - get target label for a given xindex
  * @profile: current profile  (NOT NULL)
+ * @bprm: binprm structure of transitioning task
  * @name: name to lookup (NOT NULL)
  * @xindex: index into x transition table
  * @lookupname: returns: name used in lookup if one was specified (NOT NULL)
@@ -441,6 +548,7 @@ struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex,
  * Returns: refcounted label or NULL if not found available
  */
 static struct aa_label *x_to_label(struct aa_profile *profile,
+                                  const struct linux_binprm *bprm,
                                   const char *name, u32 xindex,
                                   const char **lookupname,
                                   const char **info)
@@ -468,11 +576,11 @@ static struct aa_label *x_to_label(struct aa_profile *profile,
        case AA_X_NAME:
                if (xindex & AA_X_CHILD)
                        /* released by caller */
-                       new = find_attach(ns, &profile->base.profiles,
+                       new = find_attach(bprm, ns, &profile->base.profiles,
                                          name, info);
                else
                        /* released by caller */
-                       new = find_attach(ns, &ns->base.profiles,
+                       new = find_attach(bprm, ns, &ns->base.profiles,
                                          name, info);
                *lookupname = name;
                break;
@@ -512,6 +620,8 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
                                           bool *secure_exec)
 {
        struct aa_label *new = NULL;
+       struct aa_profile *component;
+       struct label_it i;
        const char *info = NULL, *name = NULL, *target = NULL;
        unsigned int state = profile->file.start;
        struct aa_perms perms = {};
@@ -536,8 +646,8 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
        }
 
        if (profile_unconfined(profile)) {
-               new = find_attach(profile->ns, &profile->ns->base.profiles,
-                                 name, &info);
+               new = find_attach(bprm, profile->ns,
+                                 &profile->ns->base.profiles, name, &info);
                if (new) {
                        AA_DEBUG("unconfined attached to new label");
                        return new;
@@ -550,7 +660,8 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
        state = aa_str_perms(profile->file.dfa, state, name, cond, &perms);
        if (perms.allow & MAY_EXEC) {
                /* exec permission determine how to transition */
-               new = x_to_label(profile, name, perms.xindex, &target, &info);
+               new = x_to_label(profile, bprm, name, perms.xindex, &target,
+                                &info);
                if (new && new->proxy == profile->label.proxy && info) {
                        /* hack ix fallback - improve how this is detected */
                        goto audit;
@@ -559,6 +670,21 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
                        info = "profile transition not found";
                        /* remove MAY_EXEC to audit as failure */
                        perms.allow &= ~MAY_EXEC;
+               } else {
+                       /* verify that each component's xattr requirements are
+                        * met, and fail execution otherwise
+                        */
+                       label_for_each(i, new, component) {
+                               if (aa_xattrs_match(bprm, component, state) <
+                                   0) {
+                                       error = -EACCES;
+                                       info = "required xattrs not present";
+                                       perms.allow &= ~MAY_EXEC;
+                                       aa_put_label(new);
+                                       new = NULL;
+                                       goto audit;
+                               }
+                       }
                }
        } else if (COMPLAIN_MODE(profile)) {
                /* no exec permission - learning mode */
@@ -592,22 +718,6 @@ static struct aa_label *profile_transition(struct aa_profile *profile,
        if (!new)
                goto audit;
 
-       /* Policy has specified a domain transitions. if no_new_privs and
-        * confined and not transitioning to the current domain fail.
-        *
-        * NOTE: Domain transitions from unconfined and to stritly stacked
-        * subsets are allowed even when no_new_privs is set because this
-        * aways results in a further reduction of permissions.
-        */
-       if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
-           !profile_unconfined(profile) &&
-           !aa_label_is_subset(new, &profile->label)) {
-               error = -EPERM;
-               info = "no new privs";
-               nonewprivs = true;
-               perms.allow &= ~MAY_EXEC;
-               goto audit;
-       }
 
        if (!(perms.xindex & AA_X_UNSAFE)) {
                if (DEBUG_ON) {
@@ -684,21 +794,6 @@ static int profile_onexec(struct aa_profile *profile, struct aa_label *onexec,
                perms.allow &= ~AA_MAY_ONEXEC;
                goto audit;
        }
-       /* Policy has specified a domain transitions. if no_new_privs and
-        * confined and not transitioning to the current domain fail.
-        *
-        * NOTE: Domain transitions from unconfined and to stritly stacked
-        * subsets are allowed even when no_new_privs is set because this
-        * aways results in a further reduction of permissions.
-        */
-       if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
-           !profile_unconfined(profile) &&
-           !aa_label_is_subset(onexec, &profile->label)) {
-               error = -EPERM;
-               info = "no new privs";
-               perms.allow &= ~AA_MAY_ONEXEC;
-               goto audit;
-       }
 
        if (!(perms.xindex & AA_X_UNSAFE)) {
                if (DEBUG_ON) {
@@ -794,10 +889,22 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
        if (bprm->called_set_creds)
                return 0;
 
-       ctx = cred_ctx(bprm->cred);
+       ctx = task_ctx(current);
+       AA_BUG(!cred_label(bprm->cred));
        AA_BUG(!ctx);
 
-       label = aa_get_newest_label(ctx->label);
+       label = aa_get_newest_label(cred_label(bprm->cred));
+
+       /*
+        * Detect no new privs being set, and store the label it
+        * occurred under. Ideally this would happen when nnp
+        * is set but there isn't a good way to do that yet.
+        *
+        * Testing for unconfined must be done before the subset test
+        */
+       if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) && !unconfined(label) &&
+           !ctx->nnp)
+               ctx->nnp = aa_get_label(label);
 
        /* buffer freed below, name is pointer into buffer */
        get_buffers(buffer);
@@ -819,7 +926,20 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                goto done;
        }
 
-       /* TODO: Add ns level no_new_privs subset test */
+       /* Policy has specified a domain transitions. If no_new_privs and
+        * confined ensure the transition is to confinement that is subset
+        * of the confinement when the task entered no new privs.
+        *
+        * NOTE: Domain transitions from unconfined and to stacked
+        * subsets are allowed even when no_new_privs is set because this
+        * aways results in a further reduction of permissions.
+        */
+       if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) &&
+           !unconfined(label) && !aa_label_is_subset(new, ctx->nnp)) {
+               error = -EPERM;
+               info = "no new privs";
+               goto audit;
+       }
 
        if (bprm->unsafe & LSM_UNSAFE_SHARE) {
                /* FIXME: currently don't mediate shared state */
@@ -853,14 +973,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm)
                }
                bprm->per_clear |= PER_CLEAR_ON_SETID;
        }
-       aa_put_label(ctx->label);
-       /* transfer reference, released when ctx is freed */
-       ctx->label = new;
+       aa_put_label(cred_label(bprm->cred));
+       /* transfer reference, released when cred is freed */
+       cred_label(bprm->cred) = new;
 
 done:
-       /* clear out temporary/transitional state from the context */
-       aa_clear_task_ctx_trans(ctx);
-
        aa_put_label(label);
        put_buffers(buffer);
 
@@ -1049,30 +1166,28 @@ build:
 int aa_change_hat(const char *hats[], int count, u64 token, int flags)
 {
        const struct cred *cred;
-       struct aa_task_ctx *ctx;
+       struct aa_task_ctx *ctx = task_ctx(current);
        struct aa_label *label, *previous, *new = NULL, *target = NULL;
        struct aa_profile *profile;
        struct aa_perms perms = {};
        const char *info = NULL;
        int error = 0;
 
-       /*
-        * Fail explicitly requested domain transitions if no_new_privs.
-        * There is no exception for unconfined as change_hat is not
-        * available.
-        */
-       if (task_no_new_privs(current)) {
-               /* not an apparmor denial per se, so don't log it */
-               AA_DEBUG("no_new_privs - change_hat denied");
-               return -EPERM;
-       }
-
        /* released below */
        cred = get_current_cred();
-       ctx = cred_ctx(cred);
        label = aa_get_newest_cred_label(cred);
        previous = aa_get_newest_label(ctx->previous);
 
+       /*
+        * Detect no new privs being set, and store the label it
+        * occurred under. Ideally this would happen when nnp
+        * is set but there isn't a good way to do that yet.
+        *
+        * Testing for unconfined must be done before the subset test
+        */
+       if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp)
+               ctx->nnp = aa_get_label(label);
+
        if (unconfined(label)) {
                info = "unconfined can not change_hat";
                error = -EPERM;
@@ -1093,6 +1208,18 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
                if (error)
                        goto fail;
 
+               /*
+                * no new privs prevents domain transitions that would
+                * reduce restrictions.
+                */
+               if (task_no_new_privs(current) && !unconfined(label) &&
+                   !aa_label_is_subset(new, ctx->nnp)) {
+                       /* not an apparmor denial per se, so don't log it */
+                       AA_DEBUG("no_new_privs - change_hat denied");
+                       error = -EPERM;
+                       goto out;
+               }
+
                if (flags & AA_CHANGE_TEST)
                        goto out;
 
@@ -1102,6 +1229,18 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
                        /* kill task in case of brute force attacks */
                        goto kill;
        } else if (previous && !(flags & AA_CHANGE_TEST)) {
+               /*
+                * no new privs prevents domain transitions that would
+                * reduce restrictions.
+                */
+               if (task_no_new_privs(current) && !unconfined(label) &&
+                   !aa_label_is_subset(previous, ctx->nnp)) {
+                       /* not an apparmor denial per se, so don't log it */
+                       AA_DEBUG("no_new_privs - change_hat denied");
+                       error = -EPERM;
+                       goto out;
+               }
+
                /* Return to saved label.  Kill task if restore fails
                 * to avoid brute force attacks
                 */
@@ -1144,21 +1283,6 @@ static int change_profile_perms_wrapper(const char *op, const char *name,
        const char *info = NULL;
        int error = 0;
 
-       /*
-        * Fail explicitly requested domain transitions when no_new_privs
-        * and not unconfined OR the transition results in a stack on
-        * the current label.
-        * Stacking domain transitions and transitions from unconfined are
-        * allowed even when no_new_privs is set because this aways results
-        * in a reduction of permissions.
-        */
-       if (task_no_new_privs(current) && !stack &&
-           !profile_unconfined(profile) &&
-           !aa_label_is_subset(target, &profile->label)) {
-               info = "no new privs";
-               error = -EPERM;
-       }
-
        if (!error)
                error = change_profile_perms(profile, target, stack, request,
                                             profile->file.start, perms);
@@ -1192,10 +1316,23 @@ int aa_change_profile(const char *fqname, int flags)
        const char *info = NULL;
        const char *auditname = fqname;         /* retain leading & if stack */
        bool stack = flags & AA_CHANGE_STACK;
+       struct aa_task_ctx *ctx = task_ctx(current);
        int error = 0;
        char *op;
        u32 request;
 
+       label = aa_get_current_label();
+
+       /*
+        * Detect no new privs being set, and store the label it
+        * occurred under. Ideally this would happen when nnp
+        * is set but there isn't a good way to do that yet.
+        *
+        * Testing for unconfined must be done before the subset test
+        */
+       if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp)
+               ctx->nnp = aa_get_label(label);
+
        if (!fqname || !*fqname) {
                AA_DEBUG("no profile name");
                return -EINVAL;
@@ -1283,14 +1420,28 @@ check:
        if (flags & AA_CHANGE_TEST)
                goto out;
 
+       /* stacking is always a subset, so only check the nonstack case */
+       if (!stack) {
+               new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
+                                          aa_get_label(target),
+                                          aa_get_label(&profile->label));
+               /*
+                * no new privs prevents domain transitions that would
+                * reduce restrictions.
+                */
+               if (task_no_new_privs(current) && !unconfined(label) &&
+                   !aa_label_is_subset(new, ctx->nnp)) {
+                       /* not an apparmor denial per se, so don't log it */
+                       AA_DEBUG("no_new_privs - change_hat denied");
+                       error = -EPERM;
+                       goto out;
+               }
+       }
+
        if (!(flags & AA_CHANGE_ONEXEC)) {
                /* only transition profiles in the current ns */
                if (stack)
                        new = aa_label_merge(label, target, GFP_KERNEL);
-               else
-                       new = fn_label_build_in_ns(label, profile, GFP_KERNEL,
-                                       aa_get_label(target),
-                                       aa_get_label(&profile->label));
                if (IS_ERR_OR_NULL(new)) {
                        info = "failed to build target label";
                        error = PTR_ERR(new);
@@ -1299,9 +1450,15 @@ check:
                        goto audit;
                }
                error = aa_replace_current_label(new);
-       } else
+       } else {
+               if (new) {
+                       aa_put_label(new);
+                       new = NULL;
+               }
+
                /* full transition will be built in exec path */
                error = aa_set_current_onexec(target, stack);
+       }
 
 audit:
        error = fn_for_each_in_ns(label, profile,
index e79bf44396a36f60dde2e17fc68f2d0ac7d914b9..224b2fef93cadff32cd3dbd213ad3e2498d2e009 100644 (file)
 
 #include "include/apparmor.h"
 #include "include/audit.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/file.h"
 #include "include/match.h"
+#include "include/net.h"
 #include "include/path.h"
 #include "include/policy.h"
 #include "include/label.h"
@@ -560,6 +561,32 @@ static int __file_path_perm(const char *op, struct aa_label *label,
        return error;
 }
 
+static int __file_sock_perm(const char *op, struct aa_label *label,
+                           struct aa_label *flabel, struct file *file,
+                           u32 request, u32 denied)
+{
+       struct socket *sock = (struct socket *) file->private_data;
+       int error;
+
+       AA_BUG(!sock);
+
+       /* revalidation due to label out of date. No revocation at this time */
+       if (!denied && aa_label_is_subset(flabel, label))
+               return 0;
+
+       /* TODO: improve to skip profiles cached in flabel */
+       error = aa_sock_file_perm(label, op, request, sock);
+       if (denied) {
+               /* TODO: improve to skip profiles checked above */
+               /* check every profile in file label to is cached */
+               last_error(error, aa_sock_file_perm(flabel, op, request, sock));
+       }
+       if (!error)
+               update_file_ctx(file_ctx(file), label, request);
+
+       return error;
+}
+
 /**
  * aa_file_perm - do permission revalidation check & audit for @file
  * @op: operation being checked
@@ -604,6 +631,9 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
                error = __file_path_perm(op, label, flabel, file, request,
                                         denied);
 
+       else if (S_ISSOCK(file_inode(file)->i_mode))
+               error = __file_sock_perm(op, label, flabel, file, request,
+                                        denied);
 done:
        rcu_read_unlock();
 
index 829082c35faac7a932a568745068a2a3a979c124..73d63b58d875bc774f8bdcb25eeae7989ff2f6f5 100644 (file)
 #define AA_CLASS_UNKNOWN       1
 #define AA_CLASS_FILE          2
 #define AA_CLASS_CAP           3
-#define AA_CLASS_NET           4
+#define AA_CLASS_DEPRECATED    4
 #define AA_CLASS_RLIMITS       5
 #define AA_CLASS_DOMAIN                6
 #define AA_CLASS_MOUNT         7
 #define AA_CLASS_PTRACE                9
 #define AA_CLASS_SIGNAL                10
+#define AA_CLASS_NET           14
 #define AA_CLASS_LABEL         16
 
 #define AA_CLASS_LAST          AA_CLASS_LABEL
index 4ac095118717022cfb3ea564b5ec37deaad91a90..9c9be9c98c153e52c763dcbf2f4773e5ccfa7eba 100644 (file)
@@ -126,7 +126,20 @@ struct apparmor_audit_data {
                                        const char *target;
                                        kuid_t ouid;
                                } fs;
-                               int signal;
+                               struct {
+                                       int rlim;
+                                       unsigned long max;
+                               } rlim;
+                               struct {
+                                       int signal;
+                                       int unmappedsig;
+                               };
+                               struct {
+                                       int type, protocol;
+                                       struct sock *peer_sk;
+                                       void *addr;
+                                       int addrlen;
+                               } net;
                        };
                };
                struct {
@@ -134,10 +147,6 @@ struct apparmor_audit_data {
                        const char *ns;
                        long pos;
                } iface;
-               struct {
-                       int rlim;
-                       unsigned long max;
-               } rlim;
                struct {
                        const char *src_name;
                        const char *type;
similarity index 70%
rename from security/apparmor/include/context.h
rename to security/apparmor/include/cred.h
index 6ae07e9aaa172dac7cd8820af0b9817afdf73f8a..e287b7d0d4bebcf2cc83d9add032fdb1feed54c0 100644 (file)
 
 #include "label.h"
 #include "policy_ns.h"
+#include "task.h"
 
-#define cred_ctx(X) ((X)->security)
-#define current_ctx() cred_ctx(current_cred())
-
-/**
- * struct aa_task_ctx - primary label for confined tasks
- * @label: the current label   (NOT NULL)
- * @exec: label to transition to on next exec  (MAYBE NULL)
- * @previous: label the task may return to     (MAYBE NULL)
- * @token: magic value the task must know for returning to @previous
- *
- * Contains the task's current label (which could change due to
- * change_hat).  Plus the hat_magic needed during change_hat.
- *
- * TODO: make so a task can be confined by a stack of contexts
- */
-struct aa_task_ctx {
-       struct aa_label *label;
-       struct aa_label *onexec;
-       struct aa_label *previous;
-       u64 token;
-};
-
-struct aa_task_ctx *aa_alloc_task_context(gfp_t flags);
-void aa_free_task_context(struct aa_task_ctx *ctx);
-void aa_dup_task_context(struct aa_task_ctx *new,
-                        const struct aa_task_ctx *old);
-int aa_replace_current_label(struct aa_label *label);
-int aa_set_current_onexec(struct aa_label *label, bool stack);
-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);
+#define cred_label(X) ((X)->security)
 
 
 /**
@@ -65,10 +36,10 @@ struct aa_label *aa_get_task_label(struct task_struct *task);
  */
 static inline struct aa_label *aa_cred_raw_label(const struct cred *cred)
 {
-       struct aa_task_ctx *ctx = cred_ctx(cred);
+       struct aa_label *label = cred_label(cred);
 
-       AA_BUG(!ctx || !ctx->label);
-       return ctx->label;
+       AA_BUG(!label);
+       return label;
 }
 
 /**
@@ -95,17 +66,6 @@ static inline struct aa_label *__aa_task_raw_label(struct task_struct *task)
        return aa_cred_raw_label(__task_cred(task));
 }
 
-/**
- * __aa_task_is_confined - determine if @task has any confinement
- * @task: task to check confinement of  (NOT NULL)
- *
- * If @task != current needs to be called in RCU safe critical section
- */
-static inline bool __aa_task_is_confined(struct task_struct *task)
-{
-       return !unconfined(__aa_task_raw_label(task));
-}
-
 /**
  * aa_current_raw_label - find the current tasks confining label
  *
@@ -213,17 +173,4 @@ static inline struct aa_ns *aa_get_current_ns(void)
        return ns;
 }
 
-/**
- * aa_clear_task_ctx_trans - clear transition tracking info from the ctx
- * @ctx: task context to clear (NOT NULL)
- */
-static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
-{
-       aa_put_label(ctx->previous);
-       aa_put_label(ctx->onexec);
-       ctx->previous = NULL;
-       ctx->onexec = NULL;
-       ctx->token = 0;
-}
-
 #endif /* __AA_CONTEXT_H */
index af22dcbbcb8aa165d16d1769aba7e92eb5965ada..d871e7ff095275e8a23685449945036d016682eb 100644 (file)
@@ -327,9 +327,37 @@ void aa_label_audit(struct audit_buffer *ab, struct aa_label *label, gfp_t gfp);
 void aa_label_seq_print(struct seq_file *f, struct aa_label *label, gfp_t gfp);
 void aa_label_printk(struct aa_label *label, gfp_t gfp);
 
+struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str,
+                                    size_t n, gfp_t gfp, bool create,
+                                    bool force_stack);
 struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
                                gfp_t gfp, bool create, bool force_stack);
 
+static inline const char *aa_label_strn_split(const char *str, int n)
+{
+       const char *pos;
+       unsigned int state;
+
+       state = aa_dfa_matchn_until(stacksplitdfa, DFA_START, str, n, &pos);
+       if (!ACCEPT_TABLE(stacksplitdfa)[state])
+               return NULL;
+
+       return pos - 3;
+}
+
+static inline const char *aa_label_str_split(const char *str)
+{
+       const char *pos;
+       unsigned int state;
+
+       state = aa_dfa_match_until(stacksplitdfa, DFA_START, str, &pos);
+       if (!ACCEPT_TABLE(stacksplitdfa)[state])
+               return NULL;
+
+       return pos - 3;
+}
+
+
 
 struct aa_perms;
 int aa_label_match(struct aa_profile *profile, struct aa_label *label,
index add4c672655844a33d9cadc18893f67d605d751f..958d2b52a7b74479014e47b374d4888a8461280f 100644 (file)
@@ -40,6 +40,7 @@
  */
 
 #define YYTH_MAGIC     0x1B5E783D
+#define YYTH_FLAG_DIFF_ENCODE  1
 
 struct table_set_header {
        u32 th_magic;           /* YYTH_MAGIC */
@@ -101,6 +102,7 @@ struct aa_dfa {
 };
 
 extern struct aa_dfa *nulldfa;
+extern struct aa_dfa *stacksplitdfa;
 
 #define byte_to_byte(X) (X)
 
@@ -129,9 +131,32 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
                          const char *str);
 unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
                         const char c);
+unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start,
+                               const char *str, const char **retpos);
+unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start,
+                                const char *str, int n, const char **retpos);
 
 void aa_dfa_free_kref(struct kref *kref);
 
+#define WB_HISTORY_SIZE 8
+struct match_workbuf {
+       unsigned int count;
+       unsigned int pos;
+       unsigned int len;
+       unsigned int size;      /* power of 2, same as history size */
+       unsigned int history[WB_HISTORY_SIZE];
+};
+#define DEFINE_MATCH_WB(N)             \
+struct match_workbuf N = {             \
+       .count = 0,                     \
+       .pos = 0,                       \
+       .len = 0,                       \
+       .size = WB_HISTORY_SIZE,                        \
+}
+
+unsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start,
+                             const char *str, unsigned int *count);
+
 /**
  * aa_get_dfa - increment refcount on dfa @p
  * @dfa: dfa  (MAYBE NULL)
@@ -159,4 +184,7 @@ static inline void aa_put_dfa(struct aa_dfa *dfa)
                kref_put(&dfa->count, aa_dfa_free_kref);
 }
 
+#define MATCH_FLAG_DIFF_ENCODE 0x80000000
+#define MARK_DIFF_ENCODE 0x40000000
+
 #endif /* __AA_MATCH_H */
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
new file mode 100644 (file)
index 0000000..ec7228e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation definitions.
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2017 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_NET_H
+#define __AA_NET_H
+
+#include <net/sock.h>
+#include <linux/path.h>
+
+#include "apparmorfs.h"
+#include "label.h"
+#include "perms.h"
+#include "policy.h"
+
+#define AA_MAY_SEND            AA_MAY_WRITE
+#define AA_MAY_RECEIVE         AA_MAY_READ
+
+#define AA_MAY_SHUTDOWN                AA_MAY_DELETE
+
+#define AA_MAY_CONNECT         AA_MAY_OPEN
+#define AA_MAY_ACCEPT          0x00100000
+
+#define AA_MAY_BIND            0x00200000
+#define AA_MAY_LISTEN          0x00400000
+
+#define AA_MAY_SETOPT          0x01000000
+#define AA_MAY_GETOPT          0x02000000
+
+#define NET_PERMS_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE |    \
+                       AA_MAY_SHUTDOWN | AA_MAY_BIND | AA_MAY_LISTEN |   \
+                       AA_MAY_CONNECT | AA_MAY_ACCEPT | AA_MAY_SETATTR | \
+                       AA_MAY_GETATTR | AA_MAY_SETOPT | AA_MAY_GETOPT)
+
+#define NET_FS_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE |   \
+                     AA_MAY_SHUTDOWN | AA_MAY_CONNECT | AA_MAY_RENAME |\
+                     AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_CHMOD |  \
+                     AA_MAY_CHOWN | AA_MAY_CHGRP | AA_MAY_LOCK |       \
+                     AA_MAY_MPROT)
+
+#define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \
+                      AA_MAY_ACCEPT)
+struct aa_sk_ctx {
+       struct aa_label *label;
+       struct aa_label *peer;
+};
+
+#define SK_CTX(X) ((X)->sk_security)
+#define SOCK_ctx(X) SOCK_INODE(X)->i_security
+#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P)                                  \
+       struct lsm_network_audit NAME ## _net = { .sk = (SK),             \
+                                                 .family = (F)};         \
+       DEFINE_AUDIT_DATA(NAME,                                           \
+                         ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \
+                                                    LSM_AUDIT_DATA_NONE, \
+                         OP);                                            \
+       NAME.u.net = &(NAME ## _net);                                     \
+       aad(&NAME)->net.type = (T);                                       \
+       aad(&NAME)->net.protocol = (P)
+
+#define DEFINE_AUDIT_SK(NAME, OP, SK)                                  \
+       DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type,  \
+                        (SK)->sk_protocol)
+
+
+#define af_select(FAMILY, FN, DEF_FN)          \
+({                                             \
+       int __e;                                \
+       switch ((FAMILY)) {                     \
+       default:                                \
+               __e = DEF_FN;                   \
+       }                                       \
+       __e;                                    \
+})
+
+extern struct aa_sfs_entry aa_sfs_entry_network[];
+
+void audit_net_cb(struct audit_buffer *ab, void *va);
+int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
+                      u32 request, u16 family, int type);
+int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
+              int type, int protocol);
+static inline int aa_profile_af_sk_perm(struct aa_profile *profile,
+                                       struct common_audit_data *sa,
+                                       u32 request,
+                                       struct sock *sk)
+{
+       return aa_profile_af_perm(profile, sa, request, sk->sk_family,
+                                 sk->sk_type);
+}
+int aa_sk_perm(const char *op, u32 request, struct sock *sk);
+
+int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
+                     struct socket *sock);
+
+#endif /* __AA_NET_H */
index d7b7e711516010806d194ed39b2a24e1a9f9fd09..38aa6247d00f9ce51320bbaf3c50016cbe81ea3b 100644 (file)
@@ -138,9 +138,10 @@ extern struct aa_perms allperms;
 
 
 void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask);
-void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask);
+void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
+                        u32 mask);
 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
-                       u32 chrsmask, const char **names, u32 namesmask);
+                       u32 chrsmask, const char * const *names, u32 namesmask);
 void aa_apply_modes_to_perms(struct aa_profile *profile,
                             struct aa_perms *perms);
 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
index 17fe41a9cac35e6d88f3ae738bf2b068de736ec1..ab64c6b5db5aca7aaae1b16a800d48c7499bc498 100644 (file)
@@ -30,6 +30,7 @@
 #include "file.h"
 #include "lib.h"
 #include "label.h"
+#include "net.h"
 #include "perms.h"
 #include "resource.h"
 
@@ -148,6 +149,10 @@ struct aa_profile {
        struct aa_policydb policy;
        struct aa_file_rules file;
        struct aa_caps caps;
+
+       int xattr_count;
+       char **xattrs;
+
        struct aa_rlimit rlimits;
 
        struct aa_loaddata *rawdata;
@@ -209,15 +214,15 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p)
        return labels_profile(aa_get_newest_label(&p->label));
 }
 
-#define PROFILE_MEDIATES(P, T)  ((P)->policy.start[(T)])
-/* safe version of POLICY_MEDIATES for full range input */
-static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile,
-                                                unsigned char class)
-{
-       if (profile->policy.dfa)
-               return aa_dfa_match_len(profile->policy.dfa,
-                                       profile->policy.start[0], &class, 1);
-       return 0;
+#define PROFILE_MEDIATES(P, T)  ((P)->policy.start[(unsigned char) (T)])
+static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile,
+                                              u16 AF) {
+       unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
+       __be16 be_af = cpu_to_be16(AF);
+
+       if (!state)
+               return 0;
+       return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2);
 }
 
 /**
index be6cd69ac3194aec30aded866ca4f9152982cd4e..8db4ab759e80f37837e170744f5788125ef5f657 100644 (file)
@@ -70,7 +70,7 @@ struct aa_loaddata {
        int abi;
        unsigned char *hash;
 
-       char data[];
+       char *data;
 };
 
 int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns);
index 92e62fe952926b5abdc3348884d8e2fc6b966f1d..cbf7a997ed8412797282be480a15339ee431d997 100644 (file)
@@ -2,6 +2,9 @@
 
 #define SIGUNKNOWN 0
 #define MAXMAPPED_SIG 35
+#define MAXMAPPED_SIGNAME (MAXMAPPED_SIG + 1)
+#define SIGRT_BASE 128
+
 /* provide a mapping of arch signal to internal signal # for mediation
  * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO
  * map to the same entry those that may/or may not get a separate entry
@@ -56,7 +59,7 @@ static const int sig_map[MAXMAPPED_SIG] = {
 };
 
 /* this table is ordered post sig_map[sig] mapping */
-static const char *const sig_names[MAXMAPPED_SIG + 1] = {
+static const char *const sig_names[MAXMAPPED_SIGNAME] = {
        "unknown",
        "hup",
        "int",
diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h
new file mode 100644 (file)
index 0000000..55edaa1
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor task related definitions and mediation
+ *
+ * Copyright 2017 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#ifndef __AA_TASK_H
+#define __AA_TASK_H
+
+#define task_ctx(X) ((X)->security)
+
+/*
+ * struct aa_task_ctx - information for current task label change
+ * @nnp: snapshot of label at time of no_new_privs
+ * @onexec: profile to transition to on next exec  (MAY BE NULL)
+ * @previous: profile the task may return to     (MAY BE NULL)
+ * @token: magic value the task must know for returning to @previous_profile
+ */
+struct aa_task_ctx {
+       struct aa_label *nnp;
+       struct aa_label *onexec;
+       struct aa_label *previous;
+       u64 token;
+};
+
+int aa_replace_current_label(struct aa_label *label);
+int aa_set_current_onexec(struct aa_label *label, bool stack);
+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)
+ */
+static inline void aa_free_task_ctx(struct aa_task_ctx *ctx)
+{
+       if (ctx) {
+               aa_put_label(ctx->nnp);
+               aa_put_label(ctx->previous);
+               aa_put_label(ctx->onexec);
+
+               kzfree(ctx);
+       }
+}
+
+/**
+ * aa_dup_task_ctx - duplicate a task context, incrementing reference counts
+ * @new: a blank task context      (NOT NULL)
+ * @old: the task context to copy  (NOT NULL)
+ */
+static inline void aa_dup_task_ctx(struct aa_task_ctx *new,
+                                  const struct aa_task_ctx *old)
+{
+       *new = *old;
+       aa_get_label(new->nnp);
+       aa_get_label(new->previous);
+       aa_get_label(new->onexec);
+}
+
+/**
+ * aa_clear_task_ctx_trans - clear transition tracking info from the ctx
+ * @ctx: task context to clear (NOT NULL)
+ */
+static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx)
+{
+       AA_BUG(!ctx);
+
+       aa_put_label(ctx->previous);
+       aa_put_label(ctx->onexec);
+       ctx->previous = NULL;
+       ctx->onexec = NULL;
+       ctx->token = 0;
+}
+
+#endif /* __AA_TASK_H */
index b40678f3c1d5a4d62eeb1255f26e2a73aabd6767..527ea1557120ece44aa0c04d901bfa3e8d9b9422 100644 (file)
@@ -17,7 +17,7 @@
 
 #include "include/audit.h"
 #include "include/capability.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/policy.h"
 #include "include/ipc.h"
 #include "include/sig_names.h"
@@ -138,7 +138,7 @@ static inline int map_signal_num(int sig)
        if (sig > SIGRTMAX)
                return SIGUNKNOWN;
        else if (sig >= SIGRTMIN)
-               return sig - SIGRTMIN + 128;    /* rt sigs mapped to 128 */
+               return sig - SIGRTMIN + SIGRT_BASE;
        else if (sig < MAXMAPPED_SIG)
                return sig_map[sig];
        return SIGUNKNOWN;
@@ -174,60 +174,48 @@ static void audit_signal_cb(struct audit_buffer *ab, void *va)
                        audit_signal_mask(ab, aad(sa)->denied);
                }
        }
-       if (aad(sa)->signal < MAXMAPPED_SIG)
+       if (aad(sa)->signal == SIGUNKNOWN)
+               audit_log_format(ab, "signal=unknown(%d)",
+                                aad(sa)->unmappedsig);
+       else if (aad(sa)->signal < MAXMAPPED_SIGNAME)
                audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]);
        else
                audit_log_format(ab, " signal=rtmin+%d",
-                                aad(sa)->signal - 128);
+                                aad(sa)->signal - SIGRT_BASE);
        audit_log_format(ab, " peer=");
        aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
                        FLAGS_NONE, GFP_ATOMIC);
 }
 
-/* TODO: update to handle compound name&name2, conditionals */
-static void profile_match_signal(struct aa_profile *profile, const char *label,
-                                int signal, struct aa_perms *perms)
-{
-       unsigned int state;
-
-       /* TODO: secondary cache check <profile, profile, perm> */
-       state = aa_dfa_next(profile->policy.dfa,
-                           profile->policy.start[AA_CLASS_SIGNAL],
-                           signal);
-       state = aa_dfa_match(profile->policy.dfa, state, label);
-       aa_compute_perms(profile->policy.dfa, state, perms);
-}
-
 static int profile_signal_perm(struct aa_profile *profile,
-                              struct aa_profile *peer, u32 request,
+                              struct aa_label *peer, u32 request,
                               struct common_audit_data *sa)
 {
        struct aa_perms perms;
+       unsigned int state;
 
        if (profile_unconfined(profile) ||
            !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL))
                return 0;
 
-       aad(sa)->peer = &peer->label;
-       profile_match_signal(profile, peer->base.hname, aad(sa)->signal,
-                            &perms);
+       aad(sa)->peer = peer;
+       /* TODO: secondary cache check <profile, profile, perm> */
+       state = aa_dfa_next(profile->policy.dfa,
+                           profile->policy.start[AA_CLASS_SIGNAL],
+                           aad(sa)->signal);
+       aa_label_match(profile, peer, state, false, request, &perms);
        aa_apply_modes_to_perms(profile, &perms);
        return aa_check_perms(profile, &perms, request, sa, audit_signal_cb);
 }
 
-static int aa_signal_cross_perm(struct aa_profile *sender,
-                               struct aa_profile *target,
-                               struct common_audit_data *sa)
-{
-       return xcheck(profile_signal_perm(sender, target, MAY_WRITE, sa),
-                     profile_signal_perm(target, sender, MAY_READ, sa));
-}
-
 int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig)
 {
+       struct aa_profile *profile;
        DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL);
 
        aad(&sa)->signal = map_signal_num(sig);
-       return xcheck_labels_profiles(sender, target, aa_signal_cross_perm,
-                                     &sa);
+       aad(&sa)->unmappedsig = sig;
+       return xcheck_labels(sender, target, profile,
+                       profile_signal_perm(profile, target, MAY_WRITE, &sa),
+                       profile_signal_perm(profile, sender, MAY_READ, &sa));
 }
index 324fe5c60f8781c952138d0a764a5c2223f6353b..523250e348378d1ef7ddcd80f7e6e64285ef787b 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/sort.h>
 
 #include "include/apparmor.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/label.h"
 #include "include/policy.h"
 #include "include/secid.h"
@@ -1808,14 +1808,17 @@ void aa_label_printk(struct aa_label *label, gfp_t gfp)
        aa_put_ns(ns);
 }
 
-static int label_count_str_entries(const char *str)
+static int label_count_strn_entries(const char *str, size_t n)
 {
+       const char *end = str + n;
        const char *split;
        int count = 1;
 
        AA_BUG(!str);
 
-       for (split = strstr(str, "//&"); split; split = strstr(str, "//&")) {
+       for (split = aa_label_strn_split(str, end - str);
+            split;
+            split = aa_label_strn_split(str, end - str)) {
                count++;
                str = split + 3;
        }
@@ -1843,9 +1846,10 @@ static struct aa_profile *fqlookupn_profile(struct aa_label *base,
 }
 
 /**
- * aa_label_parse - parse, validate and convert a text string to a label
+ * aa_label_strn_parse - parse, validate and convert a text string to a label
  * @base: base label to use for lookups (NOT NULL)
  * @str: null terminated text string (NOT NULL)
+ * @n: length of str to parse, will stop at \0 if encountered before n
  * @gfp: allocation type
  * @create: true if should create compound labels if they don't exist
  * @force_stack: true if should stack even if no leading &
@@ -1853,19 +1857,24 @@ static struct aa_profile *fqlookupn_profile(struct aa_label *base,
  * Returns: the matching refcounted label if present
  *     else ERRPTR
  */
-struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
-                               gfp_t gfp, bool create, bool force_stack)
+struct aa_label *aa_label_strn_parse(struct aa_label *base, const char *str,
+                                    size_t n, gfp_t gfp, bool create,
+                                    bool force_stack)
 {
        DEFINE_VEC(profile, vec);
        struct aa_label *label, *currbase = base;
        int i, len, stack = 0, error;
-       char *split;
+       const char *end = str + n;
+       const char *split;
 
        AA_BUG(!base);
        AA_BUG(!str);
 
-       str = skip_spaces(str);
-       len = label_count_str_entries(str);
+       str = skipn_spaces(str, n);
+       if (str == NULL || (*str == '=' && base != &root_ns->unconfined->label))
+               return ERR_PTR(-EINVAL);
+
+       len = label_count_strn_entries(str, end - str);
        if (*str == '&' || force_stack) {
                /* stack on top of base */
                stack = base->size;
@@ -1873,8 +1882,6 @@ struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
                if (*str == '&')
                        str++;
        }
-       if (*str == '=')
-               base = &root_ns->unconfined->label;
 
        error = vec_setup(profile, vec, len, gfp);
        if (error)
@@ -1883,7 +1890,8 @@ struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
        for (i = 0; i < stack; i++)
                vec[i] = aa_get_profile(base->vec[i]);
 
-       for (split = strstr(str, "//&"), i = stack; split && i < len; i++) {
+       for (split = aa_label_strn_split(str, end - str), i = stack;
+            split && i < len; i++) {
                vec[i] = fqlookupn_profile(base, currbase, str, split - str);
                if (!vec[i])
                        goto fail;
@@ -1894,11 +1902,11 @@ struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
                if (vec[i]->ns != labels_ns(currbase))
                        currbase = &vec[i]->label;
                str = split + 3;
-               split = strstr(str, "//&");
+               split = aa_label_strn_split(str, end - str);
        }
        /* last element doesn't have a split */
        if (i < len) {
-               vec[i] = fqlookupn_profile(base, currbase, str, strlen(str));
+               vec[i] = fqlookupn_profile(base, currbase, str, end - str);
                if (!vec[i])
                        goto fail;
        }
@@ -1930,6 +1938,12 @@ fail:
        goto out;
 }
 
+struct aa_label *aa_label_parse(struct aa_label *base, const char *str,
+                               gfp_t gfp, bool create, bool force_stack)
+{
+       return aa_label_strn_parse(base, str, strlen(str), gfp, create,
+                                  force_stack);
+}
 
 /**
  * aa_labelset_destroy - remove all labels from the label set
index 4d5e98e49d5e06a9066f618adabe2767da45ff3c..068a9f471f774d57543c6a93d978056070ac9cfb 100644 (file)
@@ -211,7 +211,8 @@ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
        *str = '\0';
 }
 
-void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
+void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
+                        u32 mask)
 {
        const char *fmt = "%s";
        unsigned int i, perm = 1;
@@ -229,7 +230,7 @@ void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
 }
 
 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
-                       u32 chrsmask, const char **names, u32 namesmask)
+                       u32 chrsmask, const char * const *names, u32 namesmask)
 {
        char str[33];
 
index 528f59b580a8dffb2ab059c3f1bee1830a66ac73..ce2b89e9ad94eb9b5b657a8ccce703894c021e19 100644 (file)
 #include "include/apparmorfs.h"
 #include "include/audit.h"
 #include "include/capability.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/file.h"
 #include "include/ipc.h"
+#include "include/net.h"
 #include "include/path.h"
 #include "include/label.h"
 #include "include/policy.h"
@@ -50,12 +51,12 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers);
  */
 
 /*
- * free the associated aa_task_ctx and put its labels
+ * put the associated labels
  */
 static void apparmor_cred_free(struct cred *cred)
 {
-       aa_free_task_context(cred_ctx(cred));
-       cred_ctx(cred) = NULL;
+       aa_put_label(cred_label(cred));
+       cred_label(cred) = NULL;
 }
 
 /*
@@ -63,30 +64,17 @@ static void apparmor_cred_free(struct cred *cred)
  */
 static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
 {
-       /* freed by apparmor_cred_free */
-       struct aa_task_ctx *ctx = aa_alloc_task_context(gfp);
-
-       if (!ctx)
-               return -ENOMEM;
-
-       cred_ctx(cred) = ctx;
+       cred_label(cred) = NULL;
        return 0;
 }
 
 /*
- * prepare new aa_task_ctx for modification by prepare_cred block
+ * prepare new cred label for modification by prepare_cred block
  */
 static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
                                 gfp_t gfp)
 {
-       /* freed by apparmor_cred_free */
-       struct aa_task_ctx *ctx = aa_alloc_task_context(gfp);
-
-       if (!ctx)
-               return -ENOMEM;
-
-       aa_dup_task_context(ctx, cred_ctx(old));
-       cred_ctx(new) = ctx;
+       cred_label(new) = aa_get_newest_label(cred_label(old));
        return 0;
 }
 
@@ -95,10 +83,28 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
  */
 static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
 {
-       const struct aa_task_ctx *old_ctx = cred_ctx(old);
-       struct aa_task_ctx *new_ctx = cred_ctx(new);
+       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;
+
+       aa_dup_task_ctx(new, task_ctx(current));
+       task_ctx(task) = new;
 
-       aa_dup_task_context(new_ctx, old_ctx);
+       return 0;
 }
 
 static int apparmor_ptrace_access_check(struct task_struct *child,
@@ -576,11 +582,11 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
        int error = -ENOENT;
        /* released below */
        const struct cred *cred = get_task_cred(task);
-       struct aa_task_ctx *ctx = cred_ctx(cred);
+       struct aa_task_ctx *ctx = task_ctx(current);
        struct aa_label *label = NULL;
 
        if (strcmp(name, "current") == 0)
-               label = aa_get_newest_label(ctx->label);
+               label = aa_get_newest_label(cred_label(cred));
        else if (strcmp(name, "prev") == 0  && ctx->previous)
                label = aa_get_newest_label(ctx->previous);
        else if (strcmp(name, "exec") == 0 && ctx->onexec)
@@ -677,11 +683,11 @@ fail:
 static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
 {
        struct aa_label *label = aa_current_raw_label();
-       struct aa_task_ctx *new_ctx = cred_ctx(bprm->cred);
+       struct aa_label *new_label = cred_label(bprm->cred);
 
        /* bail out if unconfined or not changing profile */
-       if ((new_ctx->label->proxy == label->proxy) ||
-           (unconfined(new_ctx->label)))
+       if ((new_label->proxy == label->proxy) ||
+           (unconfined(new_label)))
                return;
 
        aa_inherit_files(bprm->cred, current->files);
@@ -689,7 +695,7 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
        current->pdeath_signal = 0;
 
        /* reset soft limits and set hard limits for the new label */
-       __aa_transition_rlimits(label, new_ctx->label);
+       __aa_transition_rlimits(label, new_label);
 }
 
 /**
@@ -698,7 +704,9 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
  */
 static void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
 {
-       /* TODO: cleanup signals - ipc mediation */
+       /* clear out temporary/transitional state from the context */
+       aa_clear_task_ctx_trans(task_ctx(current));
+
        return;
 }
 
@@ -742,6 +750,373 @@ static int apparmor_task_kill(struct task_struct *target, struct siginfo *info,
        return error;
 }
 
+/**
+ * apparmor_sk_alloc_security - allocate and attach the sk_security field
+ */
+static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
+{
+       struct aa_sk_ctx *ctx;
+
+       ctx = kzalloc(sizeof(*ctx), flags);
+       if (!ctx)
+               return -ENOMEM;
+
+       SK_CTX(sk) = ctx;
+
+       return 0;
+}
+
+/**
+ * apparmor_sk_free_security - free the sk_security field
+ */
+static void apparmor_sk_free_security(struct sock *sk)
+{
+       struct aa_sk_ctx *ctx = SK_CTX(sk);
+
+       SK_CTX(sk) = NULL;
+       aa_put_label(ctx->label);
+       aa_put_label(ctx->peer);
+       kfree(ctx);
+}
+
+/**
+ * apparmor_clone_security - clone the sk_security field
+ */
+static void apparmor_sk_clone_security(const struct sock *sk,
+                                      struct sock *newsk)
+{
+       struct aa_sk_ctx *ctx = SK_CTX(sk);
+       struct aa_sk_ctx *new = SK_CTX(newsk);
+
+       new->label = aa_get_label(ctx->label);
+       new->peer = aa_get_label(ctx->peer);
+}
+
+/**
+ * apparmor_socket_create - check perms before creating a new socket
+ */
+static int apparmor_socket_create(int family, int type, int protocol, int kern)
+{
+       struct aa_label *label;
+       int error = 0;
+
+       AA_BUG(in_interrupt());
+
+       label = begin_current_label_crit_section();
+       if (!(kern || unconfined(label)))
+               error = af_select(family,
+                                 create_perm(label, family, type, protocol),
+                                 aa_af_perm(label, OP_CREATE, AA_MAY_CREATE,
+                                            family, type, protocol));
+       end_current_label_crit_section(label);
+
+       return error;
+}
+
+/**
+ * apparmor_socket_post_create - setup the per-socket security struct
+ *
+ * Note:
+ * -   kernel sockets currently labeled unconfined but we may want to
+ *     move to a special kernel label
+ * -   socket may not have sk here if created with sock_create_lite or
+ *     sock_alloc. These should be accept cases which will be handled in
+ *     sock_graft.
+ */
+static int apparmor_socket_post_create(struct socket *sock, int family,
+                                      int type, int protocol, int kern)
+{
+       struct aa_label *label;
+
+       if (kern) {
+               struct aa_ns *ns = aa_get_current_ns();
+
+               label = aa_get_label(ns_unconfined(ns));
+               aa_put_ns(ns);
+       } else
+               label = aa_get_current_label();
+
+       if (sock->sk) {
+               struct aa_sk_ctx *ctx = SK_CTX(sock->sk);
+
+               aa_put_label(ctx->label);
+               ctx->label = aa_get_label(label);
+       }
+       aa_put_label(label);
+
+       return 0;
+}
+
+/**
+ * apparmor_socket_bind - check perms before bind addr to socket
+ */
+static int apparmor_socket_bind(struct socket *sock,
+                               struct sockaddr *address, int addrlen)
+{
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+       AA_BUG(!address);
+       AA_BUG(in_interrupt());
+
+       return af_select(sock->sk->sk_family,
+                        bind_perm(sock, address, addrlen),
+                        aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk));
+}
+
+/**
+ * apparmor_socket_connect - check perms before connecting @sock to @address
+ */
+static int apparmor_socket_connect(struct socket *sock,
+                                  struct sockaddr *address, int addrlen)
+{
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+       AA_BUG(!address);
+       AA_BUG(in_interrupt());
+
+       return af_select(sock->sk->sk_family,
+                        connect_perm(sock, address, addrlen),
+                        aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk));
+}
+
+/**
+ * apparmor_socket_list - check perms before allowing listen
+ */
+static int apparmor_socket_listen(struct socket *sock, int backlog)
+{
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+       AA_BUG(in_interrupt());
+
+       return af_select(sock->sk->sk_family,
+                        listen_perm(sock, backlog),
+                        aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk));
+}
+
+/**
+ * apparmor_socket_accept - check perms before accepting a new connection.
+ *
+ * Note: while @newsock is created and has some information, the accept
+ *       has not been done.
+ */
+static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
+{
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+       AA_BUG(!newsock);
+       AA_BUG(in_interrupt());
+
+       return af_select(sock->sk->sk_family,
+                        accept_perm(sock, newsock),
+                        aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk));
+}
+
+static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock,
+                           struct msghdr *msg, int size)
+{
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+       AA_BUG(!msg);
+       AA_BUG(in_interrupt());
+
+       return af_select(sock->sk->sk_family,
+                        msg_perm(op, request, sock, msg, size),
+                        aa_sk_perm(op, request, sock->sk));
+}
+
+/**
+ * apparmor_socket_sendmsg - check perms before sending msg to another socket
+ */
+static int apparmor_socket_sendmsg(struct socket *sock,
+                                  struct msghdr *msg, int size)
+{
+       return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size);
+}
+
+/**
+ * apparmor_socket_recvmsg - check perms before receiving a message
+ */
+static int apparmor_socket_recvmsg(struct socket *sock,
+                                  struct msghdr *msg, int size, int flags)
+{
+       return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size);
+}
+
+/* revaliation, get/set attr, shutdown */
+static int aa_sock_perm(const char *op, u32 request, struct socket *sock)
+{
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+       AA_BUG(in_interrupt());
+
+       return af_select(sock->sk->sk_family,
+                        sock_perm(op, request, sock),
+                        aa_sk_perm(op, request, sock->sk));
+}
+
+/**
+ * apparmor_socket_getsockname - check perms before getting the local address
+ */
+static int apparmor_socket_getsockname(struct socket *sock)
+{
+       return aa_sock_perm(OP_GETSOCKNAME, AA_MAY_GETATTR, sock);
+}
+
+/**
+ * apparmor_socket_getpeername - check perms before getting remote address
+ */
+static int apparmor_socket_getpeername(struct socket *sock)
+{
+       return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock);
+}
+
+/* revaliation, get/set attr, opt */
+static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock,
+                           int level, int optname)
+{
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+       AA_BUG(in_interrupt());
+
+       return af_select(sock->sk->sk_family,
+                        opt_perm(op, request, sock, level, optname),
+                        aa_sk_perm(op, request, sock->sk));
+}
+
+/**
+ * apparmor_getsockopt - check perms before getting socket options
+ */
+static int apparmor_socket_getsockopt(struct socket *sock, int level,
+                                     int optname)
+{
+       return aa_sock_opt_perm(OP_GETSOCKOPT, AA_MAY_GETOPT, sock,
+                               level, optname);
+}
+
+/**
+ * apparmor_setsockopt - check perms before setting socket options
+ */
+static int apparmor_socket_setsockopt(struct socket *sock, int level,
+                                     int optname)
+{
+       return aa_sock_opt_perm(OP_SETSOCKOPT, AA_MAY_SETOPT, sock,
+                               level, optname);
+}
+
+/**
+ * apparmor_socket_shutdown - check perms before shutting down @sock conn
+ */
+static int apparmor_socket_shutdown(struct socket *sock, int how)
+{
+       return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock);
+}
+
+/**
+ * apparmor_socket_sock_recv_skb - check perms before associating skb to sk
+ *
+ * Note: can not sleep may be called with locks held
+ *
+ * dont want protocol specific in __skb_recv_datagram()
+ * to deny an incoming connection  socket_sock_rcv_skb()
+ */
+static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+       return 0;
+}
+
+
+static struct aa_label *sk_peer_label(struct sock *sk)
+{
+       struct aa_sk_ctx *ctx = SK_CTX(sk);
+
+       if (ctx->peer)
+               return ctx->peer;
+
+       return ERR_PTR(-ENOPROTOOPT);
+}
+
+/**
+ * apparmor_socket_getpeersec_stream - get security context of peer
+ *
+ * Note: for tcp only valid if using ipsec or cipso on lan
+ */
+static int apparmor_socket_getpeersec_stream(struct socket *sock,
+                                            char __user *optval,
+                                            int __user *optlen,
+                                            unsigned int len)
+{
+       char *name;
+       int slen, error = 0;
+       struct aa_label *label;
+       struct aa_label *peer;
+
+       label = begin_current_label_crit_section();
+       peer = sk_peer_label(sock->sk);
+       if (IS_ERR(peer)) {
+               error = PTR_ERR(peer);
+               goto done;
+       }
+       slen = aa_label_asxprint(&name, labels_ns(label), peer,
+                                FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
+                                FLAG_HIDDEN_UNCONFINED, GFP_KERNEL);
+       /* don't include terminating \0 in slen, it breaks some apps */
+       if (slen < 0) {
+               error = -ENOMEM;
+       } else {
+               if (slen > len) {
+                       error = -ERANGE;
+               } else if (copy_to_user(optval, name, slen)) {
+                       error = -EFAULT;
+                       goto out;
+               }
+               if (put_user(slen, optlen))
+                       error = -EFAULT;
+out:
+               kfree(name);
+
+       }
+
+done:
+       end_current_label_crit_section(label);
+
+       return error;
+}
+
+/**
+ * apparmor_socket_getpeersec_dgram - get security label of packet
+ * @sock: the peer socket
+ * @skb: packet data
+ * @secid: pointer to where to put the secid of the packet
+ *
+ * Sets the netlabel socket state on sk from parent
+ */
+static int apparmor_socket_getpeersec_dgram(struct socket *sock,
+                                           struct sk_buff *skb, u32 *secid)
+
+{
+       /* TODO: requires secid support */
+       return -ENOPROTOOPT;
+}
+
+/**
+ * apparmor_sock_graft - Initialize newly created socket
+ * @sk: child sock
+ * @parent: parent socket
+ *
+ * Note: could set off of SOCK_CTX(parent) but need to track inode and we can
+ *       just set sk security information off of current creating process label
+ *       Labeling of sk for accept case - probably should be sock based
+ *       instead of task, because of the case where an implicitly labeled
+ *       socket is shared by different tasks.
+ */
+static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
+{
+       struct aa_sk_ctx *ctx = SK_CTX(sk);
+
+       if (!ctx->label)
+               ctx->label = aa_get_current_label();
+}
+
 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),
@@ -776,6 +1151,30 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
        LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
 
+       LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
+       LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
+       LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
+
+       LSM_HOOK_INIT(socket_create, apparmor_socket_create),
+       LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create),
+       LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
+       LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
+       LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
+       LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
+       LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
+       LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
+       LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
+       LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
+       LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
+       LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
+       LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
+       LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb),
+       LSM_HOOK_INIT(socket_getpeersec_stream,
+                     apparmor_socket_getpeersec_stream),
+       LSM_HOOK_INIT(socket_getpeersec_dgram,
+                     apparmor_socket_getpeersec_dgram),
+       LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
+
        LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
        LSM_HOOK_INIT(cred_free, apparmor_cred_free),
        LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
@@ -785,6 +1184,8 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds),
        LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds),
 
+       LSM_HOOK_INIT(task_free, apparmor_task_free),
+       LSM_HOOK_INIT(task_alloc, apparmor_task_alloc),
        LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
        LSM_HOOK_INIT(task_kill, apparmor_task_kill),
 };
@@ -1032,12 +1433,12 @@ static int __init set_init_ctx(void)
        struct cred *cred = (struct cred *)current->real_cred;
        struct aa_task_ctx *ctx;
 
-       ctx = aa_alloc_task_context(GFP_KERNEL);
+       ctx = aa_alloc_task_ctx(GFP_KERNEL);
        if (!ctx)
                return -ENOMEM;
 
-       ctx->label = aa_get_label(ns_unconfined(root_ns));
-       cred_ctx(cred) = ctx;
+       cred_label(cred) = aa_get_label(ns_unconfined(root_ns));
+       task_ctx(current) = ctx;
 
        return 0;
 }
index 72c604350e805d87b16d7f6595c94fc6028648e6..280eba082c7bfbb05b0c96d8d4bd7aa3e604a7a8 100644 (file)
@@ -30,6 +30,11 @@ static char nulldfa_src[] = {
 };
 struct aa_dfa *nulldfa;
 
+static char stacksplitdfa_src[] = {
+       #include "stacksplitdfa.in"
+};
+struct aa_dfa *stacksplitdfa;
+
 int aa_setup_dfa_engine(void)
 {
        int error;
@@ -37,19 +42,31 @@ int aa_setup_dfa_engine(void)
        nulldfa = aa_dfa_unpack(nulldfa_src, sizeof(nulldfa_src),
                                TO_ACCEPT1_FLAG(YYTD_DATA32) |
                                TO_ACCEPT2_FLAG(YYTD_DATA32));
-       if (!IS_ERR(nulldfa))
-               return 0;
+       if (IS_ERR(nulldfa)) {
+               error = PTR_ERR(nulldfa);
+               nulldfa = NULL;
+               return error;
+       }
 
-       error = PTR_ERR(nulldfa);
-       nulldfa = NULL;
+       stacksplitdfa = aa_dfa_unpack(stacksplitdfa_src,
+                                     sizeof(stacksplitdfa_src),
+                                     TO_ACCEPT1_FLAG(YYTD_DATA32) |
+                                     TO_ACCEPT2_FLAG(YYTD_DATA32));
+       if (IS_ERR(stacksplitdfa)) {
+               aa_put_dfa(nulldfa);
+               nulldfa = NULL;
+               error = PTR_ERR(stacksplitdfa);
+               stacksplitdfa = NULL;
+               return error;
+       }
 
-       return error;
+       return 0;
 }
 
 void aa_teardown_dfa_engine(void)
 {
+       aa_put_dfa(stacksplitdfa);
        aa_put_dfa(nulldfa);
-       nulldfa = NULL;
 }
 
 /**
@@ -119,8 +136,8 @@ fail:
 }
 
 /**
- * verify_dfa - verify that transitions and states in the tables are in bounds.
- * @dfa: dfa to test  (NOT NULL)
+ * verify_table_headers - verify that the tables headers are as expected
+ * @tables - array of dfa tables to check (NOT NULL)
  * @flags: flags controlling what type of accept table are acceptable
  *
  * Assumes dfa has gone through the first pass verification done by unpacking
@@ -128,64 +145,98 @@ fail:
  *
  * Returns: %0 else error code on failure to verify
  */
-static int verify_dfa(struct aa_dfa *dfa, int flags)
+static int verify_table_headers(struct table_header **tables, int flags)
 {
-       size_t i, state_count, trans_count;
+       size_t state_count, trans_count;
        int error = -EPROTO;
 
        /* check that required tables exist */
-       if (!(dfa->tables[YYTD_ID_DEF] &&
-             dfa->tables[YYTD_ID_BASE] &&
-             dfa->tables[YYTD_ID_NXT] && dfa->tables[YYTD_ID_CHK]))
+       if (!(tables[YYTD_ID_DEF] && tables[YYTD_ID_BASE] &&
+             tables[YYTD_ID_NXT] && tables[YYTD_ID_CHK]))
                goto out;
 
        /* accept.size == default.size == base.size */
-       state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
+       state_count = tables[YYTD_ID_BASE]->td_lolen;
        if (ACCEPT1_FLAGS(flags)) {
-               if (!dfa->tables[YYTD_ID_ACCEPT])
+               if (!tables[YYTD_ID_ACCEPT])
                        goto out;
-               if (state_count != dfa->tables[YYTD_ID_ACCEPT]->td_lolen)
+               if (state_count != tables[YYTD_ID_ACCEPT]->td_lolen)
                        goto out;
        }
        if (ACCEPT2_FLAGS(flags)) {
-               if (!dfa->tables[YYTD_ID_ACCEPT2])
+               if (!tables[YYTD_ID_ACCEPT2])
                        goto out;
-               if (state_count != dfa->tables[YYTD_ID_ACCEPT2]->td_lolen)
+               if (state_count != tables[YYTD_ID_ACCEPT2]->td_lolen)
                        goto out;
        }
-       if (state_count != dfa->tables[YYTD_ID_DEF]->td_lolen)
+       if (state_count != tables[YYTD_ID_DEF]->td_lolen)
                goto out;
 
        /* next.size == chk.size */
-       trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
-       if (trans_count != dfa->tables[YYTD_ID_CHK]->td_lolen)
+       trans_count = tables[YYTD_ID_NXT]->td_lolen;
+       if (trans_count != tables[YYTD_ID_CHK]->td_lolen)
                goto out;
 
        /* if equivalence classes then its table size must be 256 */
-       if (dfa->tables[YYTD_ID_EC] &&
-           dfa->tables[YYTD_ID_EC]->td_lolen != 256)
+       if (tables[YYTD_ID_EC] && tables[YYTD_ID_EC]->td_lolen != 256)
                goto out;
 
-       if (flags & DFA_FLAG_VERIFY_STATES) {
-               for (i = 0; i < state_count; i++) {
-                       if (DEFAULT_TABLE(dfa)[i] >= state_count)
-                               goto out;
-                       if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
-                               printk(KERN_ERR "AppArmor DFA next/check upper "
-                                      "bounds error\n");
-                               goto out;
-                       }
+       error = 0;
+out:
+       return error;
+}
+
+/**
+ * verify_dfa - verify that transitions and states in the tables are in bounds.
+ * @dfa: dfa to test  (NOT NULL)
+ *
+ * Assumes dfa has gone through the first pass verification done by unpacking
+ * NOTE: this does not valid accept table values
+ *
+ * Returns: %0 else error code on failure to verify
+ */
+static int verify_dfa(struct aa_dfa *dfa)
+{
+       size_t i, state_count, trans_count;
+       int error = -EPROTO;
+
+       state_count = dfa->tables[YYTD_ID_BASE]->td_lolen;
+       trans_count = dfa->tables[YYTD_ID_NXT]->td_lolen;
+       for (i = 0; i < state_count; i++) {
+               if (!(BASE_TABLE(dfa)[i] & MATCH_FLAG_DIFF_ENCODE) &&
+                   (DEFAULT_TABLE(dfa)[i] >= state_count))
+                       goto out;
+               if (base_idx(BASE_TABLE(dfa)[i]) + 255 >= trans_count) {
+                       pr_err("AppArmor DFA next/check upper bounds error\n");
+                       goto out;
                }
+       }
 
-               for (i = 0; i < trans_count; i++) {
-                       if (NEXT_TABLE(dfa)[i] >= state_count)
-                               goto out;
-                       if (CHECK_TABLE(dfa)[i] >= state_count)
+       for (i = 0; i < trans_count; i++) {
+               if (NEXT_TABLE(dfa)[i] >= state_count)
+                       goto out;
+               if (CHECK_TABLE(dfa)[i] >= state_count)
+                       goto out;
+       }
+
+       /* Now that all the other tables are verified, verify diffencoding */
+       for (i = 0; i < state_count; i++) {
+               size_t j, k;
+
+               for (j = i;
+                    (BASE_TABLE(dfa)[j] & MATCH_FLAG_DIFF_ENCODE) &&
+                    !(BASE_TABLE(dfa)[j] & MARK_DIFF_ENCODE);
+                    j = k) {
+                       k = DEFAULT_TABLE(dfa)[j];
+                       if (j == k)
                                goto out;
+                       if (k < j)
+                               break;          /* already verified */
+                       BASE_TABLE(dfa)[j] |= MARK_DIFF_ENCODE;
                }
        }
-
        error = 0;
+
 out:
        return error;
 }
@@ -257,6 +308,9 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
                goto fail;
 
        dfa->flags = ntohs(*(__be16 *) (data + 12));
+       if (dfa->flags != 0 && dfa->flags != YYTH_FLAG_DIFF_ENCODE)
+               goto fail;
+
        data += hsize;
        size -= hsize;
 
@@ -299,11 +353,16 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
                size -= table_size(table->td_lolen, table->td_flags);
                table = NULL;
        }
-
-       error = verify_dfa(dfa, flags);
+       error = verify_table_headers(dfa->tables, flags);
        if (error)
                goto fail;
 
+       if (flags & DFA_FLAG_VERIFY_STATES) {
+               error = verify_dfa(dfa);
+               if (error)
+                       goto fail;
+       }
+
        return dfa;
 
 fail:
@@ -312,6 +371,20 @@ fail:
        return ERR_PTR(error);
 }
 
+#define match_char(state, def, base, next, check, C)   \
+do {                                                   \
+       u32 b = (base)[(state)];                        \
+       unsigned int pos = base_idx(b) + (C);           \
+       if ((check)[pos] != (state)) {                  \
+               (state) = (def)[(state)];               \
+               if (b & MATCH_FLAG_DIFF_ENCODE)         \
+                       continue;                       \
+               break;                                  \
+       }                                               \
+       (state) = (next)[pos];                          \
+       break;                                          \
+} while (1)
+
 /**
  * aa_dfa_match_len - traverse @dfa to find state @str stops at
  * @dfa: the dfa to match @str against  (NOT NULL)
@@ -335,6 +408,118 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
        u32 *base = BASE_TABLE(dfa);
        u16 *next = NEXT_TABLE(dfa);
        u16 *check = CHECK_TABLE(dfa);
+       unsigned int state = start;
+
+       if (state == 0)
+               return 0;
+
+       /* current state is <state>, matching character *str */
+       if (dfa->tables[YYTD_ID_EC]) {
+               /* Equivalence class table defined */
+               u8 *equiv = EQUIV_TABLE(dfa);
+               for (; len; len--)
+                       match_char(state, def, base, next, check,
+                                  equiv[(u8) *str++]);
+       } else {
+               /* default is direct to next state */
+               for (; len; len--)
+                       match_char(state, def, base, next, check, (u8) *str++);
+       }
+
+       return state;
+}
+
+/**
+ * aa_dfa_match - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against  (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
+ *
+ * aa_dfa_match will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
+                         const char *str)
+{
+       u16 *def = DEFAULT_TABLE(dfa);
+       u32 *base = BASE_TABLE(dfa);
+       u16 *next = NEXT_TABLE(dfa);
+       u16 *check = CHECK_TABLE(dfa);
+       unsigned int state = start;
+
+       if (state == 0)
+               return 0;
+
+       /* current state is <state>, matching character *str */
+       if (dfa->tables[YYTD_ID_EC]) {
+               /* Equivalence class table defined */
+               u8 *equiv = EQUIV_TABLE(dfa);
+               /* default is direct to next state */
+               while (*str)
+                       match_char(state, def, base, next, check,
+                                  equiv[(u8) *str++]);
+       } else {
+               /* default is direct to next state */
+               while (*str)
+                       match_char(state, def, base, next, check, (u8) *str++);
+       }
+
+       return state;
+}
+
+/**
+ * aa_dfa_next - step one character to the next state in the dfa
+ * @dfa: the dfa to tranverse (NOT NULL)
+ * @state: the state to start in
+ * @c: the input character to transition on
+ *
+ * aa_dfa_match will step through the dfa by one input character @c
+ *
+ * Returns: state reach after input @c
+ */
+unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
+                         const char c)
+{
+       u16 *def = DEFAULT_TABLE(dfa);
+       u32 *base = BASE_TABLE(dfa);
+       u16 *next = NEXT_TABLE(dfa);
+       u16 *check = CHECK_TABLE(dfa);
+
+       /* current state is <state>, matching character *str */
+       if (dfa->tables[YYTD_ID_EC]) {
+               /* Equivalence class table defined */
+               u8 *equiv = EQUIV_TABLE(dfa);
+               match_char(state, def, base, next, check, equiv[(u8) c]);
+       } else
+               match_char(state, def, base, next, check, (u8) c);
+
+       return state;
+}
+
+/**
+ * aa_dfa_match_until - traverse @dfa until accept state or end of input
+ * @dfa: the dfa to match @str against  (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
+ * @retpos: first character in str after match OR end of string
+ *
+ * aa_dfa_match will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_match_until(struct aa_dfa *dfa, unsigned int start,
+                               const char *str, const char **retpos)
+{
+       u16 *def = DEFAULT_TABLE(dfa);
+       u32 *base = BASE_TABLE(dfa);
+       u16 *next = NEXT_TABLE(dfa);
+       u16 *check = CHECK_TABLE(dfa);
+       u32 *accept = ACCEPT_TABLE(dfa);
        unsigned int state = start, pos;
 
        if (state == 0)
@@ -345,48 +530,60 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start,
                /* Equivalence class table defined */
                u8 *equiv = EQUIV_TABLE(dfa);
                /* default is direct to next state */
-               for (; len; len--) {
+               while (*str) {
                        pos = base_idx(base[state]) + equiv[(u8) *str++];
                        if (check[pos] == state)
                                state = next[pos];
                        else
                                state = def[state];
+                       if (accept[state])
+                               break;
                }
        } else {
                /* default is direct to next state */
-               for (; len; len--) {
+               while (*str) {
                        pos = base_idx(base[state]) + (u8) *str++;
                        if (check[pos] == state)
                                state = next[pos];
                        else
                                state = def[state];
+                       if (accept[state])
+                               break;
                }
        }
 
+       *retpos = str;
        return state;
 }
 
 /**
- * aa_dfa_match - traverse @dfa to find state @str stops at
+ * aa_dfa_matchn_until - traverse @dfa until accept or @n bytes consumed
  * @dfa: the dfa to match @str against  (NOT NULL)
  * @start: the state of the dfa to start matching in
- * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
+ * @str: the string of bytes to match against the dfa  (NOT NULL)
+ * @n: length of the string of bytes to match
+ * @retpos: first character in str after match OR str + n
  *
- * aa_dfa_match will match @str against the dfa and return the state it
+ * aa_dfa_match_len will match @str against the dfa and return the state it
  * finished matching in. The final state can be used to look up the accepting
  * label, or as the start state of a continuing match.
  *
+ * This function will happily match again the 0 byte and only finishes
+ * when @n input is consumed.
+ *
  * Returns: final state reached after input is consumed
  */
-unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
-                         const char *str)
+unsigned int aa_dfa_matchn_until(struct aa_dfa *dfa, unsigned int start,
+                                const char *str, int n, const char **retpos)
 {
        u16 *def = DEFAULT_TABLE(dfa);
        u32 *base = BASE_TABLE(dfa);
        u16 *next = NEXT_TABLE(dfa);
        u16 *check = CHECK_TABLE(dfa);
+       u32 *accept = ACCEPT_TABLE(dfa);
        unsigned int state = start, pos;
 
+       *retpos = NULL;
        if (state == 0)
                return 0;
 
@@ -395,65 +592,149 @@ unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start,
                /* Equivalence class table defined */
                u8 *equiv = EQUIV_TABLE(dfa);
                /* default is direct to next state */
-               while (*str) {
+               for (; n; n--) {
                        pos = base_idx(base[state]) + equiv[(u8) *str++];
                        if (check[pos] == state)
                                state = next[pos];
                        else
                                state = def[state];
+                       if (accept[state])
+                               break;
                }
        } else {
                /* default is direct to next state */
-               while (*str) {
+               for (; n; n--) {
                        pos = base_idx(base[state]) + (u8) *str++;
                        if (check[pos] == state)
                                state = next[pos];
                        else
                                state = def[state];
+                       if (accept[state])
+                               break;
                }
        }
 
+       *retpos = str;
        return state;
 }
 
-/**
- * aa_dfa_next - step one character to the next state in the dfa
- * @dfa: the dfa to tranverse (NOT NULL)
- * @state: the state to start in
- * @c: the input character to transition on
- *
- * aa_dfa_match will step through the dfa by one input character @c
- *
- * Returns: state reach after input @c
- */
-unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state,
-                         const char c)
+#define inc_wb_pos(wb)                                         \
+do {                                                           \
+       wb->pos = (wb->pos + 1) & (wb->size - 1);               \
+       wb->len = (wb->len + 1) & (wb->size - 1);               \
+} while (0)
+
+/* For DFAs that don't support extended tagging of states */
+static bool is_loop(struct match_workbuf *wb, unsigned int state,
+                   unsigned int *adjust)
+{
+       unsigned int pos = wb->pos;
+       unsigned int i;
+
+       if (wb->history[pos] < state)
+               return false;
+
+       for (i = 0; i <= wb->len; i++) {
+               if (wb->history[pos] == state) {
+                       *adjust = i;
+                       return true;
+               }
+               if (pos == 0)
+                       pos = wb->size;
+               pos--;
+       }
+
+       *adjust = i;
+       return true;
+}
+
+static unsigned int leftmatch_fb(struct aa_dfa *dfa, unsigned int start,
+                                const char *str, struct match_workbuf *wb,
+                                unsigned int *count)
 {
        u16 *def = DEFAULT_TABLE(dfa);
        u32 *base = BASE_TABLE(dfa);
        u16 *next = NEXT_TABLE(dfa);
        u16 *check = CHECK_TABLE(dfa);
-       unsigned int pos;
+       unsigned int state = start, pos;
+
+       AA_BUG(!dfa);
+       AA_BUG(!str);
+       AA_BUG(!wb);
+       AA_BUG(!count);
+
+       *count = 0;
+       if (state == 0)
+               return 0;
 
        /* current state is <state>, matching character *str */
        if (dfa->tables[YYTD_ID_EC]) {
                /* Equivalence class table defined */
                u8 *equiv = EQUIV_TABLE(dfa);
                /* default is direct to next state */
+               while (*str) {
+                       unsigned int adjust;
 
-               pos = base_idx(base[state]) + equiv[(u8) c];
-               if (check[pos] == state)
-                       state = next[pos];
-               else
-                       state = def[state];
+                       wb->history[wb->pos] = state;
+                       pos = base_idx(base[state]) + equiv[(u8) *str++];
+                       if (check[pos] == state)
+                               state = next[pos];
+                       else
+                               state = def[state];
+                       if (is_loop(wb, state, &adjust)) {
+                               state = aa_dfa_match(dfa, state, str);
+                               *count -= adjust;
+                               goto out;
+                       }
+                       inc_wb_pos(wb);
+                       (*count)++;
+               }
        } else {
                /* default is direct to next state */
-               pos = base_idx(base[state]) + (u8) c;
-               if (check[pos] == state)
-                       state = next[pos];
-               else
-                       state = def[state];
+               while (*str) {
+                       unsigned int adjust;
+
+                       wb->history[wb->pos] = state;
+                       pos = base_idx(base[state]) + (u8) *str++;
+                       if (check[pos] == state)
+                               state = next[pos];
+                       else
+                               state = def[state];
+                       if (is_loop(wb, state, &adjust)) {
+                               state = aa_dfa_match(dfa, state, str);
+                               *count -= adjust;
+                               goto out;
+                       }
+                       inc_wb_pos(wb);
+                       (*count)++;
+               }
        }
 
+out:
+       if (!state)
+               *count = 0;
        return state;
 }
+
+/**
+ * aa_dfa_leftmatch - traverse @dfa to find state @str stops at
+ * @dfa: the dfa to match @str against  (NOT NULL)
+ * @start: the state of the dfa to start matching in
+ * @str: the null terminated string of bytes to match against the dfa (NOT NULL)
+ * @count: current count of longest left.
+ *
+ * aa_dfa_match will match @str against the dfa and return the state it
+ * finished matching in. The final state can be used to look up the accepting
+ * label, or as the start state of a continuing match.
+ *
+ * Returns: final state reached after input is consumed
+ */
+unsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start,
+                             const char *str, unsigned int *count)
+{
+       DEFINE_MATCH_WB(wb);
+
+       /* TODO: match for extended state dfas */
+
+       return leftmatch_fb(dfa, start, str, &wb, count);
+}
index 8c558cbce930b15a69a7451973a974152fbb6a08..6e8c7ac0b33d1e7b678db852dcce3eb183a51ca8 100644 (file)
@@ -18,7 +18,7 @@
 
 #include "include/apparmor.h"
 #include "include/audit.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/domain.h"
 #include "include/file.h"
 #include "include/match.h"
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
new file mode 100644 (file)
index 0000000..bb24cfa
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * AppArmor security module
+ *
+ * This file contains AppArmor network mediation
+ *
+ * Copyright (C) 1998-2008 Novell/SUSE
+ * Copyright 2009-2017 Canonical Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include "include/apparmor.h"
+#include "include/audit.h"
+#include "include/cred.h"
+#include "include/label.h"
+#include "include/net.h"
+#include "include/policy.h"
+
+#include "net_names.h"
+
+
+struct aa_sfs_entry aa_sfs_entry_network[] = {
+       AA_SFS_FILE_STRING("af_mask",   AA_SFS_AF_MASK),
+       { }
+};
+
+static const char * const net_mask_names[] = {
+       "unknown",
+       "send",
+       "receive",
+       "unknown",
+
+       "create",
+       "shutdown",
+       "connect",
+       "unknown",
+
+       "setattr",
+       "getattr",
+       "setcred",
+       "getcred",
+
+       "chmod",
+       "chown",
+       "chgrp",
+       "lock",
+
+       "mmap",
+       "mprot",
+       "unknown",
+       "unknown",
+
+       "accept",
+       "bind",
+       "listen",
+       "unknown",
+
+       "setopt",
+       "getopt",
+       "unknown",
+       "unknown",
+
+       "unknown",
+       "unknown",
+       "unknown",
+       "unknown",
+};
+
+
+/* audit callback for net specific fields */
+void audit_net_cb(struct audit_buffer *ab, void *va)
+{
+       struct common_audit_data *sa = va;
+
+       audit_log_format(ab, " family=");
+       if (address_family_names[sa->u.net->family])
+               audit_log_string(ab, address_family_names[sa->u.net->family]);
+       else
+               audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family);
+       audit_log_format(ab, " sock_type=");
+       if (sock_type_names[aad(sa)->net.type])
+               audit_log_string(ab, sock_type_names[aad(sa)->net.type]);
+       else
+               audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type);
+       audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
+
+       if (aad(sa)->request & NET_PERMS_MASK) {
+               audit_log_format(ab, " requested_mask=");
+               aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0,
+                                  net_mask_names, NET_PERMS_MASK);
+
+               if (aad(sa)->denied & NET_PERMS_MASK) {
+                       audit_log_format(ab, " denied_mask=");
+                       aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0,
+                                          net_mask_names, NET_PERMS_MASK);
+               }
+       }
+       if (aad(sa)->peer) {
+               audit_log_format(ab, " peer=");
+               aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
+                               FLAGS_NONE, GFP_ATOMIC);
+       }
+}
+
+/* Generic af perm */
+int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
+                      u32 request, u16 family, int type)
+{
+       struct aa_perms perms = { };
+       unsigned int state;
+       __be16 buffer[2];
+
+       AA_BUG(family >= AF_MAX);
+       AA_BUG(type < 0 || type >= SOCK_MAX);
+
+       if (profile_unconfined(profile))
+               return 0;
+       state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
+       if (!state)
+               return 0;
+
+       buffer[0] = cpu_to_be16(family);
+       buffer[1] = cpu_to_be16((u16) type);
+       state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
+                                4);
+       aa_compute_perms(profile->policy.dfa, state, &perms);
+       aa_apply_modes_to_perms(profile, &perms);
+
+       return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
+}
+
+int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
+              int type, int protocol)
+{
+       struct aa_profile *profile;
+       DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol);
+
+       return fn_for_each_confined(label, profile,
+                       aa_profile_af_perm(profile, &sa, request, family,
+                                          type));
+}
+
+static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
+                           struct sock *sk)
+{
+       struct aa_profile *profile;
+       DEFINE_AUDIT_SK(sa, op, sk);
+
+       AA_BUG(!label);
+       AA_BUG(!sk);
+
+       if (unconfined(label))
+               return 0;
+
+       return fn_for_each_confined(label, profile,
+                       aa_profile_af_sk_perm(profile, &sa, request, sk));
+}
+
+int aa_sk_perm(const char *op, u32 request, struct sock *sk)
+{
+       struct aa_label *label;
+       int error;
+
+       AA_BUG(!sk);
+       AA_BUG(in_interrupt());
+
+       /* TODO: switch to begin_current_label ???? */
+       label = begin_current_label_crit_section();
+       error = aa_label_sk_perm(label, op, request, sk);
+       end_current_label_crit_section(label);
+
+       return error;
+}
+
+
+int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
+                     struct socket *sock)
+{
+       AA_BUG(!label);
+       AA_BUG(!sock);
+       AA_BUG(!sock->sk);
+
+       return aa_label_sk_perm(label, op, request, sock->sk);
+}
index 3cb38022902e809a9bdf3ed6a08217ffe6dd0658..095f42a24cbc9492ca95498d0041a5f4979c9b3c 100644 (file)
@@ -1 +1,107 @@
-0x1B, 0x5E, 0x78, 0x3D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x04, 0x90, 0x00, 0x00, 0x6E, 0x6F, 0x74, 0x66, 0x6C, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+0x1B, 0x5E, 0x78, 0x3D, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x04,
+0x90, 0x00, 0x00, 0x6E, 0x6F, 0x74, 0x66, 0x6C, 0x65, 0x78, 0x00,
+0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00
index b0b58848c2487e69cca16f9bfd3ee21d466a12af..c07493ce237680c7183d93282a310cf4eacbfbde 100644 (file)
@@ -82,7 +82,7 @@
 
 #include "include/apparmor.h"
 #include "include/capability.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/file.h"
 #include "include/ipc.h"
 #include "include/match.h"
@@ -210,6 +210,7 @@ static void aa_free_data(void *ptr, void *arg)
 void aa_free_profile(struct aa_profile *profile)
 {
        struct rhashtable *rht;
+       int i;
 
        AA_DEBUG("%s(%p)\n", __func__, profile);
 
@@ -227,6 +228,9 @@ void aa_free_profile(struct aa_profile *profile)
        aa_free_cap_rules(&profile->caps);
        aa_free_rlimit_rules(&profile->rlimits);
 
+       for (i = 0; i < profile->xattr_count; i++)
+               kzfree(profile->xattrs[i]);
+       kzfree(profile->xattrs);
        kzfree(profile->dirname);
        aa_put_dfa(profile->xmatch);
        aa_put_dfa(profile->policy.dfa);
@@ -845,8 +849,9 @@ static struct aa_profile *update_to_newest_parent(struct aa_profile *new)
  * @udata: serialized data stream  (NOT NULL)
  *
  * unpack and replace a profile on the profile list and uses of that profile
- * by any aa_task_ctx.  If the profile does not exist on the profile list
- * it is added.
+ * by any task creds via invalidating the old version of the profile, which
+ * tasks will notice to update their own cred.  If the profile does not exist
+ * on the profile list it is added.
  *
  * Returns: size of data consumed else error code on failure.
  */
index b1e629cba70b76f7b586ea07bfa0b77725c73e1d..b0f9dc3f765a9d7a19003ae2f3bd327b58df98a9 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/string.h>
 
 #include "include/apparmor.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/policy_ns.h"
 #include "include/label.h"
 #include "include/policy.h"
index 59a1a25b7d43f209b594d61c7fd38fb4e0e50f37..b9e6b2cafa6993fe29820e13429988e7e9d01c09 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "include/apparmor.h"
 #include "include/audit.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/crypto.h"
 #include "include/match.h"
 #include "include/path.h"
@@ -37,7 +37,8 @@
 
 #define v5     5       /* base version */
 #define v6     6       /* per entry policydb mediation check */
-#define v7     7       /* full network masking */
+#define v7     7
+#define v8     8       /* full network masking */
 
 /*
  * The AppArmor interface treats data as a type byte followed by the
@@ -164,8 +165,9 @@ static void do_loaddata_free(struct work_struct *work)
        }
 
        kzfree(d->hash);
-       kfree(d->name);
-       kvfree(d);
+       kzfree(d->name);
+       kvfree(d->data);
+       kzfree(d);
 }
 
 void aa_loaddata_kref(struct kref *kref)
@@ -180,10 +182,16 @@ void aa_loaddata_kref(struct kref *kref)
 
 struct aa_loaddata *aa_loaddata_alloc(size_t size)
 {
-       struct aa_loaddata *d = kvzalloc(sizeof(*d) + size, GFP_KERNEL);
+       struct aa_loaddata *d;
 
+       d = kzalloc(sizeof(*d), GFP_KERNEL);
        if (d == NULL)
                return ERR_PTR(-ENOMEM);
+       d->data = kvzalloc(size, GFP_KERNEL);
+       if (!d->data) {
+               kfree(d);
+               return ERR_PTR(-ENOMEM);
+       }
        kref_init(&d->count);
        INIT_LIST_HEAD(&d->list);
 
@@ -196,6 +204,15 @@ static bool inbounds(struct aa_ext *e, size_t size)
        return (size <= e->end - e->pos);
 }
 
+static void *kvmemdup(const void *src, size_t len)
+{
+       void *p = kvmalloc(len, GFP_KERNEL);
+
+       if (p)
+               memcpy(p, src, len);
+       return p;
+}
+
 /**
  * aa_u16_chunck - test and do bounds checking for a u16 size based chunk
  * @e: serialized data read head (NOT NULL)
@@ -515,6 +532,35 @@ fail:
        return 0;
 }
 
+static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile)
+{
+       void *pos = e->pos;
+
+       if (unpack_nameX(e, AA_STRUCT, "xattrs")) {
+               int i, size;
+
+               size = unpack_array(e, NULL);
+               profile->xattr_count = size;
+               profile->xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL);
+               if (!profile->xattrs)
+                       goto fail;
+               for (i = 0; i < size; i++) {
+                       if (!unpack_strdup(e, &profile->xattrs[i], NULL))
+                               goto fail;
+               }
+               if (!unpack_nameX(e, AA_ARRAYEND, NULL))
+                       goto fail;
+               if (!unpack_nameX(e, AA_STRUCTEND, NULL))
+                       goto fail;
+       }
+
+       return 1;
+
+fail:
+       e->pos = pos;
+       return 0;
+}
+
 static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
 {
        void *pos = e->pos;
@@ -549,15 +595,6 @@ fail:
        return 0;
 }
 
-static void *kvmemdup(const void *src, size_t len)
-{
-       void *p = kvmalloc(len, GFP_KERNEL);
-
-       if (p)
-               memcpy(p, src, len);
-       return p;
-}
-
 static u32 strhash(const void *data, u32 len, u32 seed)
 {
        const char * const *key = data;
@@ -712,6 +749,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
                        goto fail;
        }
 
+       if (!unpack_xattrs(e, profile)) {
+               info = "failed to unpack profile xattrs";
+               goto fail;
+       }
+
        if (!unpack_rlimits(e, profile)) {
                info = "failed to unpack profile rlimits";
                goto fail;
index d81617379d63d94d69d82a6949e11c7b74ef7180..80c34ed373c382582d93e4cbb7693a5487993b7b 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 #include "include/apparmor.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/policy.h"
 #include "include/policy_ns.h"
 #include "include/domain.h"
index cf4d234febe94c9e96a8c0dc7df4d0132f856621..d022137143b9eb2eb0a846ed00bfbc860e388a3b 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/security.h>
 
 #include "include/audit.h"
-#include "include/context.h"
+#include "include/cred.h"
 #include "include/resource.h"
 #include "include/policy.h"
 
diff --git a/security/apparmor/stacksplitdfa.in b/security/apparmor/stacksplitdfa.in
new file mode 100644 (file)
index 0000000..4bddd10
--- /dev/null
@@ -0,0 +1,114 @@
+/* 0x1 [^\000]*[^/\000]//& */ 0x1B, 0x5E, 0x78, 0x3D, 0x00, 0x00,
+0x00, 0x18, 0x00, 0x00, 0x04, 0xD8, 0x00, 0x00, 0x6E, 0x6F, 0x74,
+0x66, 0x6C, 0x65, 0x78, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x02,
+0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x08, 0x00,
+0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00,
+0x04, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
+0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04,
+0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00
similarity index 53%
rename from security/apparmor/context.c
rename to security/apparmor/task.c
index c95f1ac6190b4bf2c8fb42c739da67965f85ad41..c6b78a14da91842a7288e4c92e6db490284f0c4c 100644 (file)
@@ -1,72 +1,23 @@
 /*
  * AppArmor security module
  *
- * This file contains AppArmor functions used to manipulate object security
- * contexts.
+ * This file contains AppArmor task related definitions and mediation
  *
- * Copyright (C) 1998-2008 Novell/SUSE
- * Copyright 2009-2010 Canonical Ltd.
+ * Copyright 2017 Canonical Ltd.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, version 2 of the
  * License.
  *
- *
- * AppArmor sets confinement on every task, via the the aa_task_ctx and
- * the aa_task_ctx.label, both of which are required and are not allowed
- * to be NULL.  The aa_task_ctx is not reference counted and is unique
- * to each cred (which is reference count).  The label pointed to by
- * the task_ctx is reference counted.
- *
  * TODO
  * If a task uses change_hat it currently does not return to the old
  * cred or task context but instead creates a new one.  Ideally the task
  * should return to the previous cred if it has not been modified.
- *
  */
 
-#include "include/context.h"
-#include "include/policy.h"
-
-/**
- * aa_alloc_task_context - allocate a new task_ctx
- * @flags: gfp flags for allocation
- *
- * Returns: allocated buffer or NULL on failure
- */
-struct aa_task_ctx *aa_alloc_task_context(gfp_t flags)
-{
-       return kzalloc(sizeof(struct aa_task_ctx), flags);
-}
-
-/**
- * aa_free_task_context - free a task_ctx
- * @ctx: task_ctx to free (MAYBE NULL)
- */
-void aa_free_task_context(struct aa_task_ctx *ctx)
-{
-       if (ctx) {
-               aa_put_label(ctx->label);
-               aa_put_label(ctx->previous);
-               aa_put_label(ctx->onexec);
-
-               kzfree(ctx);
-       }
-}
-
-/**
- * aa_dup_task_context - duplicate a task context, incrementing reference counts
- * @new: a blank task context      (NOT NULL)
- * @old: the task context to copy  (NOT NULL)
- */
-void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old)
-{
-       *new = *old;
-       aa_get_label(new->label);
-       aa_get_label(new->previous);
-       aa_get_label(new->onexec);
-}
+#include "include/cred.h"
+#include "include/task.h"
 
 /**
  * aa_get_task_label - Get another task's label
@@ -93,11 +44,13 @@ struct aa_label *aa_get_task_label(struct task_struct *task)
  */
 int aa_replace_current_label(struct aa_label *label)
 {
-       struct aa_task_ctx *ctx = current_ctx();
+       struct aa_label *old = aa_current_raw_label();
+       struct aa_task_ctx *ctx = task_ctx(current);
        struct cred *new;
+
        AA_BUG(!label);
 
-       if (ctx->label == label)
+       if (old == label)
                return 0;
 
        if (current_cred() != current_real_cred())
@@ -107,27 +60,34 @@ int aa_replace_current_label(struct aa_label *label)
        if (!new)
                return -ENOMEM;
 
-       ctx = cred_ctx(new);
-       if (unconfined(label) || (labels_ns(ctx->label) != labels_ns(label)))
-               /* if switching to unconfined or a different label namespace
+       if (ctx->nnp && label_is_stale(ctx->nnp)) {
+               struct aa_label *tmp = ctx->nnp;
+
+               ctx->nnp = aa_get_newest_label(tmp);
+               aa_put_label(tmp);
+       }
+       if (unconfined(label) || (labels_ns(old) != labels_ns(label)))
+               /*
+                * if switching to unconfined or a different label namespace
                 * clear out context state
                 */
-               aa_clear_task_ctx_trans(ctx);
+               aa_clear_task_ctx_trans(task_ctx(current));
 
        /*
-        * be careful switching ctx->profile, when racing replacement it
-        * is possible that ctx->profile->proxy->profile is the reference
-        * keeping @profile valid, so make sure to get its reference before
-        * dropping the reference on ctx->profile
+        * be careful switching cred label, when racing replacement it
+        * is possible that the cred labels's->proxy->label is the reference
+        * keeping @label valid, so make sure to get its reference before
+        * dropping the reference on the cred's label
         */
        aa_get_label(label);
-       aa_put_label(ctx->label);
-       ctx->label = label;
+       aa_put_label(cred_label(new));
+       cred_label(new) = label;
 
        commit_creds(new);
        return 0;
 }
 
+
 /**
  * aa_set_current_onexec - set the tasks change_profile to happen onexec
  * @label: system label to set at exec  (MAYBE NULL to clear value)
@@ -136,18 +96,13 @@ int aa_replace_current_label(struct aa_label *label)
  */
 int aa_set_current_onexec(struct aa_label *label, bool stack)
 {
-       struct aa_task_ctx *ctx;
-       struct cred *new = prepare_creds();
-       if (!new)
-               return -ENOMEM;
+       struct aa_task_ctx *ctx = task_ctx(current);
 
-       ctx = cred_ctx(new);
        aa_get_label(label);
-       aa_clear_task_ctx_trans(ctx);
+       aa_put_label(ctx->onexec);
        ctx->onexec = label;
        ctx->token = stack;
 
-       commit_creds(new);
        return 0;
 }
 
@@ -163,25 +118,27 @@ int aa_set_current_onexec(struct aa_label *label, bool stack)
  */
 int aa_set_current_hat(struct aa_label *label, u64 token)
 {
-       struct aa_task_ctx *ctx;
-       struct cred *new = prepare_creds();
+       struct aa_task_ctx *ctx = task_ctx(current);
+       struct cred *new;
+
+       new = prepare_creds();
        if (!new)
                return -ENOMEM;
        AA_BUG(!label);
 
-       ctx = cred_ctx(new);
        if (!ctx->previous) {
                /* transfer refcount */
-               ctx->previous = ctx->label;
+               ctx->previous = cred_label(new);
                ctx->token = token;
        } else if (ctx->token == token) {
-               aa_put_label(ctx->label);
+               aa_put_label(cred_label(new));
        } else {
                /* previous_profile && ctx->token != token */
                abort_creds(new);
                return -EACCES;
        }
-       ctx->label = aa_get_newest_label(label);
+
+       cred_label(new) = aa_get_newest_label(label);
        /* clear exec on switching context */
        aa_put_label(ctx->onexec);
        ctx->onexec = NULL;
@@ -201,28 +158,26 @@ int aa_set_current_hat(struct aa_label *label, u64 token)
  */
 int aa_restore_previous_label(u64 token)
 {
-       struct aa_task_ctx *ctx;
-       struct cred *new = prepare_creds();
-       if (!new)
-               return -ENOMEM;
+       struct aa_task_ctx *ctx = task_ctx(current);
+       struct cred *new;
 
-       ctx = cred_ctx(new);
-       if (ctx->token != token) {
-               abort_creds(new);
+       if (ctx->token != token)
                return -EACCES;
-       }
        /* ignore restores when there is no saved label */
-       if (!ctx->previous) {
-               abort_creds(new);
+       if (!ctx->previous)
                return 0;
-       }
 
-       aa_put_label(ctx->label);
-       ctx->label = aa_get_newest_label(ctx->previous);
-       AA_BUG(!ctx->label);
+       new = prepare_creds();
+       if (!new)
+               return -ENOMEM;
+
+       aa_put_label(cred_label(new));
+       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);
 
        commit_creds(new);
+
        return 0;
 }