diff options
author | James Morris <james.l.morris@oracle.com> | 2017-12-11 17:01:08 +1100 |
---|---|---|
committer | James Morris <james.l.morris@oracle.com> | 2017-12-11 17:01:08 +1100 |
commit | d21bd6898336a7892914d308d5e0868f0b863571 (patch) | |
tree | f5f756c25348b5a6c1ce9ddbaa7d1ecd1bef40b0 /security/apparmor | |
parent | 34d8751fd4ffa34e85ee7e85d34168b3f3f62b42 (diff) | |
parent | 50c4c4e268a2d7a3e58ebb698ac74da0de40ae36 (diff) | |
download | op-kernel-dev-d21bd6898336a7892914d308d5e0868f0b863571.zip op-kernel-dev-d21bd6898336a7892914d308d5e0868f0b863571.tar.gz |
Sync to v4.15-rc3 for security subsystem developers to work against.
Diffstat (limited to 'security/apparmor')
-rw-r--r-- | security/apparmor/.gitignore | 1 | ||||
-rw-r--r-- | security/apparmor/Makefile | 44 | ||||
-rw-r--r-- | security/apparmor/apparmorfs.c | 25 | ||||
-rw-r--r-- | security/apparmor/domain.c | 68 | ||||
-rw-r--r-- | security/apparmor/file.c | 38 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 16 | ||||
-rw-r--r-- | security/apparmor/include/lib.h | 13 | ||||
-rw-r--r-- | security/apparmor/include/net.h | 114 | ||||
-rw-r--r-- | security/apparmor/include/perms.h | 5 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 13 | ||||
-rw-r--r-- | security/apparmor/ipc.c | 4 | ||||
-rw-r--r-- | security/apparmor/label.c | 10 | ||||
-rw-r--r-- | security/apparmor/lib.c | 21 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 411 | ||||
-rw-r--r-- | security/apparmor/mount.c | 13 | ||||
-rw-r--r-- | security/apparmor/net.c | 184 | ||||
-rw-r--r-- | security/apparmor/policy.c | 11 | ||||
-rw-r--r-- | security/apparmor/policy_ns.c | 8 | ||||
-rw-r--r-- | security/apparmor/policy_unpack.c | 49 | ||||
-rw-r--r-- | security/apparmor/resource.c | 4 |
20 files changed, 120 insertions, 932 deletions
diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore index d5b291e..9cdec70 100644 --- a/security/apparmor/.gitignore +++ b/security/apparmor/.gitignore @@ -1,6 +1,5 @@ # # Generated include files # -net_names.h capability_names.h rlim_names.h diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index dafdd38..9a6b403 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -1,47 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0 # Makefile for AppArmor Linux Security Module # obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ - resource.o secid.o file.o policy_ns.o label.o mount.o net.o + resource.o secid.o file.o policy_ns.o label.o mount.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o -clean-files := capability_names.h rlim_names.h net_names.h +clean-files := capability_names.h rlim_names.h -# Build a lower case string table of address family names -# Transform lines from -# #define AF_LOCAL 1 /* POSIX name for AF_UNIX */ -# #define AF_INET 2 /* Internet IP Protocol */ -# to -# [1] = "local", -# [2] = "inet", -# -# and build the securityfs entries for the mapping. -# Transforms lines from -# #define AF_INET 2 /* Internet IP Protocol */ -# to -# #define AA_SFS_AF_MASK "local inet" -quiet_cmd_make-af = GEN $@ -cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ - sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ - 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ - echo "};" >> $@ ;\ - printf '%s' '\#define AA_SFS_AF_MASK "' >> $@ ;\ - sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ - 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\ - $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ - -# Build a lower case string table of sock type names -# Transform lines from -# SOCK_STREAM = 1, -# to -# [1] = "stream", -quiet_cmd_make-sock = GEN $@ -cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ - sed $^ >>$@ -r -n \ - -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ - echo "};" >> $@ # Build a lower case string table of capability names # Transforms lines from @@ -94,7 +62,6 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ $(obj)/capability.o : $(obj)/capability_names.h -$(obj)/net.o : $(obj)/net_names.h $(obj)/resource.o : $(obj)/rlim_names.h $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ $(src)/Makefile @@ -102,8 +69,3 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \ $(src)/Makefile $(call cmd,make-rlim) -$(obj)/net_names.h : $(srctree)/include/linux/socket.h \ - $(srctree)/include/linux/net.h \ - $(src)/Makefile - $(call cmd,make-af) - $(call cmd,make-sock) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 518d592..d4fa04d 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -533,7 +533,7 @@ static ssize_t ns_revision_read(struct file *file, char __user *buf, long last_read; int avail; - mutex_lock(&rev->ns->lock); + mutex_lock_nested(&rev->ns->lock, rev->ns->level); last_read = rev->last_read; if (last_read == rev->ns->revision) { mutex_unlock(&rev->ns->lock); @@ -543,7 +543,7 @@ static ssize_t ns_revision_read(struct file *file, char __user *buf, last_read != READ_ONCE(rev->ns->revision))) return -ERESTARTSYS; - mutex_lock(&rev->ns->lock); + mutex_lock_nested(&rev->ns->lock, rev->ns->level); } avail = sprintf(buffer, "%ld\n", rev->ns->revision); @@ -577,7 +577,7 @@ static unsigned int ns_revision_poll(struct file *file, poll_table *pt) unsigned int mask = 0; if (rev) { - mutex_lock(&rev->ns->lock); + mutex_lock_nested(&rev->ns->lock, rev->ns->level); poll_wait(file, &rev->ns->wait, pt); if (rev->last_read < rev->ns->revision) mask |= POLLIN | POLLRDNORM; @@ -1643,7 +1643,7 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode) */ inode_unlock(dir); error = simple_pin_fs(&aafs_ops, &aafs_mnt, &aafs_count); - mutex_lock(&parent->lock); + mutex_lock_nested(&parent->lock, parent->level); inode_lock_nested(dir, I_MUTEX_PARENT); if (error) goto out; @@ -1692,7 +1692,7 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) inode_unlock(dir); inode_unlock(dentry->d_inode); - mutex_lock(&parent->lock); + mutex_lock_nested(&parent->lock, parent->level); ns = aa_get_ns(__aa_findn_ns(&parent->sub_ns, dentry->d_name.name, dentry->d_name.len)); if (!ns) { @@ -1747,7 +1747,7 @@ void __aafs_ns_rmdir(struct aa_ns *ns) __aafs_profile_rmdir(child); list_for_each_entry(sub, &ns->sub_ns, base.list) { - mutex_lock(&sub->lock); + mutex_lock_nested(&sub->lock, sub->level); __aafs_ns_rmdir(sub); mutex_unlock(&sub->lock); } @@ -1877,7 +1877,7 @@ int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name, /* subnamespaces */ list_for_each_entry(sub, &ns->sub_ns, base.list) { - mutex_lock(&sub->lock); + mutex_lock_nested(&sub->lock, sub->level); error = __aafs_ns_mkdir(sub, ns_subns_dir(ns), NULL, NULL); mutex_unlock(&sub->lock); if (error) @@ -1921,7 +1921,7 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns) /* is next namespace a child */ if (!list_empty(&ns->sub_ns)) { next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list); - mutex_lock(&next->lock); + mutex_lock_nested(&next->lock, next->level); return next; } @@ -1931,7 +1931,7 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns) mutex_unlock(&ns->lock); next = list_next_entry(ns, base.list); if (!list_entry_is_head(next, &parent->sub_ns, base.list)) { - mutex_lock(&next->lock); + mutex_lock_nested(&next->lock, next->level); return next; } ns = parent; @@ -2039,7 +2039,7 @@ static void *p_start(struct seq_file *f, loff_t *pos) f->private = root; /* find the first profile */ - mutex_lock(&root->lock); + mutex_lock_nested(&root->lock, root->level); profile = __first_profile(root, root); /* skip to position */ @@ -2202,7 +2202,6 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = { AA_SFS_DIR("policy", aa_sfs_entry_policy), AA_SFS_DIR("domain", aa_sfs_entry_domain), AA_SFS_DIR("file", aa_sfs_entry_file), - AA_SFS_DIR("network", aa_sfs_entry_network), AA_SFS_DIR("mount", aa_sfs_entry_mount), AA_SFS_DIR("namespaces", aa_sfs_entry_ns), AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), @@ -2452,7 +2451,7 @@ static int __init aa_create_aafs(void) aafs_mnt = kern_mount(&aafs_ops); if (IS_ERR(aafs_mnt)) panic("can't set apparmorfs up\n"); - aafs_mnt->mnt_sb->s_flags &= ~MS_NOUSER; + aafs_mnt->mnt_sb->s_flags &= ~SB_NOUSER; /* Populate fs tree. */ error = entry_create_dir(&aa_sfs_entry, NULL); @@ -2492,7 +2491,7 @@ static int __init aa_create_aafs(void) ns_subrevision(root_ns) = dent; /* policy tree referenced by magic policy symlink */ - mutex_lock(&root_ns->lock); + mutex_lock_nested(&root_ns->lock, root_ns->level); error = __aafs_ns_mkdir(root_ns, aafs_mnt->mnt_root, ".policy", aafs_mnt->mnt_root); mutex_unlock(&root_ns->lock); diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index dd754b7..04ba9d0 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -305,6 +305,7 @@ static int change_profile_perms(struct aa_profile *profile, * __attach_match_ - find an attachment match * @name - to match against (NOT NULL) * @head - profile list to walk (NOT NULL) + * @info - info message if there was an error (NOT NULL) * * Do a linear search on the profiles in the list. There is a matching * preference where an exact match is preferred over a name which uses @@ -316,28 +317,46 @@ static int change_profile_perms(struct aa_profile *profile, * Returns: profile or NULL if no match found */ static struct aa_profile *__attach_match(const char *name, - struct list_head *head) + struct list_head *head, + const char **info) { int len = 0; + bool conflict = false; struct aa_profile *profile, *candidate = NULL; list_for_each_entry_rcu(profile, head, base.list) { - if (profile->label.flags & FLAG_NULL) + if (profile->label.flags & FLAG_NULL && + &profile->label == ns_unconfined(profile->ns)) continue; - if (profile->xmatch && profile->xmatch_len > len) { - unsigned int state = aa_dfa_match(profile->xmatch, - DFA_START, name); - u32 perm = dfa_user_allow(profile->xmatch, state); - /* any accepting state means a valid match. */ - if (perm & MAY_EXEC) { - candidate = profile; - len = profile->xmatch_len; + + if (profile->xmatch) { + if (profile->xmatch_len == len) { + conflict = true; + continue; + } else if (profile->xmatch_len > len) { + unsigned int state; + u32 perm; + + state = aa_dfa_match(profile->xmatch, + DFA_START, name); + perm = dfa_user_allow(profile->xmatch, state); + /* any accepting state means a valid match. */ + if (perm & MAY_EXEC) { + candidate = profile; + len = profile->xmatch_len; + conflict = false; + } } } else if (!strcmp(profile->base.name, name)) /* exact non-re match, no more searching required */ return profile; } + if (conflict) { + *info = "conflicting profile attachments"; + return NULL; + } + return candidate; } @@ -346,16 +365,17 @@ static struct aa_profile *__attach_match(const char *name, * @ns: the current namespace (NOT NULL) * @list: list to search (NOT NULL) * @name: the executable name to match against (NOT NULL) + * @info: info message if there was an error * * Returns: label or NULL if no match found */ static struct aa_label *find_attach(struct aa_ns *ns, struct list_head *list, - const char *name) + const char *name, const char **info) { struct aa_profile *profile; rcu_read_lock(); - profile = aa_get_profile(__attach_match(name, list)); + profile = aa_get_profile(__attach_match(name, list, info)); rcu_read_unlock(); return profile ? &profile->label : NULL; @@ -448,11 +468,11 @@ static struct aa_label *x_to_label(struct aa_profile *profile, if (xindex & AA_X_CHILD) /* released by caller */ new = find_attach(ns, &profile->base.profiles, - name); + name, info); else /* released by caller */ new = find_attach(ns, &ns->base.profiles, - name); + name, info); *lookupname = name; break; } @@ -516,7 +536,7 @@ static struct aa_label *profile_transition(struct aa_profile *profile, if (profile_unconfined(profile)) { new = find_attach(profile->ns, &profile->ns->base.profiles, - name); + name, &info); if (new) { AA_DEBUG("unconfined attached to new label"); return new; @@ -541,9 +561,21 @@ static struct aa_label *profile_transition(struct aa_profile *profile, } } else if (COMPLAIN_MODE(profile)) { /* no exec permission - learning mode */ - struct aa_profile *new_profile = aa_new_null_profile(profile, - false, name, - GFP_ATOMIC); + struct aa_profile *new_profile = NULL; + char *n = kstrdup(name, GFP_ATOMIC); + + if (n) { + /* name is ptr into buffer */ + long pos = name - buffer; + /* break per cpu buffer hold */ + put_buffers(buffer); + new_profile = aa_new_null_profile(profile, false, n, + GFP_KERNEL); + get_buffers(buffer); + name = buffer + pos; + strcpy((char *)name, n); + kfree(n); + } if (!new_profile) { error = -ENOMEM; info = "could not create null profile"; diff --git a/security/apparmor/file.c b/security/apparmor/file.c index db80221..e79bf44 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -21,7 +21,6 @@ #include "include/context.h" #include "include/file.h" #include "include/match.h" -#include "include/net.h" #include "include/path.h" #include "include/policy.h" #include "include/label.h" @@ -227,18 +226,12 @@ static u32 map_old_perms(u32 old) struct aa_perms aa_compute_fperms(struct aa_dfa *dfa, unsigned int state, struct path_cond *cond) { - struct aa_perms perms; - /* FIXME: change over to new dfa format * currently file perms are encoded in the dfa, new format * splits the permissions from the dfa. This mapping can be * done at profile load */ - perms.deny = 0; - perms.kill = perms.stop = 0; - perms.complain = perms.cond = 0; - perms.hide = 0; - perms.prompt = 0; + struct aa_perms perms = { }; if (uid_eq(current_fsuid(), cond->uid)) { perms.allow = map_old_perms(dfa_user_allow(dfa, state)); @@ -567,32 +560,6 @@ static int __file_path_perm(const char *op, struct aa_label *label, return error; } -static int __file_sock_perm(const char *op, struct aa_label *label, - struct aa_label *flabel, struct file *file, - u32 request, u32 denied) -{ - struct socket *sock = (struct socket *) file->private_data; - int error; - - AA_BUG(!sock); - - /* revalidation due to label out of date. No revocation at this time */ - if (!denied && aa_label_is_subset(flabel, label)) - return 0; - - /* TODO: improve to skip profiles cached in flabel */ - error = aa_sock_file_perm(label, op, request, sock); - if (denied) { - /* TODO: improve to skip profiles checked above */ - /* check every profile in file label to is cached */ - last_error(error, aa_sock_file_perm(flabel, op, request, sock)); - } - if (!error) - update_file_ctx(file_ctx(file), label, request); - - return error; -} - /** * aa_file_perm - do permission revalidation check & audit for @file * @op: operation being checked @@ -637,9 +604,6 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file, error = __file_path_perm(op, label, flabel, file, request, denied); - else if (S_ISSOCK(file_inode(file)->i_mode)) - error = __file_sock_perm(op, label, flabel, file, request, - denied); done: rcu_read_unlock(); diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index ff4316e..4ac0951 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -123,20 +123,10 @@ struct apparmor_audit_data { struct aa_label *peer; union { struct { - kuid_t ouid; const char *target; + kuid_t ouid; } fs; - struct { - int type, protocol; - struct sock *peer_sk; - void *addr; - int addrlen; - } net; int signal; - struct { - int rlim; - unsigned long max; - } rlim; }; }; struct { @@ -145,6 +135,10 @@ struct apparmor_audit_data { long pos; } iface; struct { + int rlim; + unsigned long max; + } rlim; + struct { const char *src_name; const char *type; const char *trans; diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 436b3a7..6505e1a 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -19,17 +19,6 @@ #include "match.h" -/* Provide our own test for whether a write lock is held for asserts - * this is because on none SMP systems write_can_lock will always - * resolve to true, which is what you want for code making decisions - * based on it, but wrong for asserts checking that the lock is held - */ -#ifdef CONFIG_SMP -#define write_is_locked(X) !write_can_lock(X) -#else -#define write_is_locked(X) (1) -#endif /* CONFIG_SMP */ - /* * DEBUG remains global (no per profile flag) since it is mostly used in sysctl * which is not related to profile accesses. @@ -97,7 +86,7 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, static inline bool path_mediated_fs(struct dentry *dentry) { - return !(dentry->d_sb->s_flags & MS_NOUSER); + return !(dentry->d_sb->s_flags & SB_NOUSER); } diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h deleted file mode 100644 index 140c8efc..0000000 --- a/security/apparmor/include/net.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * AppArmor security module - * - * This file contains AppArmor network mediation definitions. - * - * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - */ - -#ifndef __AA_NET_H -#define __AA_NET_H - -#include <net/sock.h> -#include <linux/path.h> - -#include "apparmorfs.h" -#include "label.h" -#include "perms.h" -#include "policy.h" - -#define AA_MAY_SEND AA_MAY_WRITE -#define AA_MAY_RECEIVE AA_MAY_READ - -#define AA_MAY_SHUTDOWN AA_MAY_DELETE - -#define AA_MAY_CONNECT AA_MAY_OPEN -#define AA_MAY_ACCEPT 0x00100000 - -#define AA_MAY_BIND 0x00200000 -#define AA_MAY_LISTEN 0x00400000 - -#define AA_MAY_SETOPT 0x01000000 -#define AA_MAY_GETOPT 0x02000000 - -#define NET_PERMS_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \ - AA_MAY_SHUTDOWN | AA_MAY_BIND | AA_MAY_LISTEN | \ - AA_MAY_CONNECT | AA_MAY_ACCEPT | AA_MAY_SETATTR | \ - AA_MAY_GETATTR | AA_MAY_SETOPT | AA_MAY_GETOPT) - -#define NET_FS_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \ - AA_MAY_SHUTDOWN | AA_MAY_CONNECT | AA_MAY_RENAME |\ - AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_CHMOD | \ - AA_MAY_CHOWN | AA_MAY_CHGRP | AA_MAY_LOCK | \ - AA_MAY_MPROT) - -#define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \ - AA_MAY_ACCEPT) -struct aa_sk_ctx { - struct aa_label *label; - struct aa_label *peer; - struct path path; -}; - -#define SK_CTX(X) ((X)->sk_security) -#define SOCK_ctx(X) SOCK_INODE(X)->i_security -#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \ - struct lsm_network_audit NAME ## _net = { .sk = (SK), \ - .family = (F)}; \ - DEFINE_AUDIT_DATA(NAME, \ - ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \ - LSM_AUDIT_DATA_NONE, \ - OP); \ - NAME.u.net = &(NAME ## _net); \ - aad(&NAME)->net.type = (T); \ - aad(&NAME)->net.protocol = (P) - -#define DEFINE_AUDIT_SK(NAME, OP, SK) \ - DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ - (SK)->sk_protocol) - -/* struct aa_net - network confinement data - * @allow: basic network families permissions - * @audit: which network permissions to force audit - * @quiet: which network permissions to quiet rejects - */ -struct aa_net { - u16 allow[AF_MAX]; - u16 audit[AF_MAX]; - u16 quiet[AF_MAX]; -}; - - -extern struct aa_sfs_entry aa_sfs_entry_network[]; - -void audit_net_cb(struct audit_buffer *ab, void *va); -int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, - u32 request, u16 family, int type); -int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, - int type, int protocol); -static inline int aa_profile_af_sk_perm(struct aa_profile *profile, - struct common_audit_data *sa, - u32 request, - struct sock *sk) -{ - return aa_profile_af_perm(profile, sa, request, sk->sk_family, - sk->sk_type); -} -int aa_sk_perm(const char *op, u32 request, struct sock *sk); - -int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, - struct socket *sock); - - -static inline void aa_free_net_rules(struct aa_net *new) -{ - /* NOP */ -} - -#endif /* __AA_NET_H */ diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index af04d5a..2b27bb7 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -135,10 +135,9 @@ extern struct aa_perms allperms; void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask); -void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, - u32 mask); +void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask); void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, - u32 chrsmask, const char * const *names, u32 namesmask); + u32 chrsmask, const char **names, u32 namesmask); void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms); void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 4364088..17fe41a 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -30,7 +30,6 @@ #include "file.h" #include "lib.h" #include "label.h" -#include "net.h" #include "perms.h" #include "resource.h" @@ -112,7 +111,6 @@ struct aa_data { * @policy: general match rules governing policy * @file: The set of rules governing basic file access and domain transitions * @caps: capabilities for the profile - * @net: network controls for the profile * @rlimits: rlimits for the profile * * @dents: dentries for the profiles file entries in apparmorfs @@ -150,7 +148,6 @@ struct aa_profile { struct aa_policydb policy; struct aa_file_rules file; struct aa_caps caps; - struct aa_net net; struct aa_rlimit rlimits; struct aa_loaddata *rawdata; @@ -223,16 +220,6 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile, return 0; } -static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile, - u16 AF) { - unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET); - u16 be_af = cpu_to_be16(AF); - - if (!state) - return 0; - return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); -} - /** * aa_get_profile - increment refcount on profile @p * @p: profile (MAYBE NULL) diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index 66fb9ed..7ca0032 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -128,7 +128,7 @@ static inline int map_signal_num(int sig) return SIGUNKNOWN; else if (sig >= SIGRTMIN) return sig - SIGRTMIN + 128; /* rt sigs mapped to 128 */ - else if (sig <= MAXMAPPED_SIG) + else if (sig < MAXMAPPED_SIG) return sig_map[sig]; return SIGUNKNOWN; } @@ -163,7 +163,7 @@ static void audit_signal_cb(struct audit_buffer *ab, void *va) audit_signal_mask(ab, aad(sa)->denied); } } - if (aad(sa)->signal <= MAXMAPPED_SIG) + if (aad(sa)->signal < MAXMAPPED_SIG) audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]); else audit_log_format(ab, " signal=rtmin+%d", diff --git a/security/apparmor/label.c b/security/apparmor/label.c index c5b99b9..324fe5c 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -80,7 +80,7 @@ void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new) AA_BUG(!orig); AA_BUG(!new); - AA_BUG(!write_is_locked(&labels_set(orig)->lock)); + lockdep_assert_held_exclusive(&labels_set(orig)->lock); tmp = rcu_dereference_protected(orig->proxy->label, &labels_ns(orig)->lock); @@ -571,7 +571,7 @@ static bool __label_remove(struct aa_label *label, struct aa_label *new) AA_BUG(!ls); AA_BUG(!label); - AA_BUG(!write_is_locked(&ls->lock)); + lockdep_assert_held_exclusive(&ls->lock); if (new) __aa_proxy_redirect(label, new); @@ -608,7 +608,7 @@ static bool __label_replace(struct aa_label *old, struct aa_label *new) AA_BUG(!ls); AA_BUG(!old); AA_BUG(!new); - AA_BUG(!write_is_locked(&ls->lock)); + lockdep_assert_held_exclusive(&ls->lock); AA_BUG(new->flags & FLAG_IN_TREE); if (!label_is_stale(old)) @@ -645,7 +645,7 @@ static struct aa_label *__label_insert(struct aa_labelset *ls, AA_BUG(!ls); AA_BUG(!label); AA_BUG(labels_set(label) != ls); - AA_BUG(!write_is_locked(&ls->lock)); + lockdep_assert_held_exclusive(&ls->lock); AA_BUG(label->flags & FLAG_IN_TREE); /* Figure out where to put new node */ @@ -2115,7 +2115,7 @@ void __aa_labelset_update_subtree(struct aa_ns *ns) __labelset_update(ns); list_for_each_entry(child, &ns->sub_ns, base.list) { - mutex_lock(&child->lock); + mutex_lock_nested(&child->lock, child->level); __aa_labelset_update_subtree(child); mutex_unlock(&child->lock); } diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 8818621..4d5e98e 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -211,8 +211,7 @@ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask) *str = '\0'; } -void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, - u32 mask) +void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) { const char *fmt = "%s"; unsigned int i, perm = 1; @@ -230,7 +229,7 @@ void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, } void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, - u32 chrsmask, const char * const *names, u32 namesmask) + u32 chrsmask, const char **names, u32 namesmask) { char str[33]; @@ -318,14 +317,11 @@ static u32 map_other(u32 x) void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, struct aa_perms *perms) { - perms->deny = 0; - perms->kill = perms->stop = 0; - perms->complain = perms->cond = 0; - perms->hide = 0; - perms->prompt = 0; - perms->allow = dfa_user_allow(dfa, state); - perms->audit = dfa_user_audit(dfa, state); - perms->quiet = dfa_user_quiet(dfa, state); + *perms = (struct aa_perms) { + .allow = dfa_user_allow(dfa, state), + .audit = dfa_user_audit(dfa, state), + .quiet = dfa_user_quiet(dfa, state), + }; /* for v5 perm mapping in the policydb, the other set is used * to extend the general perm set @@ -427,7 +423,6 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, void (*cb)(struct audit_buffer *, void *)) { int type, error; - bool stop = false; u32 denied = request & (~perms->allow | perms->deny); if (likely(!denied)) { @@ -448,8 +443,6 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, else type = AUDIT_APPARMOR_DENIED; - if (denied & perms->stop) - stop = true; if (denied == (denied & perms->hide)) error = -ENOENT; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 72b915d..9a65eea 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -33,7 +33,6 @@ #include "include/context.h" #include "include/file.h" #include "include/ipc.h" -#include "include/net.h" #include "include/path.h" #include "include/label.h" #include "include/policy.h" @@ -737,368 +736,6 @@ static int apparmor_task_kill(struct task_struct *target, struct siginfo *info, return error; } -/** - * apparmor_sk_alloc_security - allocate and attach the sk_security field - */ -static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags) -{ - struct aa_sk_ctx *ctx; - - ctx = kzalloc(sizeof(*ctx), flags); - if (!ctx) - return -ENOMEM; - - SK_CTX(sk) = ctx; - - return 0; -} - -/** - * apparmor_sk_free_security - free the sk_security field - */ -static void apparmor_sk_free_security(struct sock *sk) -{ - struct aa_sk_ctx *ctx = SK_CTX(sk); - - SK_CTX(sk) = NULL; - aa_put_label(ctx->label); - aa_put_label(ctx->peer); - path_put(&ctx->path); - kfree(ctx); -} - -/** - * apparmor_clone_security - clone the sk_security field - */ -static void apparmor_sk_clone_security(const struct sock *sk, - struct sock *newsk) -{ - struct aa_sk_ctx *ctx = SK_CTX(sk); - struct aa_sk_ctx *new = SK_CTX(newsk); - - new->label = aa_get_label(ctx->label); - new->peer = aa_get_label(ctx->peer); - new->path = ctx->path; - path_get(&new->path); -} - -static int aa_sock_create_perm(struct aa_label *label, int family, int type, - int protocol) -{ - AA_BUG(!label); - AA_BUG(in_interrupt()); - - return aa_af_perm(label, OP_CREATE, AA_MAY_CREATE, family, type, - protocol); -} - - -/** - * apparmor_socket_create - check perms before creating a new socket - */ -static int apparmor_socket_create(int family, int type, int protocol, int kern) -{ - struct aa_label *label; - int error = 0; - - label = begin_current_label_crit_section(); - if (!(kern || unconfined(label))) - error = aa_sock_create_perm(label, family, type, protocol); - end_current_label_crit_section(label); - - return error; -} - -/** - * apparmor_socket_post_create - setup the per-socket security struct - * - * Note: - * - kernel sockets currently labeled unconfined but we may want to - * move to a special kernel label - * - socket may not have sk here if created with sock_create_lite or - * sock_alloc. These should be accept cases which will be handled in - * sock_graft. - */ -static int apparmor_socket_post_create(struct socket *sock, int family, - int type, int protocol, int kern) -{ - struct aa_label *label; - - if (kern) { - struct aa_ns *ns = aa_get_current_ns(); - - label = aa_get_label(ns_unconfined(ns)); - aa_put_ns(ns); - } else - label = aa_get_current_label(); - - if (sock->sk) { - struct aa_sk_ctx *ctx = SK_CTX(sock->sk); - - aa_put_label(ctx->label); - ctx->label = aa_get_label(label); - } - aa_put_label(label); - - return 0; -} - -/** - * apparmor_socket_bind - check perms before bind addr to socket - */ -static int apparmor_socket_bind(struct socket *sock, - struct sockaddr *address, int addrlen) -{ - AA_BUG(!sock); - AA_BUG(!sock->sk); - AA_BUG(!address); - AA_BUG(in_interrupt()); - - return aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk); -} - -/** - * apparmor_socket_connect - check perms before connecting @sock to @address - */ -static int apparmor_socket_connect(struct socket *sock, - struct sockaddr *address, int addrlen) -{ - AA_BUG(!sock); - AA_BUG(!sock->sk); - AA_BUG(!address); - AA_BUG(in_interrupt()); - - return aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk); -} - -/** - * apparmor_socket_list - check perms before allowing listen - */ -static int apparmor_socket_listen(struct socket *sock, int backlog) -{ - AA_BUG(!sock); - AA_BUG(!sock->sk); - AA_BUG(in_interrupt()); - - return aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk); -} - -/** - * apparmor_socket_accept - check perms before accepting a new connection. - * - * Note: while @newsock is created and has some information, the accept - * has not been done. - */ -static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) -{ - AA_BUG(!sock); - AA_BUG(!sock->sk); - AA_BUG(!newsock); - AA_BUG(in_interrupt()); - - return aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk); -} - -static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock, - struct msghdr *msg, int size) -{ - AA_BUG(!sock); - AA_BUG(!sock->sk); - AA_BUG(!msg); - AA_BUG(in_interrupt()); - - return aa_sk_perm(op, request, sock->sk); -} - -/** - * apparmor_socket_sendmsg - check perms before sending msg to another socket - */ -static int apparmor_socket_sendmsg(struct socket *sock, - struct msghdr *msg, int size) -{ - return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size); -} - -/** - * apparmor_socket_recvmsg - check perms before receiving a message - */ -static int apparmor_socket_recvmsg(struct socket *sock, - struct msghdr *msg, int size, int flags) -{ - return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size); -} - -/* revaliation, get/set attr, shutdown */ -static int aa_sock_perm(const char *op, u32 request, struct socket *sock) -{ - AA_BUG(!sock); - AA_BUG(!sock->sk); - AA_BUG(in_interrupt()); - - return aa_sk_perm(op, request, sock->sk); -} - -/** - * apparmor_socket_getsockname - check perms before getting the local address - */ -static int apparmor_socket_getsockname(struct socket *sock) -{ - return aa_sock_perm(OP_GETSOCKNAME, AA_MAY_GETATTR, sock); -} - -/** - * apparmor_socket_getpeername - check perms before getting remote address - */ -static int apparmor_socket_getpeername(struct socket *sock) -{ - return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock); -} - -/* revaliation, get/set attr, opt */ -static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, - int level, int optname) -{ - AA_BUG(!sock); - AA_BUG(!sock->sk); - AA_BUG(in_interrupt()); - - return aa_sk_perm(op, request, sock->sk); -} - -/** - * apparmor_getsockopt - check perms before getting socket options - */ -static int apparmor_socket_getsockopt(struct socket *sock, int level, - int optname) -{ - return aa_sock_opt_perm(OP_GETSOCKOPT, AA_MAY_GETOPT, sock, - level, optname); -} - -/** - * apparmor_setsockopt - check perms before setting socket options - */ -static int apparmor_socket_setsockopt(struct socket *sock, int level, - int optname) -{ - return aa_sock_opt_perm(OP_SETSOCKOPT, AA_MAY_SETOPT, sock, - level, optname); -} - -/** - * apparmor_socket_shutdown - check perms before shutting down @sock conn - */ -static int apparmor_socket_shutdown(struct socket *sock, int how) -{ - return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock); -} - -/** - * apparmor_socket_sock_recv_skb - check perms before associating skb to sk - * - * Note: can not sleep may be called with locks held - * - * dont want protocol specific in __skb_recv_datagram() - * to deny an incoming connection socket_sock_rcv_skb() - */ -static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - return 0; -} - - -static struct aa_label *sk_peer_label(struct sock *sk) -{ - struct aa_sk_ctx *ctx = SK_CTX(sk); - - if (ctx->peer) - return ctx->peer; - - return ERR_PTR(-ENOPROTOOPT); -} - -/** - * apparmor_socket_getpeersec_stream - get security context of peer - * - * Note: for tcp only valid if using ipsec or cipso on lan - */ -static int apparmor_socket_getpeersec_stream(struct socket *sock, - char __user *optval, - int __user *optlen, - unsigned int len) -{ - char *name; - int slen, error = 0; - struct aa_label *label; - struct aa_label *peer; - - label = begin_current_label_crit_section(); - peer = sk_peer_label(sock->sk); - if (IS_ERR(peer)) { - error = PTR_ERR(peer); - goto done; - } - slen = aa_label_asxprint(&name, labels_ns(label), peer, - FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | - FLAG_HIDDEN_UNCONFINED, GFP_KERNEL); - /* don't include terminating \0 in slen, it breaks some apps */ - if (slen < 0) { - error = -ENOMEM; - } else { - if (slen > len) { - error = -ERANGE; - } else if (copy_to_user(optval, name, slen)) { - error = -EFAULT; - goto out; - } - if (put_user(slen, optlen)) - error = -EFAULT; -out: - kfree(name); - - } - -done: - end_current_label_crit_section(label); - - return error; -} - -/** - * apparmor_socket_getpeersec_dgram - get security label of packet - * @sock: the peer socket - * @skb: packet data - * @secid: pointer to where to put the secid of the packet - * - * Sets the netlabel socket state on sk from parent - */ -static int apparmor_socket_getpeersec_dgram(struct socket *sock, - struct sk_buff *skb, u32 *secid) - -{ - /* TODO: requires secid support */ - return -ENOPROTOOPT; -} - -/** - * apparmor_sock_graft - Initialize newly created socket - * @sk: child sock - * @parent: parent socket - * - * Note: could set off of SOCK_CTX(parent) but need to track inode and we can - * just set sk security information off of current creating process label - * Labeling of sk for accept case - probably should be sock based - * instead of task, because of the case where an implicitly labeled - * socket is shared by different tasks. - */ -static void apparmor_sock_graft(struct sock *sk, struct socket *parent) -{ - struct aa_sk_ctx *ctx = SK_CTX(sk); - - if (!ctx->label) - ctx->label = aa_get_current_label(); -} - static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), @@ -1133,30 +770,6 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), - LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security), - LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), - LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), - - LSM_HOOK_INIT(socket_create, apparmor_socket_create), - LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create), - LSM_HOOK_INIT(socket_bind, apparmor_socket_bind), - LSM_HOOK_INIT(socket_connect, apparmor_socket_connect), - LSM_HOOK_INIT(socket_listen, apparmor_socket_listen), - LSM_HOOK_INIT(socket_accept, apparmor_socket_accept), - LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg), - LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg), - LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname), - LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername), - LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt), - LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt), - LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown), - LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb), - LSM_HOOK_INIT(socket_getpeersec_stream, - apparmor_socket_getpeersec_stream), - LSM_HOOK_INIT(socket_getpeersec_dgram, - apparmor_socket_getpeersec_dgram), - LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), - LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), LSM_HOOK_INIT(cred_free, apparmor_cred_free), LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare), @@ -1200,11 +813,11 @@ static const struct kernel_param_ops param_ops_aalockpolicy = { .get = param_get_aalockpolicy }; -static int param_set_audit(const char *val, struct kernel_param *kp); -static int param_get_audit(char *buffer, struct kernel_param *kp); +static int param_set_audit(const char *val, const struct kernel_param *kp); +static int param_get_audit(char *buffer, const struct kernel_param *kp); -static int param_set_mode(const char *val, struct kernel_param *kp); -static int param_get_mode(char *buffer, struct kernel_param *kp); +static int param_set_mode(const char *val, const struct kernel_param *kp); +static int param_get_mode(char *buffer, const struct kernel_param *kp); /* Flag values, also controllable via /sys/module/apparmor/parameters * We define special types as we want to do additional mediation. @@ -1233,7 +846,7 @@ module_param_call(audit, param_set_audit, param_get_audit, /* Determines if audit header is included in audited messages. This * provides more context if the audit daemon is not running */ -bool aa_g_audit_header = 1; +bool aa_g_audit_header = true; module_param_named(audit_header, aa_g_audit_header, aabool, S_IRUSR | S_IWUSR); @@ -1258,7 +871,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); * DEPRECATED: read only as strict checking of load is always done now * that none root users (user namespaces) can load policy. */ -bool aa_g_paranoid_load = 1; +bool aa_g_paranoid_load = true; module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); /* Boot time disable flag */ @@ -1338,7 +951,7 @@ static int param_get_aauint(char *buffer, const struct kernel_param *kp) return param_get_uint(buffer, kp); } -static int param_get_audit(char *buffer, struct kernel_param *kp) +static int param_get_audit(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; @@ -1347,7 +960,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp) return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); } -static int param_set_audit(const char *val, struct kernel_param *kp) +static int param_set_audit(const char *val, const struct kernel_param *kp) { int i; @@ -1368,7 +981,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp) return -EINVAL; } -static int param_get_mode(char *buffer, struct kernel_param *kp) +static int param_get_mode(char *buffer, const struct kernel_param *kp) { if (!apparmor_enabled) return -EINVAL; @@ -1378,7 +991,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); } -static int param_set_mode(const char *val, struct kernel_param *kp) +static int param_set_mode(const char *val, const struct kernel_param *kp) { int i; @@ -1506,7 +1119,7 @@ static int __init apparmor_init(void) if (!apparmor_enabled || !security_module_enable("apparmor")) { aa_info_message("AppArmor disabled by boot time parameter"); - apparmor_enabled = 0; + apparmor_enabled = false; return 0; } @@ -1562,7 +1175,7 @@ alloc_out: aa_destroy_aafs(); aa_teardown_dfa_engine(); - apparmor_enabled = 0; + apparmor_enabled = false; return error; } diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 82a64b5..ed9b4d0 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -216,13 +216,12 @@ static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state, static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa, unsigned int state) { - struct aa_perms perms; - - perms.kill = 0; - perms.allow = dfa_user_allow(dfa, state); - perms.audit = dfa_user_audit(dfa, state); - perms.quiet = dfa_user_quiet(dfa, state); - perms.xindex = dfa_user_xindex(dfa, state); + struct aa_perms perms = { + .allow = dfa_user_allow(dfa, state), + .audit = dfa_user_audit(dfa, state), + .quiet = dfa_user_quiet(dfa, state), + .xindex = dfa_user_xindex(dfa, state), + }; return perms; } diff --git a/security/apparmor/net.c b/security/apparmor/net.c deleted file mode 100644 index 33d5443..0000000 --- a/security/apparmor/net.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * AppArmor security module - * - * This file contains AppArmor network mediation - * - * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2017 Canonical Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - */ - -#include "include/apparmor.h" -#include "include/audit.h" -#include "include/context.h" -#include "include/label.h" -#include "include/net.h" -#include "include/policy.h" - -#include "net_names.h" - - -struct aa_sfs_entry aa_sfs_entry_network[] = { - AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), - { } -}; - -static const char * const net_mask_names[] = { - "unknown", - "send", - "receive", - "unknown", - - "create", - "shutdown", - "connect", - "unknown", - - "setattr", - "getattr", - "setcred", - "getcred", - - "chmod", - "chown", - "chgrp", - "lock", - - "mmap", - "mprot", - "unknown", - "unknown", - - "accept", - "bind", - "listen", - "unknown", - - "setopt", - "getopt", - "unknown", - "unknown", - - "unknown", - "unknown", - "unknown", - "unknown", -}; - - -/* audit callback for net specific fields */ -void audit_net_cb(struct audit_buffer *ab, void *va) -{ - struct common_audit_data *sa = va; - - audit_log_format(ab, " family="); - if (address_family_names[sa->u.net->family]) - audit_log_string(ab, address_family_names[sa->u.net->family]); - else - audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family); - audit_log_format(ab, " sock_type="); - if (sock_type_names[aad(sa)->net.type]) - audit_log_string(ab, sock_type_names[aad(sa)->net.type]); - else - audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type); - audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); - - if (aad(sa)->request & NET_PERMS_MASK) { - audit_log_format(ab, " requested_mask="); - aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0, - net_mask_names, NET_PERMS_MASK); - - if (aad(sa)->denied & NET_PERMS_MASK) { - audit_log_format(ab, " denied_mask="); - aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0, - net_mask_names, NET_PERMS_MASK); - } - } - if (aad(sa)->peer) { - audit_log_format(ab, " peer="); - aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, - FLAGS_NONE, GFP_ATOMIC); - } -} - - -/* Generic af perm */ -int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, - u32 request, u16 family, int type) -{ - struct aa_perms perms = { }; - - AA_BUG(family >= AF_MAX); - AA_BUG(type < 0 || type >= SOCK_MAX); - - if (profile_unconfined(profile)) - return 0; - - perms.allow = (profile->net.allow[family] & (1 << type)) ? - ALL_PERMS_MASK : 0; - perms.audit = (profile->net.audit[family] & (1 << type)) ? - ALL_PERMS_MASK : 0; - perms.quiet = (profile->net.quiet[family] & (1 << type)) ? - ALL_PERMS_MASK : 0; - aa_apply_modes_to_perms(profile, &perms); - - return aa_check_perms(profile, &perms, request, sa, audit_net_cb); -} - -int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, - int type, int protocol) -{ - struct aa_profile *profile; - DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol); - - return fn_for_each_confined(label, profile, - aa_profile_af_perm(profile, &sa, request, family, - type)); -} - -static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, - struct sock *sk) -{ - struct aa_profile *profile; - DEFINE_AUDIT_SK(sa, op, sk); - - AA_BUG(!label); - AA_BUG(!sk); - - if (unconfined(label)) - return 0; - - return fn_for_each_confined(label, profile, - aa_profile_af_sk_perm(profile, &sa, request, sk)); -} - -int aa_sk_perm(const char *op, u32 request, struct sock *sk) -{ - struct aa_label *label; - int error; - - AA_BUG(!sk); - AA_BUG(in_interrupt()); - - /* TODO: switch to begin_current_label ???? */ - label = begin_current_label_crit_section(); - error = aa_label_sk_perm(label, op, request, sk); - end_current_label_crit_section(label); - - return error; -} - - -int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, - struct socket *sock) -{ - AA_BUG(!label); - AA_BUG(!sock); - AA_BUG(!sock->sk); - - return aa_label_sk_perm(label, op, request, sock->sk); -} diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4243b0c..b0b5884 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -502,7 +502,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, { struct aa_profile *p, *profile; const char *bname; - char *name; + char *name = NULL; AA_BUG(!parent); @@ -545,7 +545,7 @@ name: profile->file.dfa = aa_get_dfa(nulldfa); profile->policy.dfa = aa_get_dfa(nulldfa); - mutex_lock(&profile->ns->lock); + mutex_lock_nested(&profile->ns->lock, profile->ns->level); p = __find_child(&parent->base.profiles, bname); if (p) { aa_free_profile(profile); @@ -562,6 +562,7 @@ out: return profile; fail: + kfree(name); aa_free_profile(profile); return NULL; } @@ -905,7 +906,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, } else ns = aa_get_ns(policy_ns ? policy_ns : labels_ns(label)); - mutex_lock(&ns->lock); + mutex_lock_nested(&ns->lock, ns->level); /* check for duplicate rawdata blobs: space and file dedup */ list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { if (aa_rawdata_eq(rawdata_ent, udata)) { @@ -1116,13 +1117,13 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj, if (!name) { /* remove namespace - can only happen if fqname[0] == ':' */ - mutex_lock(&ns->parent->lock); + mutex_lock_nested(&ns->parent->lock, ns->level); __aa_remove_ns(ns); __aa_bump_ns_revision(ns); mutex_unlock(&ns->parent->lock); } else { /* remove profile */ - mutex_lock(&ns->lock); + mutex_lock_nested(&ns->lock, ns->level); profile = aa_get_profile(__lookup_profile(&ns->base, name)); if (!profile) { error = -ENOENT; diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 62a3589..b1e629c 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -256,7 +256,8 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, ns = alloc_ns(parent->base.hname, name); if (!ns) return NULL; - mutex_lock(&ns->lock); + ns->level = parent->level + 1; + mutex_lock_nested(&ns->lock, ns->level); error = __aafs_ns_mkdir(ns, ns_subns_dir(parent), name, dir); if (error) { AA_ERROR("Failed to create interface for ns %s\n", @@ -266,7 +267,6 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, return ERR_PTR(error); } ns->parent = aa_get_ns(parent); - ns->level = parent->level + 1; list_add_rcu(&ns->base.list, &parent->sub_ns); /* add list ref */ aa_get_ns(ns); @@ -313,7 +313,7 @@ struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name) { struct aa_ns *ns; - mutex_lock(&parent->lock); + mutex_lock_nested(&parent->lock, parent->level); /* try and find the specified ns and if it doesn't exist create it */ /* released by caller */ ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); @@ -336,7 +336,7 @@ static void destroy_ns(struct aa_ns *ns) if (!ns) return; - mutex_lock(&ns->lock); + mutex_lock_nested(&ns->lock, ns->level); /* release all profiles in this namespace */ __aa_profile_list_release(&ns->base.profiles); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 5a2aec3..59a1a25 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -157,7 +157,7 @@ static void do_loaddata_free(struct work_struct *work) struct aa_ns *ns = aa_get_ns(d->ns); if (ns) { - mutex_lock(&ns->lock); + mutex_lock_nested(&ns->lock, ns->level); __aa_fs_remove_rawdata(d); mutex_unlock(&ns->lock); aa_put_ns(ns); @@ -275,19 +275,6 @@ fail: return 0; } -static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) -{ - if (unpack_nameX(e, AA_U16, name)) { - if (!inbounds(e, sizeof(u16))) - return 0; - if (data) - *data = le16_to_cpu(get_unaligned((__le16 *) e->pos)); - e->pos += sizeof(u16); - return 1; - } - return 0; -} - static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) { if (unpack_nameX(e, AA_U32, name)) { @@ -597,7 +584,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) struct aa_profile *profile = NULL; const char *tmpname, *tmpns = NULL, *name = NULL; const char *info = "failed to unpack profile"; - size_t size = 0, ns_len; + size_t ns_len; struct rhashtable_params params = { 0 }; char *key = NULL; struct aa_data *data; @@ -730,38 +717,6 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) goto fail; } - size = unpack_array(e, "net_allowed_af"); - if (size) { - - for (i = 0; i < size; i++) { - /* discard extraneous rules that this kernel will - * never request - */ - if (i >= AF_MAX) { - u16 tmp; - - if (!unpack_u16(e, &tmp, NULL) || - !unpack_u16(e, &tmp, NULL) || - !unpack_u16(e, &tmp, NULL)) - goto fail; - continue; - } - if (!unpack_u16(e, &profile->net.allow[i], NULL)) - goto fail; - if (!unpack_u16(e, &profile->net.audit[i], NULL)) - goto fail; - if (!unpack_u16(e, &profile->net.quiet[i], NULL)) - goto fail; - } - if (!unpack_nameX(e, AA_ARRAYEND, NULL)) - goto fail; - } - if (VERSION_LT(e->version, v7)) { - /* pre v7 policy always allowed these */ - profile->net.allow[AF_UNIX] = 0xffff; - profile->net.allow[AF_NETLINK] = 0xffff; - } - if (unpack_nameX(e, AA_STRUCT, "policydb")) { /* generic policy dfa - optional and may be NULL */ info = "failed to unpack policydb"; diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index d8bc842..cf4d234 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -47,7 +47,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) /** * audit_resource - audit setting resource limit * @profile: profile being enforced (NOT NULL) - * @resoure: rlimit being auditing + * @resource: rlimit being auditing * @value: value being set * @error: error value * @@ -128,7 +128,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, error = fn_for_each(label, profile, audit_resource(profile, resource, new_rlim->rlim_max, peer, - "cap_sys_resoure", -EACCES)); + "cap_sys_resource", -EACCES)); else error = fn_for_each_confined(label, profile, profile_setrlimit(profile, resource, new_rlim)); |