latest version of the patches, updated off of 2.6.25 dev

This commit is contained in:
John Johansen 2008-04-19 23:08:39 +00:00
parent 8c5f77c4bd
commit d4856f9680
8 changed files with 385 additions and 221 deletions

View file

@ -7,12 +7,12 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de> Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
--- ---
security/apparmor/lsm.c | 879 ++++++++++++++++++++++++++++++++++++++++++++++++ security/apparmor/lsm.c | 889 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 879 insertions(+) 1 file changed, 889 insertions(+)
--- /dev/null --- /dev/null
+++ b/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c
@@ -0,0 +1,879 @@ @@ -0,0 +1,889 @@
+/* +/*
+ * Copyright (C) 1998-2007 Novell/SUSE + * 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 prot, unsigned long flags,
+ unsigned long addr, unsigned long addr_only) + 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); + return aa_mmap(file, "file_mmap", prot, flags);
+} +}
+ +

View file

@ -7,12 +7,12 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de> Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
--- ---
security/apparmor/main.c | 1421 +++++++++++++++++++++++++++++++++++++++++++++++ security/apparmor/main.c | 1479 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 1421 insertions(+) 1 file changed, 1479 insertions(+)
--- /dev/null --- /dev/null
+++ b/security/apparmor/main.c +++ b/security/apparmor/main.c
@@ -0,0 +1,1421 @@ @@ -0,0 +1,1479 @@
+/* +/*
+ * Copyright (C) 2002-2007 Novell/SUSE + * 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, +static void aa_audit_file_sub_mask(struct audit_buffer *ab, char *buffer,
+ int mask) + int mask)
+{ +{
+ const char unsafex[] = "upcn";
+ const char safex[] = "UPCN";
+ char *m = buffer; + char *m = buffer;
+ +
+ if (mask & AA_EXEC_MMAP) + if (mask & AA_EXEC_MMAP)
@ -95,37 +97,18 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ else if (mask & MAY_APPEND) + else if (mask & MAY_APPEND)
+ *m++ = 'a'; + *m++ = 'a';
+ if (mask & MAY_EXEC) { + if (mask & MAY_EXEC) {
+ if (mask & AA_EXEC_UNSAFE) { + int index = AA_EXEC_INDEX(mask);
+ switch(mask & AA_EXEC_MODIFIERS) { + /* all indexes > 4 are also named transitions */
+ case AA_EXEC_UNCONFINED: + if (index > 4)
+ *m++ = 'u'; + index = 4;
+ break; + if (index > 0) {
+ case AA_EXEC_PIX: + if (mask & AA_EXEC_UNSAFE)
+ *m++ = 'p'; + *m++ = unsafex[index - 1];
+ /* fall through */ + else
+ case AA_EXEC_INHERIT: + *m++ = safex[index - 1];
+ *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;
+ }
+ } + }
+ if (mask & AA_EXEC_INHERIT)
+ *m++ = 'i';
+ *m++ = 'x'; + *m++ = 'x';
+ } + }
+ if (mask & AA_MAY_LINK) + if (mask & AA_MAY_LINK)
@ -369,7 +352,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ int *request_mask, int *audit_mask) + int *request_mask, int *audit_mask)
+{ +{
+ unsigned int state; + 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; + int link_mask = AA_MAY_LINK << target_mode;
+ +
+ *request_mask = link_mask; + *request_mask = link_mask;
@ -393,7 +376,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ return denied_mask; + 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 + * If a subset test is required a permission subset test of the
+ * perms for the link are done against the user::other of the + * perms for the link are done against the user::other of the
+ * target's 'r', 'w', 'x', 'a', 'k', and 'm' permissions. + * 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); + 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, + /* For actual subset test ignore valid-profile-transition flags,
+ * and link bits + * and link bits
+ */ + */
@ -414,12 +401,20 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ *request_mask = l_mode | link_mask; + *request_mask = l_mode | link_mask;
+ +
+ if (l_mode) { + if (l_mode) {
+ int x = l_x | (t_x & ALL_AA_EXEC_UNSAFE);
+ denied_mask |= l_mode & ~t_mode; + denied_mask |= l_mode & ~t_mode;
+ if ((l_mode & AA_EXEC_BITS) && + /* mask off x modes not used by link */
+ (l_mode & ALL_AA_EXEC_TYPE) != +
+ (t_mode & ALL_AA_EXEC_TYPE)) + /* handle exec subset
+ denied_mask = (denied_mask & ~ALL_AA_EXEC_TYPE) | + * - link safe exec issubset of unsafe exec
+ (l_mode & (ALL_AA_EXEC_TYPE | AA_EXEC_BITS)); + * - 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; + 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) +static inline void aa_put_name_buffer(char *buffer)
+{ +{
+ kfree(buffer); + kfree(buffer);
@ -840,16 +842,37 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+} +}
+ +
+static struct aa_profile * +static struct aa_profile *
+aa_register_find(struct aa_profile *profile, const char *name, int mandatory, +aa_register_find(struct aa_profile *profile, const char* ns_name,
+ int complain, struct aa_audit *sa) + const char *name, int mandatory, int complain,
+ struct aa_audit *sa)
+{ +{
+ struct aa_namespace *ns;
+ struct aa_profile *new_profile; + 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 */ + /* Locate new profile */
+ if (profile) + new_profile = aa_find_profile(ns, name);
+ new_profile = aa_find_profile(profile->ns, name);
+ else
+ new_profile = aa_find_profile(default_namespace, name);
+ +
+ if (new_profile) { + if (new_profile) {
+ AA_DEBUG("%s: setting profile %s\n", + 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); + aa_dup_profile(profile->ns->null_complain_profile);
+ } else { + } else {
+ sa->error_code = -EACCES; + sa->error_code = -EACCES;
+ return ERR_PTR(aa_audit_file(profile, sa)); + if (ns_ref)
+ aa_put_namespace(ns);
+ return ERR_PTR(-EACCES);
+ } + }
+ } else { + } else {
+ /* Only way we can get into this code is if task + /* 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", + AA_DEBUG("%s: No profile found for exec image '%s'\n",
+ __FUNCTION__, + __FUNCTION__,
+ name); + 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; + return new_profile;
+} +}
+ +
@ -886,7 +975,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+int aa_register(struct linux_binprm *bprm) +int aa_register(struct linux_binprm *bprm)
+{ +{
+ const char *filename; + const char *filename;
+ char *buffer = NULL; + char *buffer = NULL, *child = NULL;
+ struct file *filp = bprm->file; + struct file *filp = bprm->file;
+ struct aa_profile *profile, *old_profile, *new_profile = NULL; + struct aa_profile *profile, *old_profile, *new_profile = NULL;
+ int exec_mode, complain = 0, shift; + int exec_mode, complain = 0, shift;
@ -907,7 +996,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ if (profile) { + if (profile) {
+ sa.info = "Failed name resolution - exec failed"; + sa.info = "Failed name resolution - exec failed";
+ sa.error_code = PTR_ERR(filename); + sa.error_code = PTR_ERR(filename);
+ aa_audit_reject(profile, &sa); + aa_audit_file(profile, &sa);
+ return sa.error_code; + return sa.error_code;
+ } else + } else
+ return 0; + return 0;
@ -926,46 +1015,16 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ exec_mode = aa_match(profile->file_rules, filename, + exec_mode = aa_match(profile->file_rules, filename,
+ &sa.audit_mask); + &sa.audit_mask);
+ +
+
+ if (exec_mode & sa.request_mask) { + if (exec_mode & sa.request_mask) {
+ switch ((exec_mode >> shift) & AA_EXEC_MODIFIERS) { + int xm = exec_mode >> shift;
+ case AA_EXEC_INHERIT: + new_profile = aa_x_to_profile(profile, filename,
+ AA_DEBUG("%s: INHERIT %s\n", + xm, &sa, &child);
+ __FUNCTION__, +
+ filename); + if (!new_profile && (xm & AA_EXEC_INHERIT))
+ /* nothing to be done here */ + /* (p|c|n|)ix - don't change profile */
+ goto cleanup; + goto cleanup;
+ + /* error case caught below */
+ 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;
+ }
+ +
+ } else if (sa.request_mask & AUDIT_QUIET_MASK(sa.audit_mask)) { + } else if (sa.request_mask & AUDIT_QUIET_MASK(sa.audit_mask)) {
+ /* quiet failed exit */ + /* quiet failed exit */
@ -985,7 +1044,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ } + }
+ } else { + } else {
+ /* Unconfined task, load profile if it exists */ + /* 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) + if (new_profile == NULL)
+ goto cleanup; + goto cleanup;
+ } + }
@ -1039,6 +1098,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ } + }
+ +
+cleanup: +cleanup:
+ aa_put_name_buffer(child);
+ aa_put_name_buffer(buffer); + aa_put_name_buffer(buffer);
+ if (IS_ERR(new_profile)) + if (IS_ERR(new_profile))
+ return PTR_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) +int aa_change_profile(const char *ns_name, const char *name)
+{ +{
+ struct aa_task_context *cxt; + struct aa_task_context *cxt;
+ struct aa_profile *profile; + struct aa_profile *profile = NULL;
+ struct aa_namespace *ns = NULL; + struct aa_namespace *ns = NULL;
+ struct aa_audit sa; + struct aa_audit sa;
+ unsigned int state; + unsigned int state;
@ -1196,23 +1256,23 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+repeat: +repeat:
+ task_lock(current); + task_lock(current);
+ cxt = aa_task_context(current); + cxt = aa_task_context(current);
+ if (!cxt) { + if (cxt)
+ task_unlock(current); + profile = aa_dup_profile(cxt->profile);
+ return -EPERM;
+ }
+ profile = aa_dup_profile(cxt->profile);
+ task_unlock(current); + task_unlock(current);
+ +
+ if (ns_name) + if (ns_name)
+ ns = aa_find_namespace(ns_name); + ns = aa_find_namespace(ns_name);
+ else + else if (profile)
+ ns = aa_get_namespace(profile->ns); + ns = aa_get_namespace(profile->ns);
+ else
+ ns = aa_get_namespace(default_namespace);
+
+ if (!ns) { + if (!ns) {
+ aa_put_profile(profile); + aa_put_profile(profile);
+ return -ENOENT; + return -ENOENT;
+ } + }
+ +
+ if (PROFILE_COMPLAIN(profile) || + if (!profile || PROFILE_COMPLAIN(profile) ||
+ (ns == profile->ns && + (ns == profile->ns &&
+ (aa_match(profile->file_rules, name, NULL) & AA_CHANGE_PROFILE))) + (aa_match(profile->file_rules, name, NULL) & AA_CHANGE_PROFILE)))
+ error = do_change_profile(profile, ns, name, 0, 0, &sa); + error = do_change_profile(profile, ns, name, 0, 0, &sa);
@ -1287,16 +1347,14 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ else + else
+ profile_name = profile->name; + profile_name = profile->name;
+ +
+ name = kmalloc(strlen(hat_name) + 3 + strlen(profile_name), + name = new_compound_name(profile_name, hat_name);
+ GFP_KERNEL);
+ if (!name) { + if (!name) {
+ error = -ENOMEM; + error = -ENOMEM;
+ goto out; + goto out;
+ } + }
+ sprintf(name, "%s//%s", profile_name, hat_name);
+ error = do_change_profile(profile, profile->ns, name, cookie, + error = do_change_profile(profile, profile->ns, name, cookie,
+ 0, &sa); + 0, &sa);
+ kfree(name); + aa_put_name_buffer(name);
+ } else if (previous_profile) + } else if (previous_profile)
+ error = do_change_profile(profile, profile->ns, + error = do_change_profile(profile, profile->ns,
+ previous_profile->name, cookie, 1, + previous_profile->name, cookie, 1,

View file

@ -13,13 +13,13 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
--- ---
security/apparmor/Kconfig | 42 ++++ security/apparmor/Kconfig | 42 ++++
security/apparmor/Makefile | 13 + security/apparmor/Makefile | 13 +
security/apparmor/apparmor.h | 358 +++++++++++++++++++++++++++++++++++++++++ security/apparmor/apparmor.h | 367 +++++++++++++++++++++++++++++++++++++++++
security/apparmor/apparmorfs.c | 280 ++++++++++++++++++++++++++++++++ security/apparmor/apparmorfs.c | 280 +++++++++++++++++++++++++++++++
security/apparmor/inline.h | 250 ++++++++++++++++++++++++++++ security/apparmor/inline.h | 250 +++++++++++++++++++++++++++
security/apparmor/list.c | 156 +++++++++++++++++ security/apparmor/list.c | 156 +++++++++++++++++
security/apparmor/locking.txt | 68 +++++++ security/apparmor/locking.txt | 68 +++++++
security/apparmor/procattr.c | 195 ++++++++++++++++++++++ security/apparmor/procattr.c | 195 +++++++++++++++++++++
8 files changed, 1362 insertions(+) 8 files changed, 1371 insertions(+)
--- /dev/null --- /dev/null
+++ b/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig
@ -84,7 +84,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ $(call cmd,make-caps) + $(call cmd,make-caps)
--- /dev/null --- /dev/null
+++ b/security/apparmor/apparmor.h +++ b/security/apparmor/apparmor.h
@@ -0,0 +1,358 @@ @@ -0,0 +1,367 @@
+/* +/*
+ * Copyright (C) 1998-2007 Novell/SUSE + * 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_EXEC_MMAP 0x0040
+#define AA_MAY_MOUNT 0x0080 /* no direct audit mapping */ +#define AA_MAY_MOUNT 0x0080 /* no direct audit mapping */
+#define AA_EXEC_UNSAFE 0x0100 +#define AA_EXEC_UNSAFE 0x0100
+#define AA_EXEC_MOD_0 0x0200 +#define AA_EXEC_INHERIT 0x0200
+#define AA_EXEC_MOD_1 0x0400 +#define AA_EXEC_MOD_0 0x0400
+#define AA_EXEC_MOD_2 0x0800 +#define AA_EXEC_MOD_1 0x0800
+#define AA_EXEC_MOD_3 0x1000 +#define AA_EXEC_MOD_2 0x1000
+#define AA_EXEC_MOD_4 0x2000 +#define AA_EXEC_MOD_3 0x2000
+ +
+#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \ +#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \
+ MAY_APPEND | AA_MAY_LINK | \ + MAY_APPEND | AA_MAY_LINK | \
+ AA_MAY_LOCK | AA_EXEC_MMAP | \ + AA_MAY_LOCK | AA_EXEC_MMAP | \
+ AA_MAY_MOUNT | AA_EXEC_UNSAFE | \ + AA_MAY_MOUNT | AA_EXEC_UNSAFE | \
+ AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \ + AA_EXEC_INHERIT | AA_EXEC_MOD_0 | \
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \ + AA_EXEC_MOD_1 | AA_EXEC_MOD_2 | \
+ AA_EXEC_MOD_4) + AA_EXEC_MOD_3)
+ +
+#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \ +#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \ + AA_EXEC_MOD_2 | AA_EXEC_MOD_3)
+ AA_EXEC_MOD_4)
+ +
+#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_UNCONFINED AA_EXEC_MOD_0
+#define AA_EXEC_INHERIT AA_EXEC_MOD_1 +#define AA_EXEC_PROFILE AA_EXEC_MOD_1
+#define AA_EXEC_PROFILE (AA_EXEC_MOD_0 | AA_EXEC_MOD_1) +#define AA_EXEC_CHILD (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
+#define AA_EXEC_PIX AA_EXEC_MOD_2 +/* 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_USER_SHIFT 0
+#define AA_OTHER_SHIFT 14 +#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 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) +#define ALL_AA_EXEC_TYPE (AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE)
+ +
+/* overloaded permissions for link pairs */ +/* overloaded permissions for link pairs */
+#define AA_LINK_SUBSET_TEST 0x0020 +#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 */ +/* shared permissions that are not duplicated in user::other */
+#define AA_AUDIT_FIELD 0x10000000 +#define AA_CHANGE_HAT 0x40000000
+#define AA_CHANGE_HAT 0x20000000 +#define AA_CHANGE_PROFILE 0x80000000
+#define AA_CHANGE_PROFILE 0x40000000
+ +
+#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE | \ +#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE)
+ AA_AUDIT_FIELD)
+ +
+#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 */ +/* audit bits for the second accept field */
+#define AUDIT_FILE_MASK 0x1fc07f +#define AUDIT_FILE_MASK 0x1fc07f
@ -270,6 +277,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ struct list_head list; + struct list_head list;
+ struct aa_namespace *ns; + struct aa_namespace *ns;
+ +
+ int exec_table_size;
+ char **exec_table;
+ struct aa_dfa *file_rules; + struct aa_dfa *file_rules;
+ struct { + struct {
+ int complain; + int complain;

View file

@ -8,10 +8,10 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@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/match.h | 87 +++
security/apparmor/module_interface.c | 815 +++++++++++++++++++++++++++++++++++ security/apparmor/module_interface.c | 874 +++++++++++++++++++++++++++++++++++
3 files changed, 1266 insertions(+) 3 files changed, 1325 insertions(+)
--- /dev/null --- /dev/null
+++ b/security/apparmor/match.c +++ b/security/apparmor/match.c
@ -472,7 +472,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+#endif /* __MATCH_H */ +#endif /* __MATCH_H */
--- /dev/null --- /dev/null
+++ b/security/apparmor/module_interface.c +++ b/security/apparmor/module_interface.c
@@ -0,0 +1,815 @@ @@ -0,0 +1,874 @@
+/* +/*
+ * Copyright (C) 1998-2007 Novell/SUSE + * Copyright (C) 1998-2007 Novell/SUSE
+ * + *
@ -716,7 +716,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ * + *
+ * returns dfa or ERR_PTR + * 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; + char *blob = NULL;
+ size_t size, error = 0; + size_t size, error = 0;
@ -748,16 +748,53 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ return dfa; + 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 + * aa_unpack_profile - unpack a serialized profile
+ * @e: serialized data extent information + * @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, +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_profile *profile = NULL;
+ struct aa_audit sa;
+ +
+ int error = -EPROTO; + int error = -EPROTO;
+ +
@ -798,25 +835,21 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ error = PTR_ERR(profile->file_rules); + error = PTR_ERR(profile->file_rules);
+ profile->file_rules = NULL; + profile->file_rules = NULL;
+ goto fail; + 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)) + if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
+ goto fail; + goto fail;
+ +
+ return profile; + return profile;
+ +
+fail: +fail:
+ memset(&sa, 0, sizeof(sa)); + sa->name = profile && profile->name ? profile->name : "unknown";
+ sa.operation = operation; + if (!sa->info)
+ sa.gfp_mask = GFP_KERNEL; + sa->info = "failed to unpack profile";
+ sa.name = profile && profile->name ? profile->name : "unknown"; + aa_audit_status(NULL, sa);
+ if (!sa.info)
+ sa.info = "failed to unpack profile";
+ aa_audit_status(NULL, &sa);
+ +
+ if (profile) + if (profile)
+ free_aa_profile(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 + * 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 */ + /* get the interface version */
+ if (!aa_is_u32(e, &e->version, "version")) { + if (!aa_is_u32(e, &e->version, "version")) {
+ struct aa_audit sa; + sa->info = "invalid profile format";
+ memset(&sa, 0, sizeof(sa)); + aa_audit_status(NULL, sa);
+ sa.operation = operation;
+ sa.gfp_mask = GFP_KERNEL;
+ sa.info = "invalid profile format";
+ aa_audit_status(NULL, &sa);
+ return -EPROTONOSUPPORT; + return -EPROTONOSUPPORT;
+ } + }
+ +
+ /* check that the interface version is currently supported */ + /* check that the interface version is currently supported */
+ if (e->version != 4) { + if (e->version != 5) {
+ struct aa_audit sa; + sa->info = "unsupported interface version";
+ memset(&sa, 0, sizeof(sa)); + aa_audit_status(NULL, sa);
+ sa.operation = operation;
+ sa.gfp_mask = GFP_KERNEL;
+ sa.info = "unsupported interface version";
+ aa_audit_status(NULL, &sa);
+ return -EPROTONOSUPPORT; + return -EPROTONOSUPPORT;
+ } + }
+ +
@ -878,11 +903,17 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ .pos = data, + .pos = data,
+ .ns_name = NULL + .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) + if (error)
+ return error; + return error;
+ +
+ profile = aa_unpack_profile(&e, "profile_load"); + profile = aa_unpack_profile(&e, &sa);
+ if (IS_ERR(profile)) + if (IS_ERR(profile))
+ return PTR_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. */ + /* A profile with this name exists already. */
+ write_unlock(&ns->lock); + write_unlock(&ns->lock);
+ write_unlock(&profile_ns_list_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); + mutex_unlock(&aa_interface_lock);
+ aa_put_profile(profile); + aa_put_profile(profile);
+ return -EEXIST; + return -EEXIST;
@ -923,8 +958,11 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ list_add(&profile->list, &ns->profiles); + list_add(&profile->list, &ns->profiles);
+ write_unlock(&ns->lock); + write_unlock(&ns->lock);
+ write_unlock(&profile_ns_list_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; + return size;
+} +}
+ +
@ -970,12 +1008,17 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ .pos = udata, + .pos = udata,
+ .ns_name = NULL + .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) + if (error)
+ return error; + return error;
+ +
+ new_profile = aa_unpack_profile(&e, "profile_replace"); + new_profile = aa_unpack_profile(&e, &sa);
+ if (IS_ERR(new_profile)) + if (IS_ERR(new_profile))
+ return PTR_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); + new_profile->ns = aa_get_namespace(ns);
+ ns->profile_count++; + 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); + list_add(&new_profile->list, &ns->profiles);
+ write_unlock(&ns->lock); + write_unlock(&ns->lock);
+ write_unlock(&profile_ns_list_lock); + write_unlock(&profile_ns_list_lock);
+ +
+ if (!old_profile) + if (!old_profile) {
+ sa.operation = "profile_load";
+ goto out; + goto out;
+ + }
+ /* + /*
+ * Replacement needs to allocate a new aa_task_context for each + * Replacement needs to allocate a new aa_task_context for each
+ * task confined by old_profile. To do this the profile locks + * 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); + aa_put_profile(old_profile);
+ +
+out: +out:
+ sa.name = new_profile->name;
+ sa.name2 = ns->name;
+ aa_audit_status(NULL, &sa);
+ mutex_unlock(&aa_interface_lock); + mutex_unlock(&aa_interface_lock);
+ return size; + return size;
+} +}
@ -1064,29 +1113,35 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+{ +{
+ struct aa_namespace *ns; + struct aa_namespace *ns;
+ struct aa_profile *profile; + 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); + mutex_lock(&aa_interface_lock);
+ write_lock(&profile_ns_list_lock); + write_lock(&profile_ns_list_lock);
+ +
+ if (name[0] == '/') { + if (name[0] == ':') {
+ ns = default_namespace; + char *split = strchr(name + 1, ':');
+ } else {
+ char *split = strchr(name, ':');
+ if (!split) + if (!split)
+ goto noent; + goto noent;
+ *split = 0; + *split = 0;
+ ns = __aa_find_namespace(name, &profile_ns_list); + ns = __aa_find_namespace(name + 1, &profile_ns_list);
+ name = split + 1; + name = split + 1;
+ } else {
+ ns = default_namespace;
+ } + }
+ +
+ if (!ns) + if (!ns)
+ goto noent; + goto noent;
+ sa.name2 = ns->name;
+ write_lock(&ns->lock); + write_lock(&ns->lock);
+ profile = __aa_find_profile(name, &ns->profiles); + profile = __aa_find_profile(name, &ns->profiles);
+ if (!profile) { + if (!profile) {
+ write_unlock(&ns->lock); + write_unlock(&ns->lock);
+ goto noent; + goto noent;
+ } + }
+ sa.name = profile->name;
+ +
+ /* Remove the profile from each task context it is on. */ + /* Remove the profile from each task context it is on. */
+ lock_profile(profile); + lock_profile(profile);
@ -1103,6 +1158,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ aa_put_namespace(ns); + aa_put_namespace(ns);
+ } + }
+ write_unlock(&profile_ns_list_lock); + write_unlock(&profile_ns_list_lock);
+
+ aa_audit_status(NULL, &sa);
+ mutex_unlock(&aa_interface_lock); + mutex_unlock(&aa_interface_lock);
+ aa_put_profile(profile); + aa_put_profile(profile);
+ +
@ -1110,6 +1167,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
+ +
+noent: +noent:
+ write_unlock(&profile_ns_list_lock); + write_unlock(&profile_ns_list_lock);
+ sa.info = "failed: profile does not exist";
+ aa_audit_status(NULL, &sa);
+ mutex_unlock(&aa_interface_lock); + mutex_unlock(&aa_interface_lock);
+ return -ENOENT; + return -ENOENT;
+} +}

