apparmor: refactor path name lookup and permission checks around labels
authorJohn Johansen <john.johansen@canonical.com>
Fri, 9 Jun 2017 23:02:25 +0000 (16:02 -0700)
committerJohn Johansen <john.johansen@canonical.com>
Sun, 11 Jun 2017 00:11:43 +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 a40bc1e276dcef897049b21995d7f82b16096c61..1b216f889131225105a800579d30ecc342bafb0a 100644 (file)
@@ -152,6 +152,39 @@ int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms,
        return aa_audit(type, profile, &sa, file_audit_cb);
 }
 
+/**
+ * is_deleted - test if a file has been completely unlinked
+ * @dentry: dentry of file to test for deletion  (NOT NULL)
+ *
+ * Returns: %1 if deleted else %0
+ */
+static inline bool is_deleted(struct dentry *dentry)
+{
+       if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0)
+               return 1;
+       return 0;
+}
+
+static int path_name(const char *op, struct aa_label *label,
+                    const struct path *path, int flags, char *buffer,
+                    const char **name, struct path_cond *cond, u32 request)
+{
+       struct aa_profile *profile;
+       const char *info = NULL;
+       int error;
+
+       error = aa_path_name(path, flags, buffer, name, &info,
+                            labels_profile(label)->disconnected);
+       if (error) {
+               fn_for_each_confined(label, profile,
+                       aa_audit_file(profile, &nullperms, op, request, *name,
+                                     NULL, NULL, cond->uid, info, error));
+               return error;
+       }
+
+       return 0;
+}
+
 /**
  * map_old_perms - map old file perms layout to the new layout
  * @old: permission set in old mapping
@@ -249,23 +282,46 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
        return state;
 }
 
-/**
- * is_deleted - test if a file has been completely unlinked
- * @dentry: dentry of file to test for deletion  (NOT NULL)
- *
- * Returns: %1 if deleted else %0
- */
-static inline bool is_deleted(struct dentry *dentry)
+int __aa_path_perm(const char *op, struct aa_profile *profile, const char *name,
+                  u32 request, struct path_cond *cond, int flags,
+                  struct aa_perms *perms)
 {
-       if (d_unlinked(dentry) && d_backing_inode(dentry)->i_nlink == 0)
-               return 1;
-       return 0;
+       int e = 0;
+
+       if (profile_unconfined(profile))
+               return 0;
+       aa_str_perms(profile->file.dfa, profile->file.start, name, cond, perms);
+       if (request & ~perms->allow)
+               e = -EACCES;
+       return aa_audit_file(profile, perms, op, request, name, NULL, NULL,
+                            cond->uid, NULL, e);
+}
+
+
+static int profile_path_perm(const char *op, struct aa_profile *profile,
+                            const struct path *path, char *buffer, u32 request,
+                            struct path_cond *cond, int flags,
+                            struct aa_perms *perms)
+{
+       const char *name;
+       int error;
+
+       if (profile_unconfined(profile))
+               return 0;
+
+       error = path_name(op, &profile->label, path,
+                         flags | profile->path_flags, buffer, &name, cond,
+                         request);
+       if (error)
+               return error;
+       return __aa_path_perm(op, profile, name, request, cond, flags,
+                             perms);
 }
 
 /**
  * aa_path_perm - do permissions check & audit for @path
  * @op: operation being checked
- * @profile: profile being enforced  (NOT NULL)
+ * @label: profile being enforced  (NOT NULL)
  * @path: path to check permissions of  (NOT NULL)
  * @flags: any additional path flags beyond what the profile specifies
  * @request: requested permissions
@@ -273,36 +329,22 @@ static inline bool is_deleted(struct dentry *dentry)
  *
  * Returns: %0 else error if access denied or other error
  */
