next baby step to labels. Update most code to walk labels as if there
is multiple entries in a label, even though atm there can only be
one.

This does not update the domain transitions, exec, change_hat, change_profile
(separate patch).

Also it bails on first error, where for learning purposes it might be
desireable to check permission, and log against all profiles before failing.

Signed-off-by: John Johansen <[email protected]>
---
 security/apparmor/file.c         | 167 ++++++++++++++++++++++++---------------
 security/apparmor/include/file.h |   7 +-
 security/apparmor/ipc.c          |  22 ++++--
 security/apparmor/lsm.c          |  48 +++++++----
 security/apparmor/resource.c     |  62 +++++++++------
 5 files changed, 193 insertions(+), 113 deletions(-)

diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index cd21ec5..15847fb 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -267,7 +267,7 @@ static inline bool is_deleted(struct dentry *dentry)
 /**
  * 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
@@ -275,15 +275,17 @@ static inline bool is_deleted(struct dentry *dentry)
  *
  * Returns: %0 else error if access denied or other error
  */
-int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
+int aa_path_perm(int op, struct aa_label *label, struct path *path,
                 int flags, u32 request, struct path_cond *cond)
 {
        char *buffer = NULL;
        struct file_perms perms = {};
        const char *name, *info = NULL;
-       int error;
+       struct aa_profile *profile;
+       int i, error;
 
-       flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0);
+       /* TODO: fix path lookup flags */
+       flags |= labels_profile(label)->path_flags | (S_ISDIR(cond->mode) ? 
PATH_IS_DIR : 0);
        error = aa_path_name(path, flags, &buffer, &name, &info);
        if (error) {
                if (error == -ENOENT && is_deleted(path->dentry)) {
@@ -294,14 +296,29 @@ int aa_path_perm(int op, struct aa_profile *profile, 
struct path *path,
                        info = NULL;
                        perms.allow = request;
                }
-       } else {
+
+               label_for_each_confined(i, label, profile) {
+                       error = aa_audit_file(profile, &perms, GFP_KERNEL,
+                                             op, request, name, NULL,
+                                             cond->uid, info, error);
+                       if (error)
+                               break;
+               }
+               goto out;
+       }
+
+       label_for_each_confined(i, label, profile) {
                aa_str_perms(profile->file.dfa, profile->file.start, name, cond,
                             &perms);
                if (request & ~perms.allow)
                        error = -EACCES;
+               error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request,
+                                     name, NULL, cond->uid, info, error);
+               if (error)
+                       break;
        }
-       error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name,
-                             NULL, cond->uid, info, error);
+
+out:
        kfree(buffer);
 
        return error;
@@ -329,7 +346,7 @@ static inline bool xindex_is_subset(u32 link, u32 target)
 
 /**
  * aa_path_link - Handle hard link permission check
- * @profile: the profile being enforced  (NOT NULL)
+ * @label: the label being enforced  (NOT NULL)
  * @old_dentry: the target dentry  (NOT NULL)
  * @new_dir: directory the new link will be created in  (NOT NULL)
  * @new_dentry: the link being created  (NOT NULL)
@@ -345,7 +362,7 @@ static inline bool xindex_is_subset(u32 link, u32 target)
  *
  * Returns: %0 if allowed else error
  */