View file

@ -2,9 +2,9 @@
security/apparmor/Makefile | 7 + security/apparmor/Makefile | 7 +
security/apparmor/apparmor.h | 9 ++ security/apparmor/apparmor.h | 9 ++
security/apparmor/lsm.c | 129 ++++++++++++++++++++++++++++++++++- security/apparmor/lsm.c | 129 ++++++++++++++++++++++++++++++++++-
security/apparmor/main.c | 106 ++++++++++++++++++++++++++++ security/apparmor/main.c | 107 ++++++++++++++++++++++++++++-
security/apparmor/module_interface.c | 20 +++++ security/apparmor/module_interface.c | 26 ++++++-
5 files changed, 267 insertions(+), 4 deletions(-) 5 files changed, 271 insertions(+), 7 deletions(-)
--- a/security/apparmor/Makefile --- a/security/apparmor/Makefile
+++ b/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 * 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; struct list_head task_contexts;
spinlock_t lock; spinlock_t lock;
unsigned long int_flags; unsigned long int_flags;
@ -42,7 +42,7 @@
}; };
extern struct list_head profile_ns_list; 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; int request_mask, denied_mask, audit_mask;
struct iattr *iattr; struct iattr *iattr;
pid_t task, parent; pid_t task, parent;
@ -50,7 +50,7 @@
int error_code; 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); struct aa_profile *previous_profile);
extern int aa_may_ptrace(struct aa_task_context *cxt, extern int aa_may_ptrace(struct aa_task_context *cxt,
struct aa_profile *tracee); struct aa_profile *tracee);
@ -70,7 +70,7 @@
#include "apparmor.h" #include "apparmor.h"
#include "inline.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); aa_release(task);
} }
@ -188,7 +188,7 @@
static int apparmor_getprocattr(struct task_struct *task, char *name, static int apparmor_getprocattr(struct task_struct *task, char *name,
char **value) char **value)
{ {
@@ -753,9 +865,6 @@ struct security_operations apparmor_ops @@ -763,9 +875,6 @@ struct security_operations apparmor_ops
.capable = apparmor_capable, .capable = apparmor_capable,
.syslog = cap_syslog, .syslog = cap_syslog,
@ -198,7 +198,7 @@
.bprm_apply_creds = cap_bprm_apply_creds, .bprm_apply_creds = cap_bprm_apply_creds,
.bprm_set_security = apparmor_bprm_set_security, .bprm_set_security = apparmor_bprm_set_security,
.bprm_secureexec = apparmor_bprm_secureexec, .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, .getprocattr = apparmor_getprocattr,
.setprocattr = apparmor_setprocattr, .setprocattr = apparmor_setprocattr,
@ -231,7 +231,7 @@
#include "apparmor.h" #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); audit_log_format(ab, " %s=\"%s::%s\"", name, user, other);
} }
@ -256,10 +256,11 @@
/** /**
* aa_audit - Log an audit event to the audit subsystem * aa_audit - Log an audit event to the audit subsystem
* @profile: profile to check against * @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_untrustedstring(ab, sa->name2);
} }
- audit_log_format(ab, " pid=%d", current->pid);
+ if (sa->family || sa->type) { + if (sa->family || sa->type) {
+ if (address_families[sa->family]) + if (address_families[sa->family])
+ audit_log_format(ab, " family=\"%s\"", + 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);
audit_log_format(ab, " pid=%d", current->pid);
if (profile) { 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; return error;
} }
@ -357,16 +358,18 @@
*******************************/ *******************************/
--- a/security/apparmor/module_interface.c --- a/security/apparmor/module_interface.c
+++ b/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_profile *profile = NULL;
struct aa_audit sa; -
- int error = -EPROTO;
+ size_t size = 0; + size_t size = 0;
+ int i; + int i, error = -EPROTO;
int error = -EPROTO; profile = alloc_aa_profile();
if (!profile)
@@ -317,6 +319,24 @@ static struct aa_profile *aa_unpack_prof @@ -354,6 +354,28 @@ static struct aa_profile *aa_unpack_prof
if (!aa_is_u32(e, &(profile->set_caps), NULL)) if (!aa_is_u32(e, &(profile->set_caps), NULL))
goto fail; goto fail;
@ -378,6 +381,10 @@
+ for (i = 0; i < size; i++) { + for (i = 0; i < size; i++) {
+ if (!aa_is_u16(e, &profile->network_families[i], NULL)) + if (!aa_is_u16(e, &profile->network_families[i], NULL))
+ goto fail; + 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)) + if (!aa_is_nameX(e, AA_ARRAYEND, NULL))
+ goto fail; + goto fail;