-int aa_path_perm(const char *op, struct aa_profile *profile,
+int aa_path_perm(const char *op, struct aa_label *label,
                 const struct path *path, int flags, u32 request,
                 struct path_cond *cond)
 {
-       char *buffer = NULL;
        struct aa_perms perms = {};
-       const char *name, *info = NULL;
+       struct aa_profile *profile;
+       char *buffer = NULL;
        int error;
 
-       flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
+       flags |= PATH_DELEGATE_DELETED | (S_ISDIR(cond->mode) ? PATH_IS_DIR :
+                                                               0);
        get_buffers(buffer);
-       error = aa_path_name(path, flags, buffer, &name, &info,
-                            profile->disconnected);
-       if (error) {
-               if (error == -ENOENT && is_deleted(path->dentry)) {
-                       /* Access to open files that are deleted are
-                        * give a pass (implicit delegation)
-                        */
-                       error = 0;
-                       info = NULL;
-                       perms.allow = request;
-               }
-       } else {
-               aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
-                            &perms);
-               if (request & ~perms.allow)
-                       error = -EACCES;
-       }
-       error = aa_audit_file(profile, &perms, op, request, name, NULL, NULL,
-                             cond->uid, info, error);
+       error = fn_for_each_confined(label, profile,
+                       profile_path_perm(op, profile, path, buffer, request,
+                                         cond, flags, &perms));
+
        put_buffers(buffer);
 
        return error;
@@ -482,7 +524,7 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file,
        /* 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,
+               error = aa_path_perm(op, label, &file->f_path,
                                     PATH_DELEGATE_DELETED, request, &cond);
 
 done:
index 7c6026460272f931a899a9a22f796815023c8792..8daad14c47fdc38da9c3bc261954f9d9dbc701c2 100644 (file)
@@ -190,7 +190,10 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start,
                          const char *name, struct path_cond *cond,
                          struct aa_perms *perms);
 
-int aa_path_perm(const char *op, struct aa_profile *profile,
+int __aa_path_perm(const char *op, struct aa_profile *profile,
+                  const char *name, u32 request, struct path_cond *cond,
+                  int flags, struct aa_perms *perms);
+int aa_path_perm(const char *op, struct aa_label *label,
                 const struct path *path, int flags, u32 request,
                 struct path_cond *cond);
 
index 011fbb0096635ab1d0ba6c8958d8b671f9847a3b..d0c5721aa8b3ab1cb1cf5cf8f478ce5eac31d0f5 100644 (file)
@@ -196,8 +196,7 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
 
        label = __begin_current_label_crit_section();
        if (!unconfined(label))
-               error = aa_path_perm(op, labels_profile(label), path, 0, mask,
-                                    cond);
+               error = aa_path_perm(op, label, path, 0, mask, cond);
        __end_current_label_crit_section(label);
 
        return error;
@@ -359,15 +358,12 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
                                          d_backing_inode(old_dentry)->i_mode
                };
 
-               error = aa_path_perm(OP_RENAME_SRC, labels_profile(label),
-                                    &old_path, 0,
+               error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0,
                                     MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
                                     AA_MAY_SETATTR | AA_MAY_DELETE,
                                     &cond);
                if (!error)
-                       error = aa_path_perm(OP_RENAME_DEST,
-                                            labels_profile(label),
-                                            &new_path,
+                       error = aa_path_perm(OP_RENAME_DEST, label, &new_path,
                                             0, MAY_WRITE | AA_MAY_SETATTR |
                                             AA_MAY_CREATE, &cond);
 
@@ -416,8 +412,7 @@ static int apparmor_file_open(struct file *file, const struct cred *cred)
                struct inode *inode = file_inode(file);
                struct path_cond cond = { inode->i_uid, inode->i_mode };
 
-               error = aa_path_perm(OP_OPEN, labels_profile(label),
-                                    &file->f_path, 0,
+               error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
                                     aa_map_file_to_perms(file), &cond);
                /* todo cache full allowed permissions set and state */
                fctx->allow = aa_map_file_to_perms(file);