apparmor: move aa_file_perm() to use labels
authorJohn Johansen <john.johansen@canonical.com>
Fri, 9 Jun 2017 21:59:51 +0000 (14:59 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Sun, 11 Jun 2017 00:11:42 +0000 (17:11 -0700)
Signed-off-by: John Johansen <john.johansen@canonical.com>
security/apparmor/file.c
security/apparmor/include/file.h
security/apparmor/lsm.c

index 5289c8d..c13e967 100644 (file)
@@ -23,6 +23,7 @@
 #include "include/match.h"
 #include "include/path.h"
 #include "include/policy.h"
+#include "include/label.h"
 
 static u32 map_mask_to_chr_mask(u32 mask)
 {
@@ -433,22 +434,55 @@ audit:
 /**
  * aa_file_perm - do permission revalidation check & audit for @file
  * @op: operation being checked
- * @profile: profile being enforced   (NOT NULL)
+ * @label: label being enforced   (NOT NULL)
  * @file: file to revalidate access permissions on  (NOT NULL)
  * @request: requested permissions
  *
  * Returns: %0 if access allowed else error
  */
-int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
+int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
                 u32 request)
 {
        struct path_cond cond = {
                .uid = file_inode(file)->i_uid,
                .mode = file_inode(file)->i_mode
        };
+       struct aa_file_ctx *fctx;
+       struct aa_label *flabel;
+       u32 denied;
+       int error = 0;
+
+       AA_BUG(!label);
+       AA_BUG(!file);
+
+       fctx = file_ctx(file);
+
+       rcu_read_lock();
+       flabel  = rcu_dereference(fctx->label);
+       AA_BUG(!flabel);
+
+       /* revalidate access, if task is unconfined, or the cached cred
+        * doesn't match or if the request is for more permissions than
+        * was granted.
+        *
+        * Note: the test for !unconfined(flabel) is to handle file
+        *       delegation from unconfined tasks
+        */
+       denied = request & ~fctx->allow;
+       if (unconfined(label) || unconfined(flabel) ||
+           (!denied && aa_label_is_subset(flabel, label)))
+               goto done;
+
+       /* TODO: label cross check */
+
+       if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
+               error = aa_path_perm(op, labels_profile(label), &file->f_path,
+                                    PATH_DELEGATE_DELETED, request, &cond);
 
-       return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
-                           request, &cond);
+done:
+       rcu_read_unlock();
+
+       return error;
 }
 
 static void revalidate_tty(struct aa_label *label)
@@ -469,8 +503,7 @@ static void revalidate_tty(struct aa_label *label)
                                             struct tty_file_private, list);
                file = file_priv->file;
 
-               if (aa_file_perm(OP_INHERIT, labels_profile(label), file,
-                                MAY_READ | MAY_WRITE))
+               if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE))
                        drop_tty = 1;
        }
        spin_unlock(&tty->files_lock);
@@ -484,8 +517,7 @@ static int match_file(const void *p, struct file *file, unsigned int fd)
 {
        struct aa_label *label = (struct aa_label *)p;
 
-       if (aa_file_perm(OP_INHERIT, labels_profile(label), file,
-                        aa_map_file_to_perms(file)))
+       if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file)))
                return fd + 1;
        return 0;
 }
index df76c20..4155127 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __AA_FILE_H
 #define __AA_FILE_H
 
+#include <linux/spinlock.h>
+
 #include "domain.h"
 #include "match.h"
 #include "perms.h"
@@ -33,13 +35,13 @@ struct path;
 #define file_ctx(X) ((struct aa_file_ctx *)(X)->f_security)
 
 /* struct aa_file_ctx - the AppArmor context the file was opened in
+ * @lock: lock to update the ctx
+ * @label: label currently cached on the ctx
  * @perms: the permission the file was opened with
- *
- * The file_ctx could currently be directly stored in file->f_security
- * as the profile reference is now stored in the f_cred.  However the
- * ctx struct will expand in the future so we keep the struct.
  */
 struct aa_file_ctx {
+       spinlock_t lock;
+       struct aa_label __rcu *label;
        u32 allow;
 };
 
@@ -50,12 +52,16 @@ struct aa_file_ctx {
  *
  * Returns: file_ctx or NULL on failure
  */
-static inline struct aa_file_ctx *aa_alloc_file_ctx(gfp_t gfp)
+static inline struct aa_file_ctx *aa_alloc_file_ctx(struct aa_label *label,
+                                                   gfp_t gfp)
 {
        struct aa_file_ctx *ctx;
 
        ctx = kzalloc(sizeof(struct aa_file_ctx), gfp);
-
+       if (ctx) {
+               spin_lock_init(&ctx->lock);
+               rcu_assign_pointer(ctx->label, aa_get_label(label));
+       }
        return ctx;
 }
 
@@ -65,8 +71,15 @@ static inline struct aa_file_ctx *aa_alloc_file_ctx(gfp_t gfp)
  */
 static inline void aa_free_file_ctx(struct aa_file_ctx *ctx)
 {
-       if (ctx)
+       if (ctx) {
+               aa_put_label(rcu_access_pointer(ctx->label));
                kzfree(ctx);
+       }
+}
+
+static inline struct aa_label *aa_get_file_label(struct aa_file_ctx *ctx)
+{
+       return aa_get_label_rcu(&ctx->label);
 }
 
 /*
@@ -183,7 +196,7 @@ int aa_path_perm(const char *op, struct aa_profile *profile,
 int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
                 const struct path *new_dir, struct dentry *new_dentry);
 
-int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file,
+int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
                 u32 request);
 
 void aa_inherit_files(const struct cred *cred, struct files_struct *files);
index bf28b48..011fbb0 100644 (file)
@@ -433,7 +433,7 @@ static int apparmor_file_alloc_security(struct file *file)
 
        /* freed by apparmor_file_free_security */
        struct aa_label *label = begin_current_label_crit_section();
-       file->f_security = aa_alloc_file_ctx(GFP_KERNEL);
+       file->f_security = aa_alloc_file_ctx(label, GFP_KERNEL);
        if (!file_ctx(file))
                error = -ENOMEM;
        end_current_label_crit_section(label);
@@ -448,33 +448,15 @@ static void apparmor_file_free_security(struct file *file)
 
 static int common_file_perm(const char *op, struct file *file, u32 mask)
 {
-       struct aa_file_ctx *fctx = file->f_security;
-       struct aa_label *label, *flabel;
+       struct aa_label *label;
        int error = 0;
 
        /* don't reaudit files closed during inheritance */
        if (file->f_path.dentry == aa_null.dentry)
                return -EACCES;
 
-       flabel = aa_cred_raw_label(file->f_cred);
-       AA_BUG(!flabel);
-
-       if (!file->f_path.mnt ||
-           !path_mediated_fs(file->f_path.dentry))
-               return 0;
-
        label = __begin_current_label_crit_section();
-
-       /* revalidate access, if task is unconfined, or the cached cred
-        * doesn't match or if the request is for more permissions than
-        * was granted.
-        *
-        * Note: the test for !unconfined(fprofile) is to handle file
-        *       delegation from unconfined tasks
-        */
-       if (!unconfined(label) && !unconfined(flabel) &&
-           ((flabel != label) || (mask & ~fctx->allow)))
-               error = aa_file_perm(op, labels_profile(label), file, mask);
+       error = aa_file_perm(op, label, file, mask);
        __end_current_label_crit_section(label);
 
        return error;