Skip to content
Snippets Groups Projects
0001-apparmor-patch-to-provide-compatibility-with-v2-net-rules.patch 7.71 KiB
Newer Older
Philip Müller's avatar
Philip Müller committed
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
index 66d0b4245ef6fd11ed1c59fea64e570de6de4015..a4ed6163c03737d90e64e50b4bc4c24c031e7799 100644
--- a/security/apparmor/apparmorfs.c
+++ b/security/apparmor/apparmorfs.c
@@ -2265,6 +2265,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
 	AA_SFS_DIR("domain",			aa_sfs_entry_domain),
 	AA_SFS_DIR("file",			aa_sfs_entry_file),
 	AA_SFS_DIR("network_v8",		aa_sfs_entry_network),
+	AA_SFS_DIR("network",			aa_sfs_entry_network_compat),
 	AA_SFS_DIR("mount",			aa_sfs_entry_mount),
 	AA_SFS_DIR("namespaces",		aa_sfs_entry_ns),
 	AA_SFS_FILE_U64("capability",		VFS_CAP_FLAGS_MASK),
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
index 6b7e6e13176ed4f11ff3cd43d17e004b977a5ed7..70de52565857845075dccd2fd5d27467b7d97329 100644
--- a/security/apparmor/include/apparmor.h
+++ b/security/apparmor/include/apparmor.h
@@ -20,7 +20,7 @@
 #define AA_CLASS_UNKNOWN	1
 #define AA_CLASS_FILE		2
 #define AA_CLASS_CAP		3
-#define AA_CLASS_DEPRECATED	4
+#define AA_CLASS_NET_COMPAT	4
 #define AA_CLASS_RLIMITS	5
 #define AA_CLASS_DOMAIN		6
 #define AA_CLASS_MOUNT		7
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
index 2431c011800dd012307630e1ce23ae3114479542..74768db9406656cb5ac080cd23d3a4faafd9e1ea 100644
--- a/security/apparmor/include/net.h
+++ b/security/apparmor/include/net.h
@@ -68,6 +68,16 @@ struct aa_sk_ctx {
 	DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type,	\
 			 (SK)->sk_protocol)
 
