223 lines
7.7 KiB
Diff
223 lines
7.7 KiB
Diff
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";
|