summaryrefslogtreecommitdiffstats
path: root/security/apparmor
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-06-09 16:02:25 -0700
committerJohn Johansen <john.johansen@canonical.com>2017-06-10 17:11:43 -0700
commitaebd873e8d3e34757c9295eef074d1be229f5893 (patch)
treee4655a4726e7ce1ce878bbbccc80cf5fa5b33f22 /security/apparmor
parent98c3d182321d489d8bfaa596127020ec3027edb2 (diff)
downloadlinux-aebd873e8d3e34757c9295eef074d1be229f5893.tar.bz2
apparmor: refactor path name lookup and permission checks around labels
Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor')
-rw-r--r--security/apparmor/file.c112
-rw-r--r--security/apparmor/include/file.h5
-rw-r--r--security/apparmor/lsm.c13
3 files changed, 85 insertions, 45 deletions
diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index a40bc1e276dc..1b216f889131 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -153,6 +153,39 @@ int aa_audit_file(struct aa_profile *profile, struct aa_perms *perms,
}
/**
+ * 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:
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index 7c6026460272..8daad14c47fd 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -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);
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 011fbb009663..d0c5721aa8b3 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -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);