From 8014370f1257619226b79cb6de8e28563fbbc070 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 9 Jun 2017 16:06:21 -0700 Subject: [PATCH] apparmor: move path_link mediation to using labels Signed-off-by: John Johansen --- security/apparmor/file.c | 101 +++++++++++++++++-------------- security/apparmor/include/file.h | 2 +- security/apparmor/lsm.c | 3 +- 3 files changed, 59 insertions(+), 47 deletions(-) diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 1b216f889131..eb4c3006af67 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -370,66 +370,40 @@ static inline bool xindex_is_subset(u32 link, u32 target) return 1; } -/** - * aa_path_link - Handle hard link permission check - * @profile: the profile 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) - * - * Handle the permission test for a link & target pair. Permission - * is encoded as a pair where the link permission is determined - * first, and if allowed, the target is tested. The target test - * is done from the point of the link match (not start of DFA) - * making the target permission dependent on the link permission match. - * - * The subset test if required forces that permissions granted - * on link are a subset of the permission granted to target. - * - * Returns: %0 if allowed else error - */ -int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, - const struct path *new_dir, struct dentry *new_dentry) +static int profile_path_link(struct aa_profile *profile, + const struct path *link, char *buffer, + const struct path *target, char *buffer2, + struct path_cond *cond) { - struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry }; - struct path target = { .mnt = new_dir->mnt, .dentry = old_dentry }; - struct path_cond cond = { - d_backing_inode(old_dentry)->i_uid, - d_backing_inode(old_dentry)->i_mode - }; - char *buffer = NULL, *buffer2 = NULL; - const char *lname, *tname = NULL, *info = NULL; - struct aa_perms lperms, perms; + const char *lname, *tname = NULL; + struct aa_perms lperms = {}, perms; + const char *info = NULL; u32 request = AA_MAY_LINK; unsigned int state; int error; - get_buffers(buffer, buffer2); - lperms = nullperms; - - /* buffer freed below, lname is pointer in buffer */ - error = aa_path_name(&link, profile->path_flags, buffer, &lname, - &info, profile->disconnected); + error = path_name(OP_LINK, &profile->label, link, profile->path_flags, + buffer, &lname, cond, AA_MAY_LINK); if (error) goto audit; /* buffer2 freed below, tname is pointer in buffer2 */ - error = aa_path_name(&target, profile->path_flags, buffer2, &tname, - &info, profile->disconnected); + error = path_name(OP_LINK, &profile->label, target, profile->path_flags, + buffer2, &tname, cond, AA_MAY_LINK); if (error) goto audit; 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); + cond, &lperms); if (!(lperms.allow & AA_MAY_LINK)) goto audit; /* 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); + aa_str_perms(profile->file.dfa, state, tname, cond, &perms); /* force audit/quiet masks for link are stored in the second entry * in the link pair. @@ -440,6 +414,7 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, if (!(perms.allow & AA_MAY_LINK)) { info = "target restricted"; + lperms = perms; goto audit; } @@ -447,10 +422,10 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, 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. + /* 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, + aa_str_perms(profile->file.dfa, profile->file.start, tname, cond, &perms); /* AA_MAY_LINK is not considered in the subset test */ @@ -472,8 +447,46 @@ done_tests: error = 0; audit: - error = aa_audit_file(profile, &lperms, OP_LINK, request, - lname, tname, NULL, cond.uid, info, error); + return aa_audit_file(profile, &lperms, OP_LINK, request, lname, tname, + NULL, cond->uid, info, error); +} + +/** + * aa_path_link - Handle hard link permission check + * @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) + * + * Handle the permission test for a link & target pair. Permission + * is encoded as a pair where the link permission is determined + * first, and if allowed, the target is tested. The target test + * is done from the point of the link match (not start of DFA) + * making the target permission dependent on the link permission match. + * + * The subset test if required forces that permissions granted + * on link are a subset of the permission granted to target. + * + * Returns: %0 if allowed else error + */ +int aa_path_link(struct aa_label *label, struct dentry *old_dentry, + const struct path *new_dir, struct dentry *new_dentry) +{ + struct path link = { new_dir->mnt, new_dentry }; + struct path target = { new_dir->mnt, old_dentry }; + struct path_cond cond = { + d_backing_inode(old_dentry)->i_uid, + d_backing_inode(old_dentry)->i_mode + }; + char *buffer = NULL, *buffer2 = NULL; + struct aa_profile *profile; + int error; + + /* buffer freed below, lname is pointer in buffer */ + get_buffers(buffer, buffer2); + error = fn_for_each_confined(label, profile, + profile_path_link(profile, &link, buffer, &target, + buffer2, &cond)); put_buffers(buffer, buffer2); return error; diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 8daad14c47fd..001e40073ff9 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -197,7 +197,7 @@ int aa_path_perm(const char *op, struct aa_label *label, const 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, const struct path *new_dir, struct dentry *new_dentry); int aa_file_perm(const char *op, struct aa_label *label, struct file *file, diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index d0c5721aa8b3..7a986763b2b7 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -332,8 +332,7 @@ static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_ label = begin_current_label_crit_section(); 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); end_current_label_crit_section(label); return error; -- 2.20.1