-int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
                 struct path *new_dir, struct dentry *new_dentry)
 {
        struct path link = { new_dir->mnt, new_dentry };
@@ -359,93 +376,115 @@ int aa_path_link(struct aa_profile *profile, struct 
dentry *old_dentry,
        struct file_perms lperms, perms;
        u32 request = AA_MAY_LINK;
        unsigned int state;
-       int error;
+       struct aa_profile *profile;
+       int i, error;
 
        lperms = nullperms;
 
+       /* TODO: fix path lookup flags, auditing of failed path for profile */
+       profile = labels_profile(label);
        /* buffer freed below, lname is pointer in buffer */
-       error = aa_path_name(&link, profile->path_flags, &buffer, &lname,
+       error = aa_path_name(&link, labels_profile(label)->path_flags, &buffer, 
&lname,
                             &info);
        if (error)
-               goto audit;
+               goto err;
 
        /* buffer2 freed below, tname is pointer in buffer2 */
-       error = aa_path_name(&target, profile->path_flags, &buffer2, &tname,
+       error = aa_path_name(&target, labels_profile(label)->path_flags, 
&buffer2, &tname,
                             &info);
        if (error)
-               goto audit;
+               goto err;
 
-       error = -EACCES;
-       /* aa_str_perms - handles the case of the dfa being NULL */
-       state = aa_str_perms(profile->file.dfa, profile->file.start, lname,
-                            &cond, &lperms);
 
-       if (!(lperms.allow & AA_MAY_LINK))
-               goto audit;
+       label_for_each_confined(i, label, profile) {
+               error = -EACCES;
+               /* aa_str_perms - handles the case of the dfa being NULL */
+               state = aa_str_perms(profile->file.dfa, profile->file.start,
+                                    lname, &cond, &lperms);
 
-       /* test to see if target can be paired with link */
-       state = aa_dfa_null_transition(profile->file.dfa, state);
-       aa_str_perms(profile->file.dfa, state, tname, &cond, &perms);
+               if (!(lperms.allow & AA_MAY_LINK))
+                       goto audit;
 
-       /* force audit/quiet masks for link are stored in the second entry
-        * in the link pair.
-        */
-       lperms.audit = perms.audit;
-       lperms.quiet = perms.quiet;
-       lperms.kill = perms.kill;
+               /* test to see if target can be paired with link */
+               state = aa_dfa_null_transition(profile->file.dfa, state);
+               aa_str_perms(profile->file.dfa, state, tname, &cond, &perms);
 
-       if (!(perms.allow & AA_MAY_LINK)) {
-               info = "target restricted";
-               goto audit;
-       }
+               /* force audit/quiet masks for link are stored in the second
+                * entry in the link pair.
+                */
+               lperms.audit = perms.audit;
+               lperms.quiet = perms.quiet;
+               lperms.kill = perms.kill;
 
-       /* done if link subset test is not required */
-       if (!(perms.allow & AA_LINK_SUBSET))
-               goto done_tests;
+               if (!(perms.allow & AA_MAY_LINK)) {
+                       info = "target restricted";
+                       goto audit;
+               }
 
-       /* Do link perm subset test requiring allowed permission on link are a
-        * subset of the allowed permissions on target.
-        */
-       aa_str_perms(profile->file.dfa, profile->file.start, tname, &cond,
-                    &perms);
-
-       /* AA_MAY_LINK is not considered in the subset test */
-       request = lperms.allow & ~AA_MAY_LINK;
-       lperms.allow &= perms.allow | AA_MAY_LINK;
-
-       request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow);
-       if (request & ~lperms.allow) {
-               goto audit;
-       } else if ((lperms.allow & MAY_EXEC) &&
-                  !xindex_is_subset(lperms.xindex, perms.xindex)) {
-               lperms.allow &= ~MAY_EXEC;
-               request |= MAY_EXEC;
-               info = "link not subset of target";
-               goto audit;
-       }
+               /* done if link subset test is not required */
+               if (!(perms.allow & AA_LINK_SUBSET))
+                       goto done_tests;
+
+               /* Do link perm subset test requiring allowed permission on
+                * link are a subset of the allowed permissions on target.
+                */
+               aa_str_perms(profile->file.dfa, profile->file.start, tname,
+                            &cond, &perms);
+
+               /* AA_MAY_LINK is not considered in the subset test */
+               request = lperms.allow & ~AA_MAY_LINK;
+               lperms.allow &= perms.allow | AA_MAY_LINK;
+
+               request |= AA_AUDIT_FILE_MASK & (lperms.allow & ~perms.allow);
+               if (request & ~lperms.allow) {
+                       goto audit;
+               } else if ((lperms.allow & MAY_EXEC) &&
+                          !xindex_is_subset(lperms.xindex, perms.xindex)) {
+                       lperms.allow &= ~MAY_EXEC;
+                       request |= MAY_EXEC;
+                       info = "link not subset of target";
+                       goto audit;
+               }
 
-done_tests:
-       error = 0;
+       done_tests:
+               error = 0;
 
-audit:
-       error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK, request,
-                             lname, tname, cond.uid, info, error);
+       audit:
+               error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK,
+                                     request, lname, tname, cond.uid, info,
+                                     error);
+               if (error)
+                       break;
+       }
+
+out:
        kfree(buffer);
        kfree(buffer2);
 
        return error;
+
+err:
+       label_for_each_confined(i, label, profile) {
+               error = aa_audit_file(profile, &lperms, GFP_KERNEL, OP_LINK,
+                                     request, lname, tname, cond.uid, info,
+                                     error);
+               if (error)
+                       break;
+       }
+
+       goto out;
 }
 
 /**
  * aa_file_perm - do permission revalidation check & audit for @file
  * @op: operation being checked
- * @profile: profile being enforced   (NOT NULL)
+ * @label: profile 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(int op, struct aa_profile *profile, struct file *file,
+int aa_file_perm(int op, struct aa_label *label, struct file *file,
                 u32 request)
 {
        struct path_cond cond = {
@@ -453,6 +492,6 @@ int aa_file_perm(int op, struct aa_profile *profile, struct 
file *file,
                .mode = file->f_path.dentry->d_inode->i_mode
        };
 
-       return aa_path_perm(op, profile, &file->f_path, PATH_DELEGATE_DELETED,
+       return aa_path_perm(op, label, &file->f_path, PATH_DELEGATE_DELETED,
                            request, &cond);
 }
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index 2c922b8..0b0c1ab 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -17,6 +17,7 @@
 
 #include "domain.h"
 #include "match.h"
+#include "label.h"
 
 struct aa_profile;
 struct path;
@@ -171,13 +172,13 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned 
int start,
                          const char *name, struct path_cond *cond,
                          struct file_perms *perms);
 
-int aa_path_perm(int op, struct aa_profile *profile, struct path *path,
+int aa_path_perm(int op, struct aa_label *label, struct path *path,
                 int flags, u32 request, struct path_cond *cond);
 
-int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry,
+int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
                 struct path *new_dir, struct dentry *new_dentry);
 
-int aa_file_perm(int op, struct aa_profile *profile, struct file *file,
+int aa_file_perm(int op, struct aa_label *label, struct file *file,
                 u32 request);
 
 static inline void aa_free_file_rules(struct aa_file_rules *rules)
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
index 364a76b..a780917 100644
--- a/security/apparmor/ipc.c
+++ b/security/apparmor/ipc.c
@@ -64,15 +64,25 @@ static int aa_audit_ptrace(struct aa_profile *profile,
 int aa_may_ptrace(struct task_struct *tracer_task, struct aa_label *tracer,
                  struct aa_label *tracee, unsigned int mode)
 {
-       /* TODO: currently only based on capability, not extended ptrace
-        *       rules,
-        *       Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
-        */
+       struct aa_profile *profile;
+       int i, error = 0;
 
        if (unconfined(tracer) || tracer == tracee)
                return 0;
