mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 00:14:44 +01:00
latest version of the patches, updated off of 2.6.25 dev
This commit is contained in:
parent
8c5f77c4bd
commit
d4856f9680
8 changed files with 385 additions and 221 deletions
|
@ -7,12 +7,12 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
|||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/lsm.c | 879 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 879 insertions(+)
|
||||
security/apparmor/lsm.c | 889 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 889 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -0,0 +1,879 @@
|
||||
@@ -0,0 +1,889 @@
|
||||
+/*
|
||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||
+ *
|
||||
|
@ -645,6 +645,16 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ unsigned long prot, unsigned long flags,
|
||||
+ unsigned long addr, unsigned long addr_only)
|
||||
+{
|
||||
+ if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) {
|
||||
+ struct aa_profile *profile = aa_get_profile(current);
|
||||
+ if (profile)
|
||||
+ /* future control check here */
|
||||
+ return -EACCES;
|
||||
+ else
|
||||
+ return -EACCES;
|
||||
+ aa_put_profile(profile);
|
||||
+ }
|
||||
+
|
||||
+ return aa_mmap(file, "file_mmap", prot, flags);
|
||||
+}
|
||||
+
|
||||
|
|
|
@ -7,12 +7,12 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
|||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/main.c | 1421 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 1421 insertions(+)
|
||||
security/apparmor/main.c | 1479 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 1479 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -0,0 +1,1421 @@
|
||||
@@ -0,0 +1,1479 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2002-2007 Novell/SUSE
|
||||
+ *
|
||||
|
@ -84,6 +84,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+static void aa_audit_file_sub_mask(struct audit_buffer *ab, char *buffer,
|
||||
+ int mask)
|
||||
+{
|
||||
+ const char unsafex[] = "upcn";
|
||||
+ const char safex[] = "UPCN";
|
||||
+ char *m = buffer;
|
||||
+
|
||||
+ if (mask & AA_EXEC_MMAP)
|
||||
|
@ -95,37 +97,18 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ else if (mask & MAY_APPEND)
|
||||
+ *m++ = 'a';
|
||||
+ if (mask & MAY_EXEC) {
|
||||
+ if (mask & AA_EXEC_UNSAFE) {
|
||||
+ switch(mask & AA_EXEC_MODIFIERS) {
|
||||
+ case AA_EXEC_UNCONFINED:
|
||||
+ *m++ = 'u';
|
||||
+ break;
|
||||
+ case AA_EXEC_PIX:
|
||||
+ *m++ = 'p';
|
||||
+ /* fall through */
|
||||
+ case AA_EXEC_INHERIT:
|
||||
+ *m++ = 'i';
|
||||
+ break;
|
||||
+ case AA_EXEC_PROFILE:
|
||||
+ *m++ = 'p';
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ switch(mask & AA_EXEC_MODIFIERS) {
|
||||
+ case AA_EXEC_UNCONFINED:
|
||||
+ *m++ = 'U';
|
||||
+ break;
|
||||
+ case AA_EXEC_PIX:
|
||||
+ *m++ = 'P';
|
||||
+ /* fall through */
|
||||
+ case AA_EXEC_INHERIT:
|
||||
+ *m++ = 'I';
|
||||
+ break;
|
||||
+ case AA_EXEC_PROFILE:
|
||||
+ *m++ = 'P';
|
||||
+ break;
|
||||
+ }
|
||||
+ int index = AA_EXEC_INDEX(mask);
|
||||
+ /* all indexes > 4 are also named transitions */
|
||||
+ if (index > 4)
|
||||
+ index = 4;
|
||||
+ if (index > 0) {
|
||||
+ if (mask & AA_EXEC_UNSAFE)
|
||||
+ *m++ = unsafex[index - 1];
|
||||
+ else
|
||||
+ *m++ = safex[index - 1];
|
||||
+ }
|
||||
+ if (mask & AA_EXEC_INHERIT)
|
||||
+ *m++ = 'i';
|
||||
+ *m++ = 'x';
|
||||
+ }
|
||||
+ if (mask & AA_MAY_LINK)
|
||||
|
@ -369,7 +352,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ int *request_mask, int *audit_mask)
|
||||
+{
|
||||
+ unsigned int state;
|
||||
+ int l_mode, t_mode, denied_mask = 0;
|
||||
+ int l_mode, t_mode, l_x, t_x, denied_mask = 0;
|
||||
+ int link_mask = AA_MAY_LINK << target_mode;
|
||||
+
|
||||
+ *request_mask = link_mask;
|
||||
|
@ -393,7 +376,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ return denied_mask;
|
||||
+ }
|
||||
+
|
||||
+ /* Do link perm subset test
|
||||
+ /* Do link perm subset test requiring permission on link are a
|
||||
+ * subset of the permissions on target.
|
||||
+ * If a subset test is required a permission subset test of the
|
||||
+ * perms for the link are done against the user::other of the
|
||||
+ * target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions.
|
||||
|
@ -405,6 +389,9 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+
|
||||
+ t_mode = aa_match(profile->file_rules, target, NULL);
|
||||
+
|
||||
+ l_x = l_mode & (ALL_AA_EXEC_TYPE | AA_EXEC_BITS);
|
||||
+ t_x = t_mode & (ALL_AA_EXEC_TYPE | AA_EXEC_BITS);
|
||||
+
|
||||
+ /* For actual subset test ignore valid-profile-transition flags,
|
||||
+ * and link bits
|
||||
+ */
|
||||
|
@ -414,12 +401,20 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ *request_mask = l_mode | link_mask;
|
||||
+
|
||||
+ if (l_mode) {
|
||||
+ int x = l_x | (t_x & ALL_AA_EXEC_UNSAFE);
|
||||
+ denied_mask |= l_mode & ~t_mode;
|
||||
+ if ((l_mode & AA_EXEC_BITS) &&
|
||||
+ (l_mode & ALL_AA_EXEC_TYPE) !=
|
||||
+ (t_mode & ALL_AA_EXEC_TYPE))
|
||||
+ denied_mask = (denied_mask & ~ALL_AA_EXEC_TYPE) |
|
||||
+ (l_mode & (ALL_AA_EXEC_TYPE | AA_EXEC_BITS));
|
||||
+ /* mask off x modes not used by link */
|
||||
+
|
||||
+ /* handle exec subset
|
||||
+ * - link safe exec issubset of unsafe exec
|
||||
+ * - no link x perm is subset of target having x perm
|
||||
+ */
|
||||
+ if ((l_mode & AA_USER_EXEC) &&
|
||||
+ (x & AA_USER_EXEC_TYPE) != (t_x & AA_USER_EXEC_TYPE))
|
||||
+ denied_mask = AA_USER_EXEC | (l_x & AA_USER_EXEC_TYPE);
|
||||
+ if ((l_mode & AA_OTHER_EXEC) &&
|
||||
+ (x & AA_OTHER_EXEC_TYPE) != (t_x & AA_OTHER_EXEC_TYPE))
|
||||
+ denied_mask = AA_OTHER_EXEC | (l_x & AA_OTHER_EXEC_TYPE);
|
||||
+ }
|
||||
+
|
||||
+ return denied_mask;
|
||||
|
@ -484,6 +479,13 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ }
|
||||
+}
|
||||
+
|
||||
+static char *new_compound_name(const char *n1, const char *n2)
|
||||
+{
|
||||
+ char *name = kmalloc(strlen(n1) + strlen(n2) + 3, GFP_KERNEL);
|
||||
+ if (name)
|
||||
+ sprintf(name, "%s//%s", n1, n2);
|
||||
+ return name;
|
||||
+}
|
||||
+static inline void aa_put_name_buffer(char *buffer)
|
||||
+{
|
||||
+ kfree(buffer);
|
||||
|
@ -840,16 +842,37 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+}
|
||||
+
|
||||
+static struct aa_profile *
|
||||
+aa_register_find(struct aa_profile *profile, const char *name, int mandatory,
|
||||
+ int complain, struct aa_audit *sa)
|
||||
+aa_register_find(struct aa_profile *profile, const char* ns_name,
|
||||
+ const char *name, int mandatory, int complain,
|
||||
+ struct aa_audit *sa)
|
||||
+{
|
||||
+ struct aa_namespace *ns;
|
||||
+ struct aa_profile *new_profile;
|
||||
+ int ns_ref = 0;
|
||||
+
|
||||
+ if (profile)
|
||||
+ ns = profile->ns;
|
||||
+ else
|
||||
+ ns = default_namespace;
|
||||
+
|
||||
+ if (ns_name) {
|
||||
+ /* locate the profile namespace */
|
||||
+ ns = aa_find_namespace(ns_name);
|
||||
+ if (!ns) {
|
||||
+ if (mandatory) {
|
||||
+ sa->info = "profile namespace not found";
|
||||
+ sa->denied_mask = sa->request_mask;
|
||||
+ sa->error_code = -ENOENT;
|
||||
+ return ERR_PTR(-ENOENT);
|
||||
+ } else {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ }
|
||||
+ ns_ref++;
|
||||
+ }
|
||||
+
|
||||
+ /* Locate new profile */
|
||||
+ if (profile)
|
||||
+ new_profile = aa_find_profile(profile->ns, name);
|
||||
+ else
|
||||
+ new_profile = aa_find_profile(default_namespace, name);
|
||||
+ new_profile = aa_find_profile(ns, name);
|
||||
+
|
||||
+ if (new_profile) {
|
||||
+ AA_DEBUG("%s: setting profile %s\n",
|
||||
|
@ -863,16 +886,82 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ aa_dup_profile(profile->ns->null_complain_profile);
|
||||
+ } else {
|
||||
+ sa->error_code = -EACCES;
|
||||
+ return ERR_PTR(aa_audit_file(profile, sa));
|
||||
+ if (ns_ref)
|
||||
+ aa_put_namespace(ns);
|
||||
+ return ERR_PTR(-EACCES);
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Only way we can get into this code is if task
|
||||
+ * is unconfined, or pix.
|
||||
+ * is unconfined, pix, nix.
|
||||
+ */
|
||||
+ AA_DEBUG("%s: No profile found for exec image '%s'\n",
|
||||
+ __FUNCTION__,
|
||||
+ name);
|
||||
+ }
|
||||
+ if (ns_ref)
|
||||
+ aa_put_namespace(ns);
|
||||
+ return new_profile;
|
||||
+}
|
||||
+
|
||||
+static struct aa_profile *
|
||||
+aa_x_to_profile(struct aa_profile *profile, const char *filename, int xmode,
|
||||
+ struct aa_audit *sa, char **child)
|
||||
+{
|
||||
+ struct aa_profile *new_profile = NULL;
|
||||
+ int ix = xmode & AA_EXEC_INHERIT;
|
||||
+ int complain = PROFILE_COMPLAIN(profile);
|
||||
+ int index;
|
||||
+
|
||||
+ *child = NULL;
|
||||
+ switch (xmode & AA_EXEC_MODIFIERS) {
|
||||
+ case 0:
|
||||
+ /* only valid with ix flag */
|
||||
+ ix = 1;
|
||||
+ break;
|
||||
+ case AA_EXEC_UNCONFINED:
|
||||
+ /* only valid without ix flag */
|
||||
+ ix = 0;
|
||||
+ break;
|
||||
+ case AA_EXEC_PROFILE:
|
||||
+ new_profile = aa_register_find(profile, NULL, filename, !ix,
|
||||
+ complain, sa);
|
||||
+ break;
|
||||
+ case AA_EXEC_CHILD:
|
||||
+ *child = new_compound_name(profile->name, filename);
|
||||
+ sa->name2 = *child;
|
||||
+ if (!*child) {
|
||||
+ sa->info = "Failed name resolution - exec failed";
|
||||
+ sa->error_code = -ENOMEM;
|
||||
+ new_profile = ERR_PTR(-ENOMEM);
|
||||
+ } else {
|
||||
+ new_profile = aa_register_find(profile, NULL, *child,
|
||||
+ !ix, complain, sa);
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ /* all other indexes are named transitions */
|
||||
+ index = AA_EXEC_INDEX(xmode);
|
||||
+ if (index - 4 > profile->exec_table_size) {
|
||||
+ sa->info = "invalid named transition - exec failed";
|
||||
+ sa->error_code = -EACCES;
|
||||
+ new_profile = ERR_PTR(-EACCES);
|
||||
+ } else {
|
||||
+ char *ns_name = NULL;
|
||||
+ char *name = profile->exec_table[index - 4];
|
||||
+ if (*name == ':') {
|
||||
+ ns_name = name + 1;
|
||||
+ name = ns_name + strlen(ns_name) + 1;
|
||||
+ }
|
||||
+ sa->name2 = name;
|
||||
+ sa->name3 = ns_name;
|
||||
+ new_profile =
|
||||
+ aa_register_find(profile, ns_name, name,
|
||||
+ !ix, complain, sa);
|
||||
+ }
|
||||
+ }
|
||||
+ if (IS_ERR(new_profile))
|
||||
+ /* all these failures must be audited - no quieting */
|
||||
+ return ERR_PTR(aa_audit_reject(profile, sa));
|
||||
+ return new_profile;
|
||||
+}
|
||||
+
|
||||
|
@ -886,7 +975,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+int aa_register(struct linux_binprm *bprm)
|
||||
+{
|
||||
+ const char *filename;
|
||||
+ char *buffer = NULL;
|
||||
+ char *buffer = NULL, *child = NULL;
|
||||
+ struct file *filp = bprm->file;
|
||||
+ struct aa_profile *profile, *old_profile, *new_profile = NULL;
|
||||
+ int exec_mode, complain = 0, shift;
|
||||
|
@ -907,7 +996,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ if (profile) {
|
||||
+ sa.info = "Failed name resolution - exec failed";
|
||||
+ sa.error_code = PTR_ERR(filename);
|
||||
+ aa_audit_reject(profile, &sa);
|
||||
+ aa_audit_file(profile, &sa);
|
||||
+ return sa.error_code;
|
||||
+ } else
|
||||
+ return 0;
|
||||
|
@ -926,46 +1015,16 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ exec_mode = aa_match(profile->file_rules, filename,
|
||||
+ &sa.audit_mask);
|
||||
+
|
||||
+
|
||||
+ if (exec_mode & sa.request_mask) {
|
||||
+ switch ((exec_mode >> shift) & AA_EXEC_MODIFIERS) {
|
||||
+ case AA_EXEC_INHERIT:
|
||||
+ AA_DEBUG("%s: INHERIT %s\n",
|
||||
+ __FUNCTION__,
|
||||
+ filename);
|
||||
+ /* nothing to be done here */
|
||||
+ int xm = exec_mode >> shift;
|
||||
+ new_profile = aa_x_to_profile(profile, filename,
|
||||
+ xm, &sa, &child);
|
||||
+
|
||||
+ if (!new_profile && (xm & AA_EXEC_INHERIT))
|
||||
+ /* (p|c|n|)ix - don't change profile */
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ case AA_EXEC_UNCONFINED:
|
||||
+ AA_DEBUG("%s: UNCONFINED %s\n",
|
||||
+ __FUNCTION__,
|
||||
+ filename);
|
||||
+
|
||||
+ /* detach current profile */
|
||||
+ new_profile = NULL;
|
||||
+ break;
|
||||
+
|
||||
+ case AA_EXEC_PROFILE:
|
||||
+ AA_DEBUG("%s: PROFILE %s\n",
|
||||
+ __FUNCTION__,
|
||||
+ filename);
|
||||
+ new_profile = aa_register_find(profile,
|
||||
+ filename,
|
||||
+ 1, complain,
|
||||
+ &sa);
|
||||
+ break;
|
||||
+ case AA_EXEC_PIX:
|
||||
+ AA_DEBUG("%s: PROFILE %s\n",
|
||||
+ __FUNCTION__,
|
||||
+ filename);
|
||||
+ new_profile = aa_register_find(profile,
|
||||
+ filename,
|
||||
+ 0, complain,
|
||||
+ &sa);
|
||||
+ if (!new_profile)
|
||||
+ /* inherit - nothing to be done here */
|
||||
+ goto cleanup;
|
||||
+ break;
|
||||
+ }
|
||||
+ /* error case caught below */
|
||||
+
|
||||
+ } else if (sa.request_mask & AUDIT_QUIET_MASK(sa.audit_mask)) {
|
||||
+ /* quiet failed exit */
|
||||
|
@ -985,7 +1044,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ }
|
||||
+ } else {
|
||||
+ /* Unconfined task, load profile if it exists */
|
||||
+ new_profile = aa_register_find(NULL, filename, 0, 0, &sa);
|
||||
+ new_profile = aa_register_find(NULL, NULL, filename, 0, 0, &sa);
|
||||
+ if (new_profile == NULL)
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
|
@ -1039,6 +1098,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ }
|
||||
+
|
||||
+cleanup:
|
||||
+ aa_put_name_buffer(child);
|
||||
+ aa_put_name_buffer(buffer);
|
||||
+ if (IS_ERR(new_profile))
|
||||
+ return PTR_ERR(new_profile);
|
||||
|
@ -1180,7 +1240,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+int aa_change_profile(const char *ns_name, const char *name)
|
||||
+{
|
||||
+ struct aa_task_context *cxt;
|
||||
+ struct aa_profile *profile;
|
||||
+ struct aa_profile *profile = NULL;
|
||||
+ struct aa_namespace *ns = NULL;
|
||||
+ struct aa_audit sa;
|
||||
+ unsigned int state;
|
||||
|
@ -1196,23 +1256,23 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+repeat:
|
||||
+ task_lock(current);
|
||||
+ cxt = aa_task_context(current);
|
||||
+ if (!cxt) {
|
||||
+ task_unlock(current);
|
||||
+ return -EPERM;
|
||||
+ }
|
||||
+ profile = aa_dup_profile(cxt->profile);
|
||||
+ if (cxt)
|
||||
+ profile = aa_dup_profile(cxt->profile);
|
||||
+ task_unlock(current);
|
||||
+
|
||||
+ if (ns_name)
|
||||
+ ns = aa_find_namespace(ns_name);
|
||||
+ else
|
||||
+ else if (profile)
|
||||
+ ns = aa_get_namespace(profile->ns);
|
||||
+ else
|
||||
+ ns = aa_get_namespace(default_namespace);
|
||||
+
|
||||
+ if (!ns) {
|
||||
+ aa_put_profile(profile);
|
||||
+ return -ENOENT;
|
||||
+ }
|
||||
+
|
||||
+ if (PROFILE_COMPLAIN(profile) ||
|
||||
+ if (!profile || PROFILE_COMPLAIN(profile) ||
|
||||
+ (ns == profile->ns &&
|
||||
+ (aa_match(profile->file_rules, name, NULL) & AA_CHANGE_PROFILE)))
|
||||
+ error = do_change_profile(profile, ns, name, 0, 0, &sa);
|
||||
|
@ -1287,16 +1347,14 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ else
|
||||
+ profile_name = profile->name;
|
||||
+
|
||||
+ name = kmalloc(strlen(hat_name) + 3 + strlen(profile_name),
|
||||
+ GFP_KERNEL);
|
||||
+ name = new_compound_name(profile_name, hat_name);
|
||||
+ if (!name) {
|
||||
+ error = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ sprintf(name, "%s//%s", profile_name, hat_name);
|
||||
+ error = do_change_profile(profile, profile->ns, name, cookie,
|
||||
+ 0, &sa);
|
||||
+ kfree(name);
|
||||
+ aa_put_name_buffer(name);
|
||||
+ } else if (previous_profile)
|
||||
+ error = do_change_profile(profile, profile->ns,
|
||||
+ previous_profile->name, cookie, 1,
|
||||
|
|
|
@ -13,13 +13,13 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
---
|
||||
security/apparmor/Kconfig | 42 ++++
|
||||
security/apparmor/Makefile | 13 +
|
||||
security/apparmor/apparmor.h | 358 +++++++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/apparmorfs.c | 280 ++++++++++++++++++++++++++++++++
|
||||
security/apparmor/inline.h | 250 ++++++++++++++++++++++++++++
|
||||
security/apparmor/apparmor.h | 367 +++++++++++++++++++++++++++++++++++++++++
|
||||
security/apparmor/apparmorfs.c | 280 +++++++++++++++++++++++++++++++
|
||||
security/apparmor/inline.h | 250 +++++++++++++++++++++++++++
|
||||
security/apparmor/list.c | 156 +++++++++++++++++
|
||||
security/apparmor/locking.txt | 68 +++++++
|
||||
security/apparmor/procattr.c | 195 ++++++++++++++++++++++
|
||||
8 files changed, 1362 insertions(+)
|
||||
security/apparmor/procattr.c | 195 +++++++++++++++++++++
|
||||
8 files changed, 1371 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/Kconfig
|
||||
|
@ -84,7 +84,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ $(call cmd,make-caps)
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/apparmor.h
|
||||
@@ -0,0 +1,358 @@
|
||||
@@ -0,0 +1,367 @@
|
||||
+/*
|
||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||
+ *
|
||||
|
@ -113,30 +113,31 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+#define AA_EXEC_MMAP 0x0040
|
||||
+#define AA_MAY_MOUNT 0x0080 /* no direct audit mapping */
|
||||
+#define AA_EXEC_UNSAFE 0x0100
|
||||
+#define AA_EXEC_MOD_0 0x0200
|
||||
+#define AA_EXEC_MOD_1 0x0400
|
||||
+#define AA_EXEC_MOD_2 0x0800
|
||||
+#define AA_EXEC_MOD_3 0x1000
|
||||
+#define AA_EXEC_MOD_4 0x2000
|
||||
+#define AA_EXEC_INHERIT 0x0200
|
||||
+#define AA_EXEC_MOD_0 0x0400
|
||||
+#define AA_EXEC_MOD_1 0x0800
|
||||
+#define AA_EXEC_MOD_2 0x1000
|
||||
+#define AA_EXEC_MOD_3 0x2000
|
||||
+
|
||||
+#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \
|
||||
+ MAY_APPEND | AA_MAY_LINK | \
|
||||
+ AA_MAY_LOCK | AA_EXEC_MMAP | \
|
||||
+ AA_MAY_MOUNT | AA_EXEC_UNSAFE | \
|
||||
+ AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
|
||||
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
|
||||
+ AA_EXEC_MOD_4)
|
||||
+ AA_EXEC_INHERIT | AA_EXEC_MOD_0 | \
|
||||
+ AA_EXEC_MOD_1 | AA_EXEC_MOD_2 | \
|
||||
+ AA_EXEC_MOD_3)
|
||||
+
|
||||
+#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
|
||||
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
|
||||
+ AA_EXEC_MOD_4)
|
||||
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3)
|
||||
+
|
||||
+#define AA_EXEC_TYPE (AA_EXEC_UNSAFE | AA_EXEC_MODIFIERS)
|
||||
+#define AA_EXEC_TYPE (AA_EXEC_UNSAFE | AA_EXEC_INHERIT | \
|
||||
+ AA_EXEC_MODIFIERS)
|
||||
+
|
||||
+#define AA_EXEC_UNCONFINED AA_EXEC_MOD_0
|
||||
+#define AA_EXEC_INHERIT AA_EXEC_MOD_1
|
||||
+#define AA_EXEC_PROFILE (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
|
||||
+#define AA_EXEC_PIX AA_EXEC_MOD_2
|
||||
+#define AA_EXEC_PROFILE AA_EXEC_MOD_1
|
||||
+#define AA_EXEC_CHILD (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
|
||||
+/* remaining exec modes are index into profile name table */
|
||||
+#define AA_EXEC_INDEX(mode) ((mode & AA_EXEC_MODIFIERS) >> 10)
|
||||
+
|
||||
+#define AA_USER_SHIFT 0
|
||||
+#define AA_OTHER_SHIFT 14
|
||||
|
@ -157,20 +158,26 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+
|
||||
+#define AA_EXEC_BITS (AA_USER_EXEC | AA_OTHER_EXEC)
|
||||
+
|
||||
+#define ALL_AA_EXEC_UNSAFE ((AA_EXEC_UNSAFE << AA_USER_SHIFT) | \
|
||||
+ (AA_EXEC_UNSAFE << AA_OTHER_SHIFT))
|
||||
+
|
||||
+#define ALL_AA_EXEC_TYPE (AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE)
|
||||
+
|
||||
+/* overloaded permissions for link pairs */
|
||||
+#define AA_LINK_SUBSET_TEST 0x0020
|
||||
+
|
||||
+#define AA_USER_PTRACE 0x10000000
|
||||
+#define AA_OTHER_PTRACE 0x20000000
|
||||
+#define AA_PTRACE_PERMS (AA_USER_PTRACE | AA_OTHER_PTRACE)
|
||||
+
|
||||
+/* shared permissions that are not duplicated in user::other */
|
||||
+#define AA_AUDIT_FIELD 0x10000000
|
||||
+#define AA_CHANGE_HAT 0x20000000
|
||||
+#define AA_CHANGE_PROFILE 0x40000000
|
||||
+#define AA_CHANGE_HAT 0x40000000
|
||||
+#define AA_CHANGE_PROFILE 0x80000000
|
||||
+
|
||||
+#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE | \
|
||||
+ AA_AUDIT_FIELD)
|
||||
+#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE)
|
||||
+
|
||||
+#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
|
||||
+#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_PTRACE_PERMS | \
|
||||
+ AA_SHARED_PERMS)
|
||||
+
|
||||
+/* audit bits for the second accept field */
|
||||
+#define AUDIT_FILE_MASK 0x1fc07f
|
||||
|
@ -270,6 +277,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ struct list_head list;
|
||||
+ struct aa_namespace *ns;
|
||||
+
|
||||
+ int exec_table_size;
|
||||
+ char **exec_table;
|
||||
+ struct aa_dfa *file_rules;
|
||||
+ struct {
|
||||
+ int complain;
|
||||
|
|
|
@ -8,10 +8,10 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
|||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||
|
||||
---
|
||||
security/apparmor/match.c | 364 +++++++++++++++
|
||||
security/apparmor/match.c | 364 ++++++++++++++
|
||||
security/apparmor/match.h | 87 +++
|
||||
security/apparmor/module_interface.c | 815 +++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 1266 insertions(+)
|
||||
security/apparmor/module_interface.c | 874 +++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 1325 insertions(+)
|
||||
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/match.c
|
||||
|
@ -472,7 +472,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+#endif /* __MATCH_H */
|
||||
--- /dev/null
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -0,0 +1,815 @@
|
||||
@@ -0,0 +1,874 @@
|
||||
+/*
|
||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||
+ *
|
||||
|
@ -716,7 +716,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ *
|
||||
+ * returns dfa or ERR_PTR
|
||||
+ */
|
||||
+struct aa_dfa *aa_unpack_dfa(struct aa_ext *e)
|
||||
+static struct aa_dfa *aa_unpack_dfa(struct aa_ext *e)
|
||||
+{
|
||||
+ char *blob = NULL;
|
||||
+ size_t size, error = 0;
|
||||
|
@ -748,16 +748,53 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ return dfa;
|
||||
+}
|
||||
+
|
||||
+static int aa_unpack_exec_table(struct aa_ext *e, struct aa_profile *profile)
|
||||
+{
|
||||
+ void *pos = e->pos;
|
||||
+
|
||||
+ /* exec table is optional */
|
||||
+ if (aa_is_nameX(e, AA_STRUCT, "xtable")) {
|
||||
+ int i, size;
|
||||
+
|
||||
+ size = aa_is_array(e, NULL);
|
||||
+ /* currently 4 exec bits and entries 0-3 are reserved iupcx */
|
||||
+ if (size > 16 - 4)
|
||||
+ goto fail;
|
||||
+ profile->exec_table = kzalloc(sizeof(char *) * size,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!profile->exec_table)
|
||||
+ goto fail;
|
||||
+
|
||||
+ for (i = 0; i < size; i++) {
|
||||
+ char *tmp;
|
||||
+ if (!aa_is_dynstring(e, &tmp, NULL))
|
||||
+ goto fail;
|
||||
+ /* note: strings beginning with a : have an embedded
|
||||
+ \0 seperating the profile ns name from the profile
|
||||
+ name */
|
||||
+ profile->exec_table[i] = tmp;
|
||||
+ }
|
||||
+ if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ return 1;
|
||||
+
|
||||
+fail:
|
||||
+ e->pos = pos;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * aa_unpack_profile - unpack a serialized profile
|
||||
+ * @e: serialized data extent information
|
||||
+ * @operation: operation profile is being unpacked for
|
||||
+ * @sa: audit struct for the operation
|
||||
+ */
|
||||
+static struct aa_profile *aa_unpack_profile(struct aa_ext *e,
|
||||
+ const char *operation)
|
||||
+ struct aa_audit *sa)
|
||||
+{
|
||||
+ struct aa_profile *profile = NULL;
|
||||
+ struct aa_audit sa;
|
||||
+
|
||||
+ int error = -EPROTO;
|
||||
+
|
||||
|
@ -798,25 +835,21 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ error = PTR_ERR(profile->file_rules);
|
||||
+ profile->file_rules = NULL;
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u16(e, &profile->audit_network[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u16(e, &profile->quiet_network[i], NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+
|
||||
+ if (!aa_unpack_exec_table(e, profile))
|
||||
+ goto fail;
|
||||
+
|
||||
+ if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
||||
+ goto fail;
|
||||
+
|
||||
+ return profile;
|
||||
+
|
||||
+fail:
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = operation;
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+ sa.name = profile && profile->name ? profile->name : "unknown";
|
||||
+ if (!sa.info)
|
||||
+ sa.info = "failed to unpack profile";
|
||||
+ aa_audit_status(NULL, &sa);
|
||||
+ sa->name = profile && profile->name ? profile->name : "unknown";
|
||||
+ if (!sa->info)
|
||||
+ sa->info = "failed to unpack profile";
|
||||
+ aa_audit_status(NULL, sa);
|
||||
+
|
||||
+ if (profile)
|
||||
+ free_aa_profile(profile);
|
||||
|
@ -831,27 +864,19 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ *
|
||||
+ * returns error or 0 if header is good
|
||||
+ */
|
||||
+static int aa_verify_header(struct aa_ext *e, const char *operation)
|
||||
+static int aa_verify_header(struct aa_ext *e, struct aa_audit *sa)
|
||||
+{
|
||||
+ /* get the interface version */
|
||||
+ if (!aa_is_u32(e, &e->version, "version")) {
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = operation;
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+ sa.info = "invalid profile format";
|
||||
+ aa_audit_status(NULL, &sa);
|
||||
+ sa->info = "invalid profile format";
|
||||
+ aa_audit_status(NULL, sa);
|
||||
+ return -EPROTONOSUPPORT;
|
||||
+ }
|
||||
+
|
||||
+ /* check that the interface version is currently supported */
|
||||
+ if (e->version != 4) {
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = operation;
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+ sa.info = "unsupported interface version";
|
||||
+ aa_audit_status(NULL, &sa);
|
||||
+ if (e->version != 5) {
|
||||
+ sa->info = "unsupported interface version";
|
||||
+ aa_audit_status(NULL, sa);
|
||||
+ return -EPROTONOSUPPORT;
|
||||
+ }
|
||||
+
|
||||
|
@ -878,11 +903,17 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ .pos = data,
|
||||
+ .ns_name = NULL
|
||||
+ };
|
||||
+ ssize_t error = aa_verify_header(&e, "profile_load");
|
||||
+ ssize_t error;
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "profile_load";
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+
|
||||
+ error = aa_verify_header(&e, &sa);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ profile = aa_unpack_profile(&e, "profile_load");
|
||||
+ profile = aa_unpack_profile(&e, &sa);
|
||||
+ if (IS_ERR(profile))
|
||||
+ return PTR_ERR(profile);
|
||||
+
|
||||
|
@ -914,6 +945,10 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ /* A profile with this name exists already. */
|
||||
+ write_unlock(&ns->lock);
|
||||
+ write_unlock(&profile_ns_list_lock);
|
||||
+ sa.name = profile->name;
|
||||
+ sa.name2 = ns->name;
|
||||
+ sa.info = "failed: profile already loaded";
|
||||
+ aa_audit_status(NULL, &sa);
|
||||
+ mutex_unlock(&aa_interface_lock);
|
||||
+ aa_put_profile(profile);
|
||||
+ return -EEXIST;
|
||||
|
@ -923,8 +958,11 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ list_add(&profile->list, &ns->profiles);
|
||||
+ write_unlock(&ns->lock);
|
||||
+ write_unlock(&profile_ns_list_lock);
|
||||
+ mutex_unlock(&aa_interface_lock);
|
||||
+
|
||||
+ sa.name = profile->name;
|
||||
+ sa.name2 = ns->name;
|
||||
+ aa_audit_status(NULL, &sa);
|
||||
+ mutex_unlock(&aa_interface_lock);
|
||||
+ return size;
|
||||
+}
|
||||
+
|
||||
|
@ -970,12 +1008,17 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ .pos = udata,
|
||||
+ .ns_name = NULL
|
||||
+ };
|
||||
+ ssize_t error;
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "profile_replace";
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+
|
||||
+ ssize_t error = aa_verify_header(&e, "profile_replace");
|
||||
+ error = aa_verify_header(&e, &sa);
|
||||
+ if (error)
|
||||
+ return error;
|
||||
+
|
||||
+ new_profile = aa_unpack_profile(&e, "profile_replace");
|
||||
+ new_profile = aa_unpack_profile(&e, &sa);
|
||||
+ if (IS_ERR(new_profile))
|
||||
+ return PTR_ERR(new_profile);
|
||||
+
|
||||
|
@ -1013,13 +1056,16 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ }
|
||||
+ new_profile->ns = aa_get_namespace(ns);
|
||||
+ ns->profile_count++;
|
||||
+ /* not don't need an extra ref count to keep new_profile as
|
||||
+ * it is protect by the interface mutex */
|
||||
+ list_add(&new_profile->list, &ns->profiles);
|
||||
+ write_unlock(&ns->lock);
|
||||
+ write_unlock(&profile_ns_list_lock);
|
||||
+
|
||||
+ if (!old_profile)
|
||||
+ if (!old_profile) {
|
||||
+ sa.operation = "profile_load";
|
||||
+ goto out;
|
||||
+
|
||||
+ }
|
||||
+ /*
|
||||
+ * Replacement needs to allocate a new aa_task_context for each
|
||||
+ * task confined by old_profile. To do this the profile locks
|
||||
|
@ -1048,6 +1094,9 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ aa_put_profile(old_profile);
|
||||
+
|
||||
+out:
|
||||
+ sa.name = new_profile->name;
|
||||
+ sa.name2 = ns->name;
|
||||
+ aa_audit_status(NULL, &sa);
|
||||
+ mutex_unlock(&aa_interface_lock);
|
||||
+ return size;
|
||||
+}
|
||||
|
@ -1064,29 +1113,35 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+{
|
||||
+ struct aa_namespace *ns;
|
||||
+ struct aa_profile *profile;
|
||||
+ struct aa_audit sa;
|
||||
+ memset(&sa, 0, sizeof(sa));
|
||||
+ sa.operation = "profile_remove";
|
||||
+ sa.gfp_mask = GFP_KERNEL;
|
||||
+
|
||||
+ mutex_lock(&aa_interface_lock);
|
||||
+ write_lock(&profile_ns_list_lock);
|
||||
+
|
||||
+ if (name[0] == '/') {
|
||||
+ ns = default_namespace;
|
||||
+ } else {
|
||||
+ char *split = strchr(name, ':');
|
||||
+ if (name[0] == ':') {
|
||||
+ char *split = strchr(name + 1, ':');
|
||||
+ if (!split)
|
||||
+ goto noent;
|
||||
+ *split = 0;
|
||||
+ ns = __aa_find_namespace(name, &profile_ns_list);
|
||||
+ ns = __aa_find_namespace(name + 1, &profile_ns_list);
|
||||
+ name = split + 1;
|
||||
+ } else {
|
||||
+ ns = default_namespace;
|
||||
+ }
|
||||
+
|
||||
+ if (!ns)
|
||||
+ goto noent;
|
||||
+ sa.name2 = ns->name;
|
||||
+ write_lock(&ns->lock);
|
||||
+ profile = __aa_find_profile(name, &ns->profiles);
|
||||
+ if (!profile) {
|
||||
+ write_unlock(&ns->lock);
|
||||
+ goto noent;
|
||||
+ }
|
||||
+ sa.name = profile->name;
|
||||
+
|
||||
+ /* Remove the profile from each task context it is on. */
|
||||
+ lock_profile(profile);
|
||||
|
@ -1103,6 +1158,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+ aa_put_namespace(ns);
|
||||
+ }
|
||||
+ write_unlock(&profile_ns_list_lock);
|
||||
+
|
||||
+ aa_audit_status(NULL, &sa);
|
||||
+ mutex_unlock(&aa_interface_lock);
|
||||
+ aa_put_profile(profile);
|
||||
+
|
||||
|
@ -1110,6 +1167,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
|||
+
|
||||
+noent:
|
||||
+ write_unlock(&profile_ns_list_lock);
|
||||
+ sa.info = "failed: profile does not exist";
|
||||
+ aa_audit_status(NULL, &sa);
|
||||
+ mutex_unlock(&aa_interface_lock);
|
||||
+ return -ENOENT;
|
||||
+}
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
security/apparmor/Makefile | 7 +
|
||||
security/apparmor/apparmor.h | 9 ++
|
||||
security/apparmor/lsm.c | 129 ++++++++++++++++++++++++++++++++++-
|
||||
security/apparmor/main.c | 106 ++++++++++++++++++++++++++++
|
||||
security/apparmor/module_interface.c | 20 +++++
|
||||
5 files changed, 267 insertions(+), 4 deletions(-)
|
||||
security/apparmor/main.c | 107 ++++++++++++++++++++++++++++-
|
||||
security/apparmor/module_interface.c | 26 ++++++-
|
||||
5 files changed, 271 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/security/apparmor/Makefile
|
||||
+++ b/security/apparmor/Makefile
|
||||
|
@ -32,7 +32,7 @@
|
|||
|
||||
/*
|
||||
* We use MAY_READ, MAY_WRITE, MAY_EXEC, MAY_APPEND and the following flags
|
||||
@@ -199,6 +201,9 @@ struct aa_profile {
|
||||
@@ -208,6 +210,9 @@ struct aa_profile {
|
||||
struct list_head task_contexts;
|
||||
spinlock_t lock;
|
||||
unsigned long int_flags;
|
||||
|
@ -42,7 +42,7 @@
|
|||
};
|
||||
|
||||
extern struct list_head profile_ns_list;
|
||||
@@ -245,6 +250,7 @@ struct aa_audit {
|
||||
@@ -254,6 +259,7 @@ struct aa_audit {
|
||||
int request_mask, denied_mask, audit_mask;
|
||||
struct iattr *iattr;
|
||||
pid_t task, parent;
|
||||
|
@ -50,7 +50,7 @@
|
|||
int error_code;
|
||||
};
|
||||
|
||||
@@ -306,6 +312,9 @@ extern void aa_change_task_context(struc
|
||||
@@ -315,6 +321,9 @@ extern void aa_change_task_context(struc
|
||||
struct aa_profile *previous_profile);
|
||||
extern int aa_may_ptrace(struct aa_task_context *cxt,
|
||||
struct aa_profile *tracee);
|
||||
|
@ -70,7 +70,7 @@
|
|||
|
||||
#include "apparmor.h"
|
||||
#include "inline.h"
|
||||
@@ -653,6 +654,117 @@ static void apparmor_task_free_security(
|
||||
@@ -663,6 +664,117 @@ static void apparmor_task_free_security(
|
||||
aa_release(task);
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@
|
|||
static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||
char **value)
|
||||
{
|
||||
@@ -753,9 +865,6 @@ struct security_operations apparmor_ops
|
||||
@@ -763,9 +875,6 @@ struct security_operations apparmor_ops
|
||||
.capable = apparmor_capable,
|
||||
.syslog = cap_syslog,
|
||||
|
||||
|
@ -198,7 +198,7 @@
|
|||
.bprm_apply_creds = cap_bprm_apply_creds,
|
||||
.bprm_set_security = apparmor_bprm_set_security,
|
||||
.bprm_secureexec = apparmor_bprm_secureexec,
|
||||
@@ -791,6 +900,20 @@ struct security_operations apparmor_ops
|
||||
@@ -801,6 +910,20 @@ struct security_operations apparmor_ops
|
||||
|
||||
.getprocattr = apparmor_getprocattr,
|
||||
.setprocattr = apparmor_setprocattr,
|
||||
|
@ -231,7 +231,7 @@
|
|||
|
||||
#include "apparmor.h"
|
||||
|
||||
@@ -133,6 +136,24 @@ static void aa_audit_file_mask(struct au
|
||||
@@ -116,6 +119,24 @@ static void aa_audit_file_mask(struct au
|
||||
audit_log_format(ab, " %s=\"%s::%s\"", name, user, other);
|
||||
}
|
||||
|
||||
|
@ -256,10 +256,11 @@
|
|||
/**
|
||||
* aa_audit - Log an audit event to the audit subsystem
|
||||
* @profile: profile to check against
|
||||
@@ -204,6 +225,25 @@ static int aa_audit_base(struct aa_profi
|
||||
@@ -187,7 +208,25 @@ static int aa_audit_base(struct aa_profi
|
||||
audit_log_untrustedstring(ab, sa->name2);
|
||||
}
|
||||
|
||||
- audit_log_format(ab, " pid=%d", current->pid);
|
||||
+ if (sa->family || sa->type) {
|
||||
+ if (address_families[sa->family])
|
||||
+ audit_log_format(ab, " family=\"%s\"",
|
||||
|
@ -279,10 +280,10 @@
|
|||
+ }
|
||||
+
|
||||
+ audit_log_format(ab, " pid=%d", current->pid);
|
||||
audit_log_format(ab, " pid=%d", current->pid);
|
||||
|
||||
if (profile) {
|
||||
@@ -766,6 +806,72 @@ int aa_link(struct aa_profile *profile,
|
||||
audit_log_format(ab, " profile=");
|
||||
@@ -768,6 +807,72 @@ int aa_link(struct aa_profile *profile,
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -357,16 +358,18 @@
|
|||
*******************************/
|
||||
--- a/security/apparmor/module_interface.c
|
||||
+++ b/security/apparmor/module_interface.c
|
||||
@@ -283,6 +283,8 @@ static struct aa_profile *aa_unpack_prof
|
||||
@@ -320,8 +320,8 @@ static struct aa_profile *aa_unpack_prof
|
||||
struct aa_audit *sa)
|
||||
{
|
||||
struct aa_profile *profile = NULL;
|
||||
struct aa_audit sa;
|
||||
-
|
||||
- int error = -EPROTO;
|
||||
+ size_t size = 0;
|
||||
+ int i;
|
||||
+ int i, error = -EPROTO;
|
||||
|
||||
int error = -EPROTO;
|
||||
|
||||
@@ -317,6 +319,24 @@ static struct aa_profile *aa_unpack_prof
|
||||
profile = alloc_aa_profile();
|
||||
if (!profile)
|
||||
@@ -354,6 +354,28 @@ static struct aa_profile *aa_unpack_prof
|
||||
if (!aa_is_u32(e, &(profile->set_caps), NULL))
|
||||
goto fail;
|
||||
|
||||
|
@ -378,6 +381,10 @@
|
|||
+ for (i = 0; i < size; i++) {
|
||||
+ if (!aa_is_u16(e, &profile->network_families[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u16(e, &profile->audit_network[i], NULL))
|
||||
+ goto fail;
|
||||
+ if (!aa_is_u16(e, &profile->quiet_network[i], NULL))
|
||||
+ goto fail;
|
||||
+ }
|
||||
+ if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
|
||||
+ goto fail;
|
||||
|
|
|
@ -1,3 +1,23 @@
|
|||
From: John Johansen <jjohansen@suse.de>
|
||||
Subject: AppArmor: per profile controls for system rlimits
|
||||
|
||||
Provide contol of rlimits on a per profile basis. Each profile provides
|
||||
a per limit contol and corresponding hard limit value, such that when a
|
||||
profile becomes attached to a task it sets the tasks limits to be <= to
|
||||
the profiles specified limits. Note: the profile limit value will not
|
||||
raise a tasks limit if it is already less than the profile mandates.
|
||||
|
||||
In addition to setting a tasks limits, the ability to set limits on
|
||||
a confined task are controlled. AppArmor only controls the raising
|
||||
of a tasks limits Tasks with CAP_SYS_RESOURCE can have their hard limits
|
||||
raised up to the value specified by the profile. AppArmor does not
|
||||
prevent a task for lowering its hard limits, nor does it provide
|
||||
additional control on soft limits.
|
||||
|
||||
AppArmor only controls the limits specified in a profile so that
|
||||
any limit not specified is free to be modified subject to standard
|
||||
linux limitations.
|
||||
|
||||
---
|
||||
security/apparmor/apparmor.h | 23 ++++++
|
||||
security/apparmor/apparmorfs.c | 2
|
||||
|
@ -16,7 +36,7 @@
|
|||
#include <linux/socket.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
@@ -129,6 +130,18 @@ extern unsigned int apparmor_path_max;
|
||||
@@ -136,6 +137,18 @@ extern unsigned int apparmor_path_max;
|
||||
|
||||
#define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
|
||||
|
||||
|
@ -35,7 +55,7 @@
|
|||
struct aa_profile;
|
||||
|
||||
/* struct aa_namespace - namespace for a set of profiles
|
||||
@@ -163,6 +176,8 @@ struct aa_namespace {
|
||||
@@ -170,6 +183,8 @@ struct aa_namespace {
|
||||
* @audit_caps: caps that are to be audited
|
||||
* @quiet_caps: caps that should not be audited
|
||||
* @capabilities: capabilities granted by the process
|
||||
|
@ -44,7 +64,7 @@
|
|||
* @count: reference count of the profile
|
||||
* @task_contexts: list of tasks confined by profile
|
||||
* @lock: lock for the task_contexts list
|
||||
@@ -197,6 +212,9 @@ struct aa_profile {
|
||||
@@ -206,6 +221,9 @@ struct aa_profile {
|
||||
kernel_cap_t audit_caps;
|
||||
kernel_cap_t quiet_caps;
|
||||
|
||||
|
@ -54,7 +74,7 @@
|
|||
struct kref count;
|
||||
struct list_head task_contexts;
|
||||
spinlock_t lock;
|
||||
@@ -248,6 +266,7 @@ struct aa_audit {
|
||||
@@ -257,6 +275,7 @@ struct aa_audit {
|
||||
const char *name2;
|
||||
const char *name3;
|
||||
int request_mask, denied_mask, audit_mask;
|
||||
|
@ -62,7 +82,7 @@
|
|||
struct iattr *iattr;
|
||||
pid_t task, parent;
|
||||
int family, type, protocol;
|
||||
@@ -315,6 +334,10 @@ extern int aa_may_ptrace(struct aa_task_
|
||||
@@ -324,6 +343,10 @@ extern int aa_may_ptrace(struct aa_task_
|
||||
extern int aa_net_perm(struct aa_profile *profile, char *operation,
|
||||
int family, int type, int protocol);
|
||||
extern int aa_revalidate_sk(struct sock *sk, char *operation);
|
||||
|
@ -86,7 +106,7 @@
|
|||
strlen(features));
|
||||
--- a/security/apparmor/lsm.c
|
||||
+++ b/security/apparmor/lsm.c
|
||||
@@ -856,6 +856,21 @@ static int apparmor_setprocattr(struct t
|
||||
@@ -866,6 +866,21 @@ static int apparmor_setprocattr(struct t
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -108,7 +128,7 @@
|
|||
struct security_operations apparmor_ops = {
|
||||
.ptrace = apparmor_ptrace,
|
||||
.capget = cap_capget,
|
||||
@@ -897,6 +912,7 @@ struct security_operations apparmor_ops
|
||||
@@ -907,6 +922,7 @@ struct security_operations apparmor_ops
|
||||
.task_free_security = apparmor_task_free_security,
|
||||
.task_post_setuid = cap_task_post_setuid,
|
||||
.task_reparent_to_init = cap_task_reparent_to_init,
|
||||
|
@ -118,7 +138,7 @@
|
|||
.setprocattr = apparmor_setprocattr,
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -176,6 +176,9 @@ static int aa_audit_base(struct aa_profi
|
||||
@@ -177,6 +177,9 @@ static int aa_audit_base(struct aa_profi
|
||||
if (sa->request_mask)
|
||||
audit_log_format(ab, " fsuid=%d", current->fsuid);
|
||||
|
||||
|
@ -128,7 +148,7 @@
|
|||
if (sa->iattr) {
|
||||
struct iattr *iattr = sa->iattr;
|
||||
|
||||
@@ -871,6 +874,79 @@ int aa_revalidate_sk(struct sock *sk, ch
|
||||
@@ -872,6 +875,79 @@ int aa_revalidate_sk(struct sock *sk, ch
|
||||
|
||||
return error;
|
||||
}
|
||||
|
@ -208,7 +228,7 @@
|
|||
|
||||
/*******************************
|
||||
* Global task related functions
|
||||
@@ -884,6 +960,7 @@ int aa_revalidate_sk(struct sock *sk, ch
|
||||
@@ -885,6 +961,7 @@ int aa_revalidate_sk(struct sock *sk, ch
|
||||
*/
|
||||
int aa_clone(struct task_struct *child)
|
||||
{
|
||||
|
@ -216,7 +236,7 @@
|
|||
struct aa_task_context *cxt, *child_cxt;
|
||||
struct aa_profile *profile;
|
||||
|
||||
@@ -893,6 +970,11 @@ int aa_clone(struct task_struct *child)
|
||||
@@ -894,6 +971,11 @@ int aa_clone(struct task_struct *child)
|
||||
if (!child_cxt)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -228,7 +248,7 @@
|
|||
repeat:
|
||||
profile = aa_get_profile(current);
|
||||
if (profile) {
|
||||
@@ -909,18 +991,22 @@ repeat:
|
||||
@@ -910,18 +992,22 @@ repeat:
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
|
@ -256,7 +276,7 @@
|
|||
aa_audit_hint(profile, &sa);
|
||||
}
|
||||
aa_put_profile(profile);
|
||||
@@ -1098,6 +1184,10 @@ repeat:
|
||||
@@ -1156,6 +1242,10 @@ repeat:
|
||||
sa.task = current->parent->pid;
|
||||
aa_audit_reject(profile, &sa);
|
||||
}
|
||||
|
@ -267,7 +287,7 @@
|
|||
new_profile = old_profile;
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -1237,6 +1327,12 @@ static int do_change_profile(struct aa_p
|
||||
@@ -1296,6 +1386,12 @@ static int do_change_profile(struct aa_p
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -280,7 +300,7 @@
|
|||
if (new_profile == ns->null_complain_profile)
|
||||
aa_audit_hint(cxt->profile, sa);
|
||||
|
||||
@@ -1425,17 +1521,18 @@ struct aa_profile *__aa_replace_profile(
|
||||
@@ -1482,17 +1578,18 @@ struct aa_profile *__aa_replace_profile(
|
||||
|
||||
cxt = lock_task_and_profiles(task, profile);
|
||||
if (unlikely(profile && profile->isstale)) {
|
||||
|
@ -307,7 +327,7 @@
|
|||
}
|
||||
|
||||
if (cxt)
|
||||
@@ -1443,8 +1540,15 @@ struct aa_profile *__aa_replace_profile(
|
||||
@@ -1500,8 +1597,15 @@ struct aa_profile *__aa_replace_profile(
|
||||
aa_change_task_context(task, new_cxt, profile, 0, NULL);
|
||||
|
||||
task_unlock(task);
|
||||
|
@ -323,7 +343,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
@@ -1509,6 +1613,7 @@ void aa_change_task_context(struct task_
|
||||
@@ -1566,6 +1670,7 @@ void aa_change_task_context(struct task_
|
||||
|
||||
if (old_cxt) {
|
||||
list_del_init(&old_cxt->list);
|
||||
|
@ -331,7 +351,7 @@
|
|||
call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
|
||||
}
|
||||
if (new_cxt) {
|
||||
@@ -1520,6 +1625,7 @@ void aa_change_task_context(struct task_
|
||||
@@ -1577,6 +1682,7 @@ void aa_change_task_context(struct task_
|
||||
new_cxt->cookie = cookie;
|
||||
new_cxt->task = task;
|
||||
new_cxt->profile = aa_dup_profile(profile);
|
||||
|
@ -364,8 +384,8 @@
|
|||
static size_t aa_is_array(struct aa_ext *e, const char *name)
|
||||
{
|
||||
void *pos = e->pos;
|
||||
@@ -273,6 +289,39 @@ struct aa_dfa *aa_unpack_dfa(struct aa_e
|
||||
return dfa;
|
||||
@@ -311,6 +327,39 @@ fail:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int aa_unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
|
||||
|
@ -404,7 +424,7 @@
|
|||
/**
|
||||
* aa_unpack_profile - unpack a serialized profile
|
||||
* @e: serialized data extent information
|
||||
@@ -319,6 +368,9 @@ static struct aa_profile *aa_unpack_prof
|
||||
@@ -354,6 +403,9 @@ static struct aa_profile *aa_unpack_prof
|
||||
if (!aa_is_u32(e, &(profile->set_caps), NULL))
|
||||
goto fail;
|
||||
|
||||
|
@ -414,16 +434,16 @@
|
|||
size = aa_is_array(e, "net_allowed_af");
|
||||
if (size) {
|
||||
if (size > AF_MAX)
|
||||
@@ -565,6 +617,8 @@ ssize_t aa_replace_profile(void *udata,
|
||||
if (!old_profile)
|
||||
@@ -613,6 +665,8 @@ ssize_t aa_replace_profile(void *udata,
|
||||
sa.operation = "profile_load";
|
||||
goto out;
|
||||
|
||||
}
|
||||
+ /* do not fail replacement based off of profile's NPROC rlimit */
|
||||
+
|
||||
/*
|
||||
* Replacement needs to allocate a new aa_task_context for each
|
||||
* task confined by old_profile. To do this the profile locks
|
||||
@@ -585,6 +639,7 @@ ssize_t aa_replace_profile(void *udata,
|
||||
@@ -633,6 +687,7 @@ ssize_t aa_replace_profile(void *udata,
|
||||
task_lock(task);
|
||||
task_replace(task, new_cxt, new_profile);
|
||||
task_unlock(task);
|
||||
|
@ -431,7 +451,7 @@
|
|||
new_cxt = NULL;
|
||||
}
|
||||
unlock_both_profiles(old_profile, new_profile);
|
||||
@@ -604,6 +659,7 @@ out:
|
||||
@@ -655,6 +710,7 @@ out:
|
||||
*
|
||||
* remove a profile from the profile list and all aa_task_context references
|
||||
* to said profile.
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
--- a/security/apparmor/main.c
|
||||
+++ b/security/apparmor/main.c
|
||||
@@ -176,8 +176,10 @@ static int aa_audit_base(struct aa_profi
|
||||
@@ -159,8 +159,10 @@ static int aa_audit_base(struct aa_profi
|
||||
return type == AUDIT_APPARMOR_ALLOWED ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,6 +110,7 @@ apparmor-intree.diff
|
|||
#FS2.2.2_fix-unionfs-with-AppArmor.patch
|
||||
#FS2.1.3_fix-unionfs-with-AppArmor.patch
|
||||
|
||||
#named-transitions.diff
|
||||
apparmor-network.diff
|
||||
#fix-net.diff
|
||||
apparmor-rlimits.diff
|
||||
|
|
Loading…
Add table
Reference in a new issue