Blob Blame History Raw
From 9377e727c8045a58dee38ff817029e2a3627363e Mon Sep 17 00:00:00 2001
From: John Johansen <john.johansen@canonical.com>
Date: Mon, 29 May 2017 12:16:04 -0700
Subject: [PATCH 26/65] apparmor: add gerneric permissions struct and support
 fns
Git-commit: aa9aeea8d4c3dfb9297723c4340671ef88e372d3
Patch-mainline: v4.13-rc1
References: FATE#323500

Signed-off-by: John Johansen <john.johansen@canonical.com>
Acked-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
---
 security/apparmor/file.c          |  30 +++++------
 security/apparmor/include/audit.h |   4 +-
 security/apparmor/include/perms.h |  34 +++++++++++++
 security/apparmor/lib.c           | 102 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 153 insertions(+), 17 deletions(-)

diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 44549db904b3..1ee656f66aa4 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -56,15 +56,15 @@ static void file_audit_cb(struct audit_buffer *ab, void *va)
 	struct common_audit_data *sa = va;
 	kuid_t fsuid = current_fsuid();
 
-	if (aad(sa)->fs.request & AA_AUDIT_FILE_MASK) {
+	if (aad(sa)->request & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " requested_mask=");
-		audit_file_mask(ab, aad(sa)->fs.request);
+		audit_file_mask(ab, aad(sa)->request);
 	}
-	if (aad(sa)->fs.denied & AA_AUDIT_FILE_MASK) {
+	if (aad(sa)->denied & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " denied_mask=");
-		audit_file_mask(ab, aad(sa)->fs.denied);
+		audit_file_mask(ab, aad(sa)->denied);
 	}
-	if (aad(sa)->fs.request & AA_AUDIT_FILE_MASK) {
+	if (aad(sa)->request & AA_AUDIT_FILE_MASK) {
 		audit_log_format(ab, " fsuid=%d",
 				 from_kuid(&init_user_ns, fsuid));
 		audit_log_format(ab, " ouid=%d",
@@ -100,7 +100,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
 	DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_TASK, op);
 
 	sa.u.tsk = NULL;
-	aad(&sa)->fs.request = request;
+	aad(&sa)->request = request;
 	aad(&sa)->name = name;
 	aad(&sa)->fs.target = target;
 	aad(&sa)->fs.ouid = ouid;
@@ -115,30 +115,30 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
 			mask = 0xffff;
 
 		/* mask off perms that are not being force audited */
-		aad(&sa)->fs.request &= mask;
+		aad(&sa)->request &= mask;
 
-		if (likely(!aad(&sa)->fs.request))
+		if (likely(!aad(&sa)->request))
 			return 0;
 		type = AUDIT_APPARMOR_AUDIT;
 	} else {
 		/* only report permissions that were denied */
-		aad(&sa)->fs.request = aad(&sa)->fs.request & ~perms->allow;
-		AA_BUG(!aad(&sa)->fs.request);
+		aad(&sa)->request = aad(&sa)->request & ~perms->allow;
+		AA_BUG(!aad(&sa)->request);
 
-		if (aad(&sa)->fs.request & perms->kill)
+		if (aad(&sa)->request & perms->kill)
 			type = AUDIT_APPARMOR_KILL;
 
 		/* quiet known rejects, assumes quiet and kill do not overlap */
-		if ((aad(&sa)->fs.request & perms->quiet) &&
+		if ((aad(&sa)->request & perms->quiet) &&
 		    AUDIT_MODE(profile) != AUDIT_NOQUIET &&
 		    AUDIT_MODE(profile) != AUDIT_ALL)
-			aad(&sa)->fs.request &= ~perms->quiet;
+			aad(&sa)->request &= ~perms->quiet;
 
-		if (!aad(&sa)->fs.request)
+		if (!aad(&sa)->request)
 			return COMPLAIN_MODE(profile) ? 0 : aad(&sa)->error;
 	}
 
-	aad(&sa)->fs.denied = aad(&sa)->fs.request & ~perms->allow;
+	aad(&sa)->denied = aad(&sa)->request & ~perms->allow;
 	return aa_audit(type, profile, &sa, file_audit_cb);
 }
 
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
index fdc4774318ba..1aeb8550fb82 100644
--- a/security/apparmor/include/audit.h
+++ b/security/apparmor/include/audit.h
@@ -107,14 +107,14 @@ struct apparmor_audit_data {
 	void *profile;
 	const char *name;
 	const char *info;
+	u32 request;
+	u32 denied;
 	union {
 		/* these entries require a custom callback fn */
 		struct {
 			struct aa_profile *peer;
 			struct {
 				const char *target;
-				u32 request;
-				u32 denied;
 				kuid_t ouid;
 			} fs;
 		};
diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h
index 35e365e7aa75..6ef23212bd66 100644
--- a/security/apparmor/include/perms.h
+++ b/security/apparmor/include/perms.h
@@ -66,6 +66,40 @@
 extern const char aa_file_perm_chrs[];
 extern const char *aa_file_perm_names[];
 
+struct aa_perms {
+	u32 allow;
+	u32 audit;	/* set only when allow is set */
+
+	u32 deny;	/* explicit deny, or conflict if allow also set */
+	u32 quiet;	/* set only when ~allow | deny */
+	u32 kill;	/* set only when ~allow | deny */
+	u32 stop;	/* set only when ~allow | deny */
+
+	u32 complain;	/* accumulates only used when ~allow & ~deny */
+	u32 cond;	/* set only when ~allow and ~deny */
+
+	u32 hide;	/* set only when  ~allow | deny */
+	u32 prompt;	/* accumulates only used when ~allow & ~deny */
+
+	/* Reserved:
+	 * u32 subtree;	/ * set only when allow is set * /
+	 */
+	u16 xindex;
+};
+
+#define ALL_PERMS_MASK 0xffffffff
+
+extern struct aa_perms allperms;
+
+struct aa_profile;
+
 void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask);
+void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask);
+void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
+			u32 chrsmask, const char **names, u32 namesmask);
+void aa_apply_modes_to_perms(struct aa_profile *profile,
+			     struct aa_perms *perms);
+void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
+		      struct aa_perms *perms);
 
 #endif /* __AA_PERM_H */
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c
index 90d4631ddafe..a50913744823 100644
--- a/security/apparmor/lib.c
+++ b/security/apparmor/lib.c
@@ -24,6 +24,10 @@
 #include "include/perms.h"
 #include "include/policy.h"
 
+struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
+			     .quiet = ALL_PERMS_MASK,
+			     .hide = ALL_PERMS_MASK };
+
 /**
  * aa_split_fqname - split a fqname into a profile and namespace name
  * @fqname: a full qualified name in namespace profile format (NOT NULL)
@@ -188,6 +192,104 @@ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
 	*str = '\0';
 }
 
+void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
+{
+	const char *fmt = "%s";
+	unsigned int i, perm = 1;
+	bool prev = false;
+
+	for (i = 0; i < 32; perm <<= 1, i++) {
+		if (mask & perm) {
+			audit_log_format(ab, fmt, names[i]);
+			if (!prev) {
+				prev = true;
+				fmt = " %s";
+			}
+		}
+	}
+}
+
+void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
+			u32 chrsmask, const char **names, u32 namesmask)
+{
+	char str[33];
+
+	audit_log_format(ab, "\"");
+	if ((mask & chrsmask) && chrs) {
+		aa_perm_mask_to_str(str, chrs, mask & chrsmask);
+		mask &= ~chrsmask;
+		audit_log_format(ab, "%s", str);
+		if (mask & namesmask)
+			audit_log_format(ab, " ");
+	}
+	if ((mask & namesmask) && names)
+		aa_audit_perm_names(ab, names, mask & namesmask);
+	audit_log_format(ab, "\"");
+}
+
+/**
+ * aa_apply_modes_to_perms - apply namespace and profile flags to perms
+ * @profile: that perms where computed from
+ * @perms: perms to apply mode modifiers to
+ *
+ * TODO: split into profile and ns based flags for when accumulating perms
+ */
+void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
+{
+	switch (AUDIT_MODE(profile)) {
+	case AUDIT_ALL:
+		perms->audit = ALL_PERMS_MASK;
+		/* fall through */
+	case AUDIT_NOQUIET:
+		perms->quiet = 0;
+		break;
+	case AUDIT_QUIET:
+		perms->audit = 0;
+		/* fall through */
+	case AUDIT_QUIET_DENIED:
+		perms->quiet = ALL_PERMS_MASK;
+		break;
+	}
+
+	if (KILL_MODE(profile))
+		perms->kill = ALL_PERMS_MASK;
+	else if (COMPLAIN_MODE(profile))
+		perms->complain = ALL_PERMS_MASK;
+/*
+ *  TODO:
+ *	else if (PROMPT_MODE(profile))
+ *		perms->prompt = ALL_PERMS_MASK;
+ */
+}
+
+static u32 map_other(u32 x)
+{
+	return ((x & 0x3) << 8) |	/* SETATTR/GETATTR */
+		((x & 0x1c) << 18) |	/* ACCEPT/BIND/LISTEN */
+		((x & 0x60) << 19);	/* SETOPT/GETOPT */
+}
+
+void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
+		      struct aa_perms *perms)
+{
+	perms->deny = 0;
+	perms->kill = perms->stop = 0;
+	perms->complain = perms->cond = 0;
+	perms->hide = 0;
+	perms->prompt = 0;
+	perms->allow = dfa_user_allow(dfa, state);
+	perms->audit = dfa_user_audit(dfa, state);
+	perms->quiet = dfa_user_quiet(dfa, state);
+
+	/* for v5 perm mapping in the policydb, the other set is used
+	 * to extend the general perm set
+	 */
+	perms->allow |= map_other(dfa_other_allow(dfa, state));
+	perms->audit |= map_other(dfa_other_audit(dfa, state));
+	perms->quiet |= map_other(dfa_other_quiet(dfa, state));
+//	perms->xindex = dfa_user_xindex(dfa, state);
+}
+
 /**
  * aa_policy_init - initialize a policy structure
  * @policy: policy to initialize  (NOT NULL)
-- 
2.12.3