-       /* log this capability request */
-       return aa_capable(tracer_task, labels_profile(tracer), CAP_SYS_PTRACE, 
1);
+
+       label_for_each_confined(i, tracer, profile) {
+               /* TODO: currently only based on capability, not extended ptrace
+                *       rules,
+                *       Test mode for PTRACE_MODE_READ || PTRACE_MODE_ATTACH
+                */
+
+               /* log this capability request */
+               error = aa_capable(tracer_task, profile, CAP_SYS_PTRACE, 1);
+               if (error)
+                       break;
+       }
+
+       return error;
 }
 
 /**
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index c4eb445..eb7bf2a 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -127,9 +127,17 @@ static int apparmor_capget(struct task_struct *target, 
kernel_cap_t *effective,
        *inheritable = cred->cap_inheritable;
        *permitted = cred->cap_permitted;
 
-       if (!unconfined(label) && !COMPLAIN_MODE(labels_profile(label))) {
-               *effective = cap_intersect(*effective, 
labels_profile(label)->caps.allow);
-               *permitted = cap_intersect(*permitted, 
labels_profile(label)->caps.allow);
+       if (!unconfined(label)) {
+               struct aa_profile *profile;
+               int i;
+               label_for_each_confined(i, label, profile) {
+                       if (COMPLAIN_MODE(profile))
+                               continue;
+                       *effective = cap_intersect(*effective,
+                                                  profile->caps.allow);
+                       *permitted = cap_intersect(*permitted,
+                                                  profile->caps.allow);
+               }
        }
        rcu_read_unlock();
 
@@ -139,14 +147,23 @@ static int apparmor_capget(struct task_struct *target, 
kernel_cap_t *effective,
 static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
                            int cap, int audit)
 {
+       struct aa_profile *profile;
        struct aa_label *label;
        /* cap_capable returns 0 on success, else -EPERM */
-       int error = cap_capable(cred, ns, cap, audit);
-       if (!error) {
-               label = aa_cred_label(cred);
-               if (!unconfined(label))
-                       error = aa_capable(current, labels_profile(label), cap, 
audit);
+       int i, error = cap_capable(cred, ns, cap, audit);
+       if (error)
+               return error;
+
+       label = aa_cred_label(cred);
+       if (unconfined(label))
+               return 0;
+
+       label_for_each_confined(i, label, profile) {
+               error = aa_capable(current, profile, cap, audit);
+               if (error)
+                       break;
        }
+
        return error;
 }
 
@@ -167,7 +184,7 @@ static int common_perm(int op, struct path *path, u32 mask,
 
        label = __aa_current_label();
        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);
 
        return error;
 }
@@ -310,7 +327,7 @@ static int apparmor_path_link(struct dentry *old_dentry, 
struct path *new_dir,
 
        label = aa_current_label();
        if (!unconfined(label))
-               error = aa_path_link(labels_profile(label), old_dentry, 
new_dir, new_dentry);
+               error = aa_path_link(label, old_dentry, new_dir, new_dentry);
        return error;
 }
 
@@ -331,12 +348,12 @@ static int apparmor_path_rename(struct path *old_dir, 
struct dentry *old_dentry,
                                          old_dentry->d_inode->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_META_READ | MAY_WRITE |
                                     AA_MAY_META_WRITE | 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_META_WRITE |
                                             AA_MAY_CREATE, &cond);
 
@@ -349,7 +366,8 @@ static int apparmor_path_chmod(struct path *path, umode_t 
mode)
        if (!mediated_filesystem(path->dentry->d_inode))
                return 0;
 
-       return common_perm_mnt_dentry(OP_CHMOD, path->mnt, path->dentry, 
AA_MAY_CHMOD);
+       return common_perm_mnt_dentry(OP_CHMOD, path->mnt, path->dentry,
+                                     AA_MAY_CHMOD);
 }
 
 static int apparmor_path_chown(struct path *path, kuid_t uid, kgid_t gid)
@@ -397,7 +415,7 @@ static int apparmor_file_open(struct file *file, const 
struct cred *cred)
                struct inode *inode = file->f_path.dentry->d_inode;
                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 */
                fcxt->allow = aa_map_file_to_perms(file);
@@ -446,7 +464,7 @@ static int common_file_perm(int op, struct file *file, u32 
mask)
         */
        if (!unconfined(label) && !unconfined(flabel) &&
            ((flabel != label) || (mask & ~fcxt->allow)))
-               error = aa_file_perm(op, labels_profile(label), file, mask);
+               error = aa_file_perm(op, label, file, mask);
 
        return error;
 }
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c
index e0a1d39..b9489c5 100644
--- a/security/apparmor/resource.c
+++ b/security/apparmor/resource.c
@@ -91,8 +91,9 @@ int aa_map_resource(int resource)
 int aa_task_setrlimit(struct aa_label *label, struct task_struct *task,
                      unsigned int resource, struct rlimit *new_rlim)
 {
+       struct aa_profile *profile;
        struct aa_label *task_label;
-       int error = 0;
+       int i, error = 0;
 
        rcu_read_lock();
        task_label = aa_get_label(aa_cred_label(__task_cred(task)));
@@ -103,14 +104,20 @@ int aa_task_setrlimit(struct aa_label *label, struct 
task_struct *task,
         * that the task is setting the resource of a task confined with
         * the same profile.
         */
-       if (label != task_label ||
-           (labels_profile(label)->rlimits.mask & (1 << resource) &&
-            new_rlim->rlim_max > 
labels_profile(label)->rlimits.limits[resource].rlim_max))
-               error = -EACCES;
 
+       label_for_each_confined(i, label, profile) {
+               if (label != task_label ||
+                   (profile->rlimits.mask & (1 << resource) &&
+                    new_rlim->rlim_max > 
profile->rlimits.limits[resource].rlim_max))
+                       error = -EACCES;
+               error = audit_resource(labels_profile(label), resource,
+                                      new_rlim->rlim_max, error);
+               if (error)
+                       break;
+       }
        aa_put_label(task_label);
 
-       return audit_resource(labels_profile(label), resource, 
new_rlim->rlim_max, error);
+       return error;
 }
 
 /**
@@ -128,31 +135,36 @@ void __aa_transition_rlimits(struct aa_label *old_l, 
struct aa_label *new_l)
        old = labels_profile(old_l);
        new = labels_profile(new_l);
 
-       /* for any rlimits the profile controlled reset the soft limit
-        * to the less of the tasks hard limit and the init tasks soft limit
+       /* for any rlimits the profile controlled, reset the soft limit
+        * to the lesser of the tasks hard limit and the init tasks soft limit
         */
-       if (old->rlimits.mask) {
-               for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
-                       if (old->rlimits.mask & mask) {
-                               rlim = current->signal->rlim + i;
-                               initrlim = init_task.signal->rlim + i;
-                               rlim->rlim_cur = min(rlim->rlim_max,
-                                                    initrlim->rlim_cur);
+       label_for_each_confined(i, old_l, old) {
+               if (old->rlimits.mask) {
+                       for (i = 0, mask = 1; i < RLIM_NLIMITS; i++,
+                                    mask <<= 1) {
+                               if (old->rlimits.mask & mask) {
+                                       rlim = current->signal->rlim + i;
+                                       initrlim = init_task.signal->rlim + i;
+                                       rlim->rlim_cur = min(rlim->rlim_max,
+                                                            
initrlim->rlim_cur);
+                               }
                        }
                }
        }
 
        /* set any new hard limits as dictated by the new profile */
-       if (!new->rlimits.mask)
-               return;
-       for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
-               if (!(new->rlimits.mask & mask))
+       label_for_each_confined(i, new_l, new) {
+               if (!new->rlimits.mask)
                        continue;
-
-               rlim = current->signal->rlim + i;
-               rlim->rlim_max = min(rlim->rlim_max,
-                                    new->rlimits.limits[i].rlim_max);
-               /* soft limit should not exceed hard limit */
-               rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
+               for (i = 0, mask = 1; i < RLIM_NLIMITS; i++, mask <<= 1) {
+                       if (!(new->rlimits.mask & mask))
+                               continue;
+
+                       rlim = current->signal->rlim + i;
+                       rlim->rlim_max = min(rlim->rlim_max,
+                                            new->rlimits.limits[i].rlim_max);
+                       /* soft limit should not exceed hard limit */
+                       rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
+               }
        }
 }
-- 
1.8.1.2


-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to