e50352257c
This change updates the kernel patches with the patches used by Proxmox. Furthermore, we split the patches from Proxmox and Ubuntu, so that we don't have to re-order them.
250 lines
8.3 KiB
Diff
250 lines
8.3 KiB
Diff
From f153f512ed7a81e9b92a04d49869cffebf714f52 Mon Sep 17 00:00:00 2001
|
|
From: John Johansen <john.johansen@canonical.com>
|
|
Date: Sun, 17 Jun 2018 03:56:25 -0700
|
|
Subject: UBUNTU: SAUCE: apparmor: patch to provide compatibility with v2.x net
|
|
rules
|
|
|
|
The networking rules upstreamed in 4.17 have a deliberate abi break
|
|
with the older 2.x network rules.
|
|
|
|
This patch provides compatibility with the older rules for those
|
|
still using an apparmor 2.x userspace and still want network rules
|
|
to work on a newer kernel.
|
|
|
|
Signed-off-by: John Johansen <john.johansen@canonical.com>
|
|
[ saf: resolve conflicts when rebasing to 4.20 ]
|
|
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
|
|
---
|
|
security/apparmor/apparmorfs.c | 1 +
|
|
security/apparmor/include/apparmor.h | 2 +-
|
|
security/apparmor/include/net.h | 11 ++++++++
|
|
security/apparmor/include/policy.h | 2 ++
|
|
security/apparmor/net.c | 31 ++++++++++++++++-----
|
|
security/apparmor/policy.c | 1 +
|
|
security/apparmor/policy_unpack.c | 54 ++++++++++++++++++++++++++++++++++--
|
|
7 files changed, 92 insertions(+), 10 deletions(-)
|
|
|
|
(limited to 'security/apparmor')
|
|
|
|
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
|
|
index 2ee3b3d..0aef8e3 100644
|
|
--- a/security/apparmor/apparmorfs.c
|
|
+++ b/security/apparmor/apparmorfs.c
|
|
@@ -2362,6 +2362,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 1fbabdb..5870de2 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 aadb4b2..98a42ef 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 b5b4b81..f904105 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 e0c1b50..e693df8 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",
|
|
@@ -118,14 +123,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 4c010c9..a00e39b 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);
|
|
+ kfree_sensitive(profile->net_compat);
|
|
|
|
for (i = 0; i < profile->xattr_count; i++)
|
|
kfree_sensitive(profile->xattrs[i]);
|
|
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
|
|
index 4e1f96b..aedfecc 100644
|
|
--- a/security/apparmor/policy_unpack.c
|
|
+++ b/security/apparmor/policy_unpack.c
|
|
@@ -34,7 +34,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 */
|
|
|
|
/*
|
|
@@ -314,6 +314,19 @@ fail:
|
|
return false;
|
|
}
|
|
|
|
+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)
|
|
{
|
|
void *pos = e->pos;
|
|
@@ -676,7 +689,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;
|
|
@@ -823,6 +836,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";
|