View file

@ -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/apparmor.h | 23 ++++++
security/apparmor/apparmorfs.c | 2 security/apparmor/apparmorfs.c | 2
@ -16,7 +36,7 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <net/sock.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) #define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
@ -35,7 +55,7 @@
struct aa_profile; struct aa_profile;
/* struct aa_namespace - namespace for a set of profiles /* 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 * @audit_caps: caps that are to be audited
* @quiet_caps: caps that should not be audited * @quiet_caps: caps that should not be audited
* @capabilities: capabilities granted by the process * @capabilities: capabilities granted by the process
@ -44,7 +64,7 @@
* @count: reference count of the profile * @count: reference count of the profile
* @task_contexts: list of tasks confined by profile * @task_contexts: list of tasks confined by profile
* @lock: lock for the task_contexts list * @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 audit_caps;
kernel_cap_t quiet_caps; kernel_cap_t quiet_caps;
@ -54,7 +74,7 @@
struct kref count; struct kref count;
struct list_head task_contexts; struct list_head task_contexts;
spinlock_t lock; spinlock_t lock;
@@ -248,6 +266,7 @@ struct aa_audit { @@ -257,6 +275,7 @@ struct aa_audit {
const char *name2; const char *name2;
const char *name3; const char *name3;
int request_mask, denied_mask, audit_mask; int request_mask, denied_mask, audit_mask;
@ -62,7 +82,7 @@
struct iattr *iattr; struct iattr *iattr;
pid_t task, parent; pid_t task, parent;
int family, type, protocol; 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, extern int aa_net_perm(struct aa_profile *profile, char *operation,
int family, int type, int protocol); int family, int type, int protocol);
extern int aa_revalidate_sk(struct sock *sk, char *operation); extern int aa_revalidate_sk(struct sock *sk, char *operation);
@ -86,7 +106,7 @@
strlen(features)); strlen(features));
--- a/security/apparmor/lsm.c --- a/security/apparmor/lsm.c
+++ b/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; return error;
} }
@ -108,7 +128,7 @@
struct security_operations apparmor_ops = { struct security_operations apparmor_ops = {
.ptrace = apparmor_ptrace, .ptrace = apparmor_ptrace,
.capget = cap_capget, .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_free_security = apparmor_task_free_security,
.task_post_setuid = cap_task_post_setuid, .task_post_setuid = cap_task_post_setuid,
.task_reparent_to_init = cap_task_reparent_to_init, .task_reparent_to_init = cap_task_reparent_to_init,
@ -118,7 +138,7 @@
.setprocattr = apparmor_setprocattr, .setprocattr = apparmor_setprocattr,
--- a/security/apparmor/main.c --- a/security/apparmor/main.c
+++ b/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) if (sa->request_mask)
audit_log_format(ab, " fsuid=%d", current->fsuid); audit_log_format(ab, " fsuid=%d", current->fsuid);
@ -128,7 +148,7 @@
if (sa->iattr) { if (sa->iattr) {
struct iattr *iattr = 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; return error;
} }
@ -208,7 +228,7 @@
/******************************* /*******************************
* Global task related functions * 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) int aa_clone(struct task_struct *child)
{ {
@ -216,7 +236,7 @@
struct aa_task_context *cxt, *child_cxt; struct aa_task_context *cxt, *child_cxt;
struct aa_profile *profile; 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) if (!child_cxt)
return -ENOMEM; return -ENOMEM;
@ -228,7 +248,7 @@
repeat: repeat:
profile = aa_get_profile(current); profile = aa_get_profile(current);
if (profile) { if (profile) {
@@ -909,18 +991,22 @@ repeat: @@ -910,18 +992,22 @@ repeat:
goto repeat; goto repeat;
} }
@ -256,7 +276,7 @@
aa_audit_hint(profile, &sa); aa_audit_hint(profile, &sa);
} }
aa_put_profile(profile); aa_put_profile(profile);
@@ -1098,6 +1184,10 @@ repeat: @@ -1156,6 +1242,10 @@ repeat:
sa.task = current->parent->pid; sa.task = current->parent->pid;
aa_audit_reject(profile, &sa); aa_audit_reject(profile, &sa);
} }
@ -267,7 +287,7 @@
new_profile = old_profile; new_profile = old_profile;
goto cleanup; 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; goto out;
} }
@ -280,7 +300,7 @@
if (new_profile == ns->null_complain_profile) if (new_profile == ns->null_complain_profile)
aa_audit_hint(cxt->profile, sa); 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); cxt = lock_task_and_profiles(task, profile);
if (unlikely(profile && profile->isstale)) { if (unlikely(profile && profile->isstale)) {
@ -307,7 +327,7 @@
} }
if (cxt) 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); aa_change_task_context(task, new_cxt, profile, 0, NULL);
task_unlock(task); 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) { if (old_cxt) {
list_del_init(&old_cxt->list); list_del_init(&old_cxt->list);
@ -331,7 +351,7 @@
call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback); call_rcu(&old_cxt->rcu, free_aa_task_context_rcu_callback);
} }
if (new_cxt) { 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->cookie = cookie;
new_cxt->task = task; new_cxt->task = task;
new_cxt->profile = aa_dup_profile(profile); new_cxt->profile = aa_dup_profile(profile);
@ -364,8 +384,8 @@
static size_t aa_is_array(struct aa_ext *e, const char *name) static size_t aa_is_array(struct aa_ext *e, const char *name)
{ {
void *pos = e->pos; void *pos = e->pos;
@@ -273,6 +289,39 @@ struct aa_dfa *aa_unpack_dfa(struct aa_e @@ -311,6 +327,39 @@ fail:
return dfa; return 0;
} }
+int aa_unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) +int aa_unpack_rlimits(struct aa_ext *e, struct aa_profile *profile)
@ -404,7 +424,7 @@
/** /**
* aa_unpack_profile - unpack a serialized profile * aa_unpack_profile - unpack a serialized profile
* @e: serialized data extent information * @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)) if (!aa_is_u32(e, &(profile->set_caps), NULL))
goto fail; goto fail;
@ -414,16 +434,16 @@
size = aa_is_array(e, "net_allowed_af"); size = aa_is_array(e, "net_allowed_af");
if (size) { if (size) {
if (size > AF_MAX) if (size > AF_MAX)
@@ -565,6 +617,8 @@ ssize_t aa_replace_profile(void *udata, @@ -613,6 +665,8 @@ ssize_t aa_replace_profile(void *udata,
if (!old_profile) sa.operation = "profile_load";
goto out; goto out;
}
+ /* do not fail replacement based off of profile's NPROC rlimit */ + /* do not fail replacement based off of profile's NPROC rlimit */
+ +
/* /*
* Replacement needs to allocate a new aa_task_context for each * Replacement needs to allocate a new aa_task_context for each
* task confined by old_profile. To do this the profile locks * 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_lock(task);
task_replace(task, new_cxt, new_profile); task_replace(task, new_cxt, new_profile);
task_unlock(task); task_unlock(task);
@ -431,7 +451,7 @@
new_cxt = NULL; new_cxt = NULL;
} }
unlock_both_profiles(old_profile, new_profile); 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 * remove a profile from the profile list and all aa_task_context references
* to said profile. * to said profile.

View file

@ -4,7 +4,7 @@
--- a/security/apparmor/main.c --- a/security/apparmor/main.c
+++ b/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; return type == AUDIT_APPARMOR_ALLOWED ? 0 : -ENOMEM;
} }

View file

@ -110,6 +110,7 @@ apparmor-intree.diff
#FS2.2.2_fix-unionfs-with-AppArmor.patch #FS2.2.2_fix-unionfs-with-AppArmor.patch
#FS2.1.3_fix-unionfs-with-AppArmor.patch #FS2.1.3_fix-unionfs-with-AppArmor.patch
#named-transitions.diff
apparmor-network.diff apparmor-network.diff
#fix-net.diff #fix-net.diff
apparmor-rlimits.diff apparmor-rlimits.diff