+/* struct aa_net - network confinement data
+ * @allow: basic network families permissions
+ * @audit: which network permissions to force audit
+ * @quiet: which network permissions to quiet rejects
+ */
+struct aa_net_compat {
+	u16 allow[AF_MAX];
+	u16 audit[AF_MAX];
+	u16 quiet[AF_MAX];
+};
 
 #define af_select(FAMILY, FN, DEF_FN)		\
 ({						\
@@ -87,6 +97,7 @@ struct aa_secmark {
 };
 
 extern struct aa_sfs_entry aa_sfs_entry_network[];
+extern struct aa_sfs_entry aa_sfs_entry_network_compat[];
 
 void audit_net_cb(struct audit_buffer *ab, void *va);
 int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h
index 1ce4e9bdac48191ac859a31919ec4eac12a29b98..6515a9174835c7d41279da92e6cafd72868ef181 100644
--- a/security/apparmor/include/policy.h
+++ b/security/apparmor/include/policy.h
@@ -108,6 +108,7 @@ struct aa_data {
  * @policy: general match rules governing policy
  * @file: The set of rules governing basic file access and domain transitions
  * @caps: capabilities for the profile
+ * @net_compat: v2 compat network controls for the profile
  * @rlimits: rlimits for the profile
  *
  * @dents: dentries for the profiles file entries in apparmorfs
@@ -145,6 +146,7 @@ struct aa_profile {
 	struct aa_policydb policy;
 	struct aa_file_rules file;
 	struct aa_caps caps;
+	struct aa_net_compat *net_compat;
 
 	int xattr_count;
 	char **xattrs;
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index d8afc39f663ac6d5b54d2508bc6e3d2a0b78d42e..1d8f5ff53cd4c19b73532387accb034589ef1122 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -24,6 +24,11 @@ struct aa_sfs_entry aa_sfs_entry_network[] = {
 	{ }
 };
 
+struct aa_sfs_entry aa_sfs_entry_network_compat[] = {
+	AA_SFS_FILE_STRING("af_mask",	AA_SFS_AF_MASK),
+	{ }
+};
+
 static const char * const net_mask_names[] = {
 	"unknown",
 	"send",
@@ -116,14 +121,26 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
 	if (profile_unconfined(profile))
 		return 0;
 	state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
-	if (!state)
+	if (state) {
+		if (!state)
+			return 0;
+		buffer[0] = cpu_to_be16(family);
+		buffer[1] = cpu_to_be16((u16) type);
+		state = aa_dfa_match_len(profile->policy.dfa, state,
+					 (char *) &buffer, 4);
+		aa_compute_perms(profile->policy.dfa, state, &perms);
+	} else if (profile->net_compat) {
+		/* 2.x socket mediation compat */
+		perms.allow = (profile->net_compat->allow[family] & (1 << type)) ?
+			ALL_PERMS_MASK : 0;
+		perms.audit = (profile->net_compat->audit[family] & (1 << type)) ?
+			ALL_PERMS_MASK : 0;
+		perms.quiet = (profile->net_compat->quiet[family] & (1 << type)) ?
+			ALL_PERMS_MASK : 0;
+
+	} else {
 		return 0;
-
-	buffer[0] = cpu_to_be16(family);
-	buffer[1] = cpu_to_be16((u16) type);
-	state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
-				 4);
-	aa_compute_perms(profile->policy.dfa, state, &perms);
+	}
 	aa_apply_modes_to_perms(profile, &perms);
 
 	return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c
index ade333074c8ed50263999e231b9750842ef2ef6d..32f617df3d98120883643378549280c085a99be4 100644
--- a/security/apparmor/policy.c
+++ b/security/apparmor/policy.c
@@ -222,6 +222,7 @@ void aa_free_profile(struct aa_profile *profile)
 	aa_free_file_rules(&profile->file);
 	aa_free_cap_rules(&profile->caps);
 	aa_free_rlimit_rules(&profile->rlimits);
+	kzfree(profile->net_compat);
 
 	for (i = 0; i < profile->xattr_count; i++)
 		kzfree(profile->xattrs[i]);
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
index 01957ce9252b52d436da3f057ec5c97687106431..8a93a3dc87e1bca791843eefe28511a2a3cd8200 100644
--- a/security/apparmor/policy_unpack.c
+++ b/security/apparmor/policy_unpack.c
@@ -33,7 +33,7 @@
 
 #define v5	5	/* base version */
 #define v6	6	/* per entry policydb mediation check */
-#define v7	7
+#define v7	7	/* v2 compat networking */
 #define v8	8	/* full network masking */
 
 /*
@@ -301,6 +301,19 @@ static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name)
 	return 0;
 }
 
+static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name)
+{
+	if (unpack_nameX(e, AA_U16, name)) {
+		if (!inbounds(e, sizeof(u16)))
+			return 0;
+		if (data)
+			*data = le16_to_cpu(get_unaligned((__le16 *) e->pos));
+		e->pos += sizeof(u16);
+		return 1;
+	}
+	return 0;
+}
+
 static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name)
 {
 	if (unpack_nameX(e, AA_U32, name)) {
@@ -642,7 +655,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
 	struct aa_profile *profile = NULL;
 	const char *tmpname, *tmpns = NULL, *name = NULL;
 	const char *info = "failed to unpack profile";
-	size_t ns_len;
+	size_t size = 0, ns_len;
 	struct rhashtable_params params = { 0 };
 	char *key = NULL;
 	struct aa_data *data;
@@ -785,6 +798,43 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name)
 		goto fail;
 	}
 
+	size = unpack_array(e, "net_allowed_af");
+	if (size || VERSION_LT(e->version, v8)) {
+		profile->net_compat = kzalloc(sizeof(struct aa_net_compat), GFP_KERNEL);
+		if (!profile->net_compat) {
+			info = "out of memory";
+			goto fail;
+		}
+		for (i = 0; i < size; i++) {
+			/* discard extraneous rules that this kernel will
+			 * never request
+			 */
+			if (i >= AF_MAX) {
+				u16 tmp;
+
+				if (!unpack_u16(e, &tmp, NULL) ||
+				    !unpack_u16(e, &tmp, NULL) ||
+				    !unpack_u16(e, &tmp, NULL))
+					goto fail;
+				continue;
+			}
+			if (!unpack_u16(e, &profile->net_compat->allow[i], NULL))
+				goto fail;
+			if (!unpack_u16(e, &profile->net_compat->audit[i], NULL))
+				goto fail;
+			if (!unpack_u16(e, &profile->net_compat->quiet[i], NULL))
+				goto fail;
+		}
+		if (size && !unpack_nameX(e, AA_ARRAYEND, NULL))
+			goto fail;
+		if (VERSION_LT(e->version, v7)) {
+			/* pre v7 policy always allowed these */
+			profile->net_compat->allow[AF_UNIX] = 0xffff;
+			profile->net_compat->allow[AF_NETLINK] = 0xffff;
+		}
+	}
+
+
 	if (unpack_nameX(e, AA_STRUCT, "policydb")) {
 		/* generic policy dfa - optional and may be NULL */
 		info = "failed to unpack policydb";