Blob Blame History Raw
From 76c7d634246759381c5d558769bbc02cedc35f7f Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Fri, 9 Jun 2017 16:19:02 -0700
Subject: [PATCH 56/65] apparmor: rework file permission to cache file access
 in file->ctx
Git-commit: 496c93196654d3e604013d750b7047886af14506
Patch-mainline: v4.13-rc1
References: FATE#323500

This is a temporary step, towards using the file->ctx for delegation,
and also helps speed up file queries, until the permission lookup
cache is introduced.

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
---
 security/apparmor/file.c | 82 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 76 insertions(+), 6 deletions(-)

diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index eb4c3006af67..b6e8e5b11e05 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -492,6 +492,80 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
 	return error;
 }
 
+static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label,
+			    u32 request)
+{
+	struct aa_label *l, *old;
+
+	/* update caching of label on file_ctx */
+	spin_lock(&fctx->lock);
+	old = rcu_dereference_protected(fctx->label,
+					spin_is_locked(&fctx->lock));
+	l = aa_label_merge(old, label, GFP_ATOMIC);
+	if (l) {
+		if (l != old) {
+			rcu_assign_pointer(fctx->label, l);
+			aa_put_label(old);
+		} else
+			aa_put_label(l);
+		fctx->allow |= request;
+	}
+	spin_unlock(&fctx->lock);
+}
+
+static int __file_path_perm(const char *op, struct aa_label *label,
+			    struct aa_label *flabel, struct file *file,
+			    u32 request, u32 denied)
+{
+	struct aa_profile *profile;
+	struct aa_perms perms = {};
+	struct path_cond cond = {
+		.uid = file_inode(file)->i_uid,
+		.mode = file_inode(file)->i_mode
+	};
+	char *buffer;
+	int flags, error;
+
+	/* revalidation due to label out of date. No revocation at this time */
+	if (!denied && aa_label_is_subset(flabel, label))
+		/* TODO: check for revocation on stale profiles */
+		return 0;
+
+	flags = PATH_DELEGATE_DELETED | (S_ISDIR(cond.mode) ? PATH_IS_DIR : 0);
+	get_buffers(buffer);
+
+	/* check every profile in task label not in current cache */
+	error = fn_for_each_not_in_set(flabel, label, profile,
+			profile_path_perm(op, profile, &file->f_path, buffer,
+					  request, &cond, flags, &perms));
+	if (denied && !error) {
+		/*
+		 * check every profile in file label that was not tested
+		 * in the initial check above.
+		 *
+		 * TODO: cache full perms so this only happens because of
+		 * conditionals
+		 * TODO: don't audit here
+		 */
+		if (label == flabel)
+			error = fn_for_each(label, profile,
+				profile_path_perm(op, profile, &file->f_path,
+						  buffer, request, &cond, flags,
+						  &perms));
+		else
+			error = fn_for_each_not_in_set(label, flabel, profile,
+				profile_path_perm(op, profile, &file->f_path,
+						  buffer, request, &cond, flags,
+						  &perms));
+	}
+	if (!error)
+		update_file_ctx(file_ctx(file), label, request);
+
+	put_buffers(buffer);
+
+	return error;
+}
+
 /**
  * aa_file_perm - do permission revalidation check & audit for @file
  * @op: operation being checked
@@ -504,10 +578,6 @@ int aa_path_link(struct aa_label *label, struct dentry *old_dentry,
 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;
@@ -537,8 +607,8 @@ 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, label, &file->f_path,
-				     PATH_DELEGATE_DELETED, request, &cond);
+		error = __file_path_perm(op, label, flabel, file, request,
+					 denied);
 
 done:
 	rcu_read_unlock();
-- 
2.12.3