From c02b3f26e3b0a7982656cf4246ccf1485e4b5d78 Mon Sep 17 00:00:00 2001 From: Daniel Llewellyn Date: Mon, 23 Sep 2019 00:08:34 +0100 Subject: [PATCH 1/2] Add apparmor v1 patch; Config enable apparmor Snapd strict confinement requires apparmor with a legacy patch applied to the kernel. * Add apparmor v1 (legacy) patch for snapd support * Update config-wsl to enable apparmor by default Signed-off-by: Daniel Llewellyn --- Microsoft/config-wsl | 25 +- security/apparmor/Makefile | 3 +- security/apparmor/af_unix.c | 652 +++++++++++++++++++++++++++ security/apparmor/apparmorfs.c | 7 + security/apparmor/file.c | 4 +- security/apparmor/include/af_unix.h | 114 +++++ security/apparmor/include/apparmor.h | 2 +- security/apparmor/include/net.h | 15 + security/apparmor/include/path.h | 1 + security/apparmor/include/policy.h | 12 +- security/apparmor/lsm.c | 120 ++++- security/apparmor/net.c | 84 +++- security/apparmor/policy.c | 1 + security/apparmor/policy_unpack.c | 54 ++- 14 files changed, 1069 insertions(+), 25 deletions(-) create mode 100644 security/apparmor/af_unix.c create mode 100644 security/apparmor/include/af_unix.h diff --git a/Microsoft/config-wsl b/Microsoft/config-wsl index 1c71f53fb96aa..9c96f3c3b4bed 100644 --- a/Microsoft/config-wsl +++ b/Microsoft/config-wsl @@ -42,8 +42,11 @@ CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE_SYSCTL=y CONFIG_CROSS_MEMORY_ATTACH=y # CONFIG_USELIB is not set -# CONFIG_AUDIT is not set +CONFIG_AUDIT=y CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y # # IRQ subsystem @@ -968,6 +971,7 @@ CONFIG_NETFILTER_XT_SET=y # # Xtables targets # +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set CONFIG_NETFILTER_XT_TARGET_CHECKSUM=y # CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set # CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set @@ -2465,23 +2469,30 @@ CONFIG_KEYS_COMPAT=y # CONFIG_KEY_DH_OPERATIONS is not set CONFIG_SECURITY_DMESG_RESTRICT=y CONFIG_SECURITY=y -# CONFIG_SECURITYFS is not set -# CONFIG_SECURITY_NETWORK is not set +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y CONFIG_PAGE_TABLE_ISOLATION=y -# CONFIG_SECURITY_PATH is not set +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y # CONFIG_HARDENED_USERCOPY is not set # CONFIG_FORTIFY_SOURCE is not set CONFIG_STATIC_USERMODEHELPER=y CONFIG_STATIC_USERMODEHELPER_PATH="/sbin/usermode-helper" +# CONFIG_SECURITY_SELINUX is not set # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set -# CONFIG_SECURITY_APPARMOR is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set # CONFIG_SECURITY_LOADPIN is not set # CONFIG_SECURITY_YAMA is not set # CONFIG_INTEGRITY is not set -CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="apparmor" CONFIG_XOR_BLOCKS=y CONFIG_CRYPTO=y diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index ff23fcfefe196..fad407f6f62c8 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o apparmor-y := apparmorfs.o audit.o capability.o task.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 net.o \ + af_unix.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o clean-files := capability_names.h rlim_names.h net_names.h diff --git a/security/apparmor/af_unix.c b/security/apparmor/af_unix.c new file mode 100644 index 0000000000000..54b3796f63d0d --- /dev/null +++ b/security/apparmor/af_unix.c @@ -0,0 +1,652 @@ +/* + * AppArmor security module + * + * This file contains AppArmor af_unix fine grained mediation + * + * Copyright 2018 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 "include/audit.h" +#include "include/af_unix.h" +#include "include/apparmor.h" +#include "include/file.h" +#include "include/label.h" +#include "include/path.h" +#include "include/policy.h" +#include "include/cred.h" + +static inline struct sock *aa_sock(struct unix_sock *u) +{ + return &u->sk; +} + +static inline int unix_fs_perm(const char *op, u32 mask, struct aa_label *label, + struct unix_sock *u, int flags) +{ + AA_BUG(!label); + AA_BUG(!u); + AA_BUG(!UNIX_FS(aa_sock(u))); + + if (unconfined(label) || !LABEL_MEDIATES(label, AA_CLASS_FILE)) + return 0; + + mask &= NET_FS_PERMS; + if (!u->path.dentry) { + struct path_cond cond = { }; + struct aa_perms perms = { }; + struct aa_profile *profile; + + /* socket path has been cleared because it is being shutdown + * can only fall back to original sun_path request + */ + struct aa_sk_ctx *ctx = SK_CTX(&u->sk); + if (ctx->path.dentry) + return aa_path_perm(op, label, &ctx->path, flags, mask, + &cond); + return fn_for_each_confined(label, profile, + ((flags | profile->path_flags) & PATH_MEDIATE_DELETED) ? + __aa_path_perm(op, profile, + u->addr->name->sun_path, mask, + &cond, flags, &perms) : + aa_audit_file(profile, &nullperms, op, mask, + u->addr->name->sun_path, NULL, + NULL, cond.uid, + "Failed name lookup - " + "deleted entry", -EACCES)); + } else { + /* the sunpath may not be valid for this ns so use the path */ + struct path_cond cond = { u->path.dentry->d_inode->i_uid, + u->path.dentry->d_inode->i_mode + }; + + return aa_path_perm(op, label, &u->path, flags, mask, &cond); + } + + return 0; +} + +/* passing in state returned by PROFILE_MEDIATES_AF */ +static unsigned int match_to_prot(struct aa_profile *profile, + unsigned int state, int type, int protocol, + const char **info) +{ + __be16 buffer[2]; + buffer[0] = cpu_to_be16(type); + buffer[1] = cpu_to_be16(protocol); + state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer, + 4); + if (!state) + *info = "failed type and protocol match"; + return state; +} + +static unsigned int match_addr(struct aa_profile *profile, unsigned int state, + struct sockaddr_un *addr, int addrlen) +{ + if (addr) + /* include leading \0 */ + state = aa_dfa_match_len(profile->policy.dfa, state, + addr->sun_path, + unix_addr_len(addrlen)); + else + /* anonymous end point */ + state = aa_dfa_match_len(profile->policy.dfa, state, "\x01", + 1); + /* todo change to out of band */ + state = aa_dfa_null_transition(profile->policy.dfa, state); + return state; +} + +static unsigned int match_to_local(struct aa_profile *profile, + unsigned int state, int type, int protocol, + struct sockaddr_un *addr, int addrlen, + const char **info) +{ + state = match_to_prot(profile, state, type, protocol, info); + if (state) { + state = match_addr(profile, state, addr, addrlen); + if (state) { + /* todo: local label matching */ + state = aa_dfa_null_transition(profile->policy.dfa, + state); + if (!state) + *info = "failed local label match"; + } else + *info = "failed local address match"; + } + + return state; +} + +static unsigned int match_to_sk(struct aa_profile *profile, + unsigned int state, struct unix_sock *u, + const char **info) +{ + struct sockaddr_un *addr = NULL; + int addrlen = 0; + + if (u->addr) { + addr = u->addr->name; + addrlen = u->addr->len; + } + + return match_to_local(profile, state, u->sk.sk_type, u->sk.sk_protocol, + addr, addrlen, info); +} + +#define CMD_ADDR 1 +#define CMD_LISTEN 2 +#define CMD_OPT 4 + +static inline unsigned int match_to_cmd(struct aa_profile *profile, + unsigned int state, struct unix_sock *u, + char cmd, const char **info) +{ + state = match_to_sk(profile, state, u, info); + if (state) { + state = aa_dfa_match_len(profile->policy.dfa, state, &cmd, 1); + if (!state) + *info = "failed cmd selection match"; + } + + return state; +} + +static inline unsigned int match_to_peer(struct aa_profile *profile, + unsigned int state, + struct unix_sock *u, + struct sockaddr_un *peer_addr, + int peer_addrlen, + const char **info) +{ + state = match_to_cmd(profile, state, u, CMD_ADDR, info); + if (state) { + state = match_addr(profile, state, peer_addr, peer_addrlen); + if (!state) + *info = "failed peer address match"; + } + return state; +} + +static int do_perms(struct aa_profile *profile, unsigned int state, u32 request, + struct common_audit_data *sa) +{ + struct aa_perms perms; + + AA_BUG(!profile); + + aa_compute_perms(profile->policy.dfa, state, &perms); + aa_apply_modes_to_perms(profile, &perms); + return aa_check_perms(profile, &perms, request, sa, + audit_net_cb); +} + +static int match_label(struct aa_profile *profile, struct aa_profile *peer, + unsigned int state, u32 request, + struct common_audit_data *sa) +{ + AA_BUG(!profile); + AA_BUG(!peer); + + aad(sa)->peer = &peer->label; + + if (state) { + state = aa_dfa_match(profile->policy.dfa, state, + peer->base.hname); + if (!state) + aad(sa)->info = "failed peer label match"; + } + return do_perms(profile, state, request, sa); +} + + +/* unix sock creation comes before we know if the socket will be an fs + * socket + * v6 - semantics are handled by mapping in profile load + * v7 - semantics require sock create for tasks creating an fs socket. + */ +static int profile_create_perm(struct aa_profile *profile, int family, + int type, int protocol) +{ + unsigned int state; + DEFINE_AUDIT_NET(sa, OP_CREATE, NULL, family, type, protocol); + + AA_BUG(!profile); + AA_BUG(profile_unconfined(profile)); + + if ((state = PROFILE_MEDIATES_AF(profile, AF_UNIX))) { + state = match_to_prot(profile, state, type, protocol, + &aad(&sa)->info); + return do_perms(profile, state, AA_MAY_CREATE, &sa); + } + + return aa_profile_af_perm(profile, &sa, AA_MAY_CREATE, family, type); +} + +int aa_unix_create_perm(struct aa_label *label, int family, int type, + int protocol) +{ + struct aa_profile *profile; + + if (unconfined(label)) + return 0; + + return fn_for_each_confined(label, profile, + profile_create_perm(profile, family, type, protocol)); +} + + +static inline int profile_sk_perm(struct aa_profile *profile, const char *op, + u32 request, struct sock *sk) +{ + unsigned int state; + DEFINE_AUDIT_SK(sa, op, sk); + + AA_BUG(!profile); + AA_BUG(!sk); + AA_BUG(UNIX_FS(sk)); + AA_BUG(profile_unconfined(profile)); + + state = PROFILE_MEDIATES_AF(profile, AF_UNIX); + if (state) { + state = match_to_sk(profile, state, unix_sk(sk), + &aad(&sa)->info); + return do_perms(profile, state, request, &sa); + } + + return aa_profile_af_sk_perm(profile, &sa, request, sk); +} + +int aa_unix_label_sk_perm(struct aa_label *label, const char *op, u32 request, + struct sock *sk) +{ + struct aa_profile *profile; + + return fn_for_each_confined(label, profile, + profile_sk_perm(profile, op, request, sk)); +} + +static int unix_label_sock_perm(struct aa_label *label, const char *op, u32 request, + struct socket *sock) +{ + if (unconfined(label)) + return 0; + if (UNIX_FS(sock->sk)) + return unix_fs_perm(op, request, label, unix_sk(sock->sk), 0); + + return aa_unix_label_sk_perm(label, op, request, sock->sk); +} + +/* revaliation, get/set attr */ +int aa_unix_sock_perm(const char *op, u32 request, struct socket *sock) +{ + struct aa_label *label; + int error; + + label = begin_current_label_crit_section(); + error = unix_label_sock_perm(label, op, request, sock); + end_current_label_crit_section(label); + + return error; +} + +static int profile_bind_perm(struct aa_profile *profile, struct sock *sk, + struct sockaddr *addr, int addrlen) +{ + unsigned int state; + DEFINE_AUDIT_SK(sa, OP_BIND, sk); + + AA_BUG(!profile); + AA_BUG(!sk); + AA_BUG(addr->sa_family != AF_UNIX); + AA_BUG(profile_unconfined(profile)); + AA_BUG(unix_addr_fs(addr, addrlen)); + + state = PROFILE_MEDIATES_AF(profile, AF_UNIX); + if (state) { + /* bind for abstract socket */ + aad(&sa)->net.addr = unix_addr(addr); + aad(&sa)->net.addrlen = addrlen; + + state = match_to_local(profile, state, + sk->sk_type, sk->sk_protocol, + unix_addr(addr), addrlen, + &aad(&sa)->info); + return do_perms(profile, state, AA_MAY_BIND, &sa); + } + + return aa_profile_af_sk_perm(profile, &sa, AA_MAY_BIND, sk); +} + +int aa_unix_bind_perm(struct socket *sock, struct sockaddr *address, + int addrlen) +{ + struct aa_profile *profile; + struct aa_label *label; + int error = 0; + + label = begin_current_label_crit_section(); + /* fs bind is handled by mknod */ + if (!(unconfined(label) || unix_addr_fs(address, addrlen))) + error = fn_for_each_confined(label, profile, + profile_bind_perm(profile, sock->sk, address, + addrlen)); + end_current_label_crit_section(label); + + return error; +} + +int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address, + int addrlen) +{ + /* unix connections are covered by the + * - unix_stream_connect (stream) and unix_may_send hooks (dgram) + * - fs connect is handled by open + */ + return 0; +} + +static int profile_listen_perm(struct aa_profile *profile, struct sock *sk, + int backlog) +{ + unsigned int state; + DEFINE_AUDIT_SK(sa, OP_LISTEN, sk); + + AA_BUG(!profile); + AA_BUG(!sk); + AA_BUG(UNIX_FS(sk)); + AA_BUG(profile_unconfined(profile)); + + state = PROFILE_MEDIATES_AF(profile, AF_UNIX); + if (state) { + __be16 b = cpu_to_be16(backlog); + + state = match_to_cmd(profile, state, unix_sk(sk), CMD_LISTEN, + &aad(&sa)->info); + if (state) { + state = aa_dfa_match_len(profile->policy.dfa, state, + (char *) &b, 2); + if (!state) + aad(&sa)->info = "failed listen backlog match"; + } + return do_perms(profile, state, AA_MAY_LISTEN, &sa); + } + + return aa_profile_af_sk_perm(profile, &sa, AA_MAY_LISTEN, sk); +} + +int aa_unix_listen_perm(struct socket *sock, int backlog) +{ + struct aa_profile *profile; + struct aa_label *label; + int error = 0; + + label = begin_current_label_crit_section(); + if (!(unconfined(label) || UNIX_FS(sock->sk))) + error = fn_for_each_confined(label, profile, + profile_listen_perm(profile, sock->sk, + backlog)); + end_current_label_crit_section(label); + + return error; +} + + +static inline int profile_accept_perm(struct aa_profile *profile, + struct sock *sk, + struct sock *newsk) +{ + unsigned int state; + DEFINE_AUDIT_SK(sa, OP_ACCEPT, sk); + + AA_BUG(!profile); + AA_BUG(!sk); + AA_BUG(UNIX_FS(sk)); + AA_BUG(profile_unconfined(profile)); + + state = PROFILE_MEDIATES_AF(profile, AF_UNIX); + if (state) { + state = match_to_sk(profile, state, unix_sk(sk), + &aad(&sa)->info); + return do_perms(profile, state, AA_MAY_ACCEPT, &sa); + } + + return aa_profile_af_sk_perm(profile, &sa, AA_MAY_ACCEPT, sk); +} + +/* ability of sock to connect, not peer address binding */ +int aa_unix_accept_perm(struct socket *sock, struct socket *newsock) +{ + struct aa_profile *profile; + struct aa_label *label; + int error = 0; + + label = begin_current_label_crit_section(); + if (!(unconfined(label) || UNIX_FS(sock->sk))) + error = fn_for_each_confined(label, profile, + profile_accept_perm(profile, sock->sk, + newsock->sk)); + end_current_label_crit_section(label); + + return error; +} + + +/* dgram handled by unix_may_sendmsg, right to send on stream done at connect + * could do per msg unix_stream here + */ +/* sendmsg, recvmsg */ +int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock, + struct msghdr *msg, int size) +{ + return 0; +} + + +static int profile_opt_perm(struct aa_profile *profile, const char *op, u32 request, + struct sock *sk, int level, int optname) +{ + unsigned int state; + DEFINE_AUDIT_SK(sa, op, sk); + + AA_BUG(!profile); + AA_BUG(!sk); + AA_BUG(UNIX_FS(sk)); + AA_BUG(profile_unconfined(profile)); + + state = PROFILE_MEDIATES_AF(profile, AF_UNIX); + if (state) { + __be16 b = cpu_to_be16(optname); + + state = match_to_cmd(profile, state, unix_sk(sk), CMD_OPT, + &aad(&sa)->info); + if (state) { + state = aa_dfa_match_len(profile->policy.dfa, state, + (char *) &b, 2); + if (!state) + aad(&sa)->info = "failed sockopt match"; + } + return do_perms(profile, state, request, &sa); + } + + return aa_profile_af_sk_perm(profile, &sa, request, sk); +} + +int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock, int level, + int optname) +{ + struct aa_profile *profile; + struct aa_label *label; + int error = 0; + + label = begin_current_label_crit_section(); + if (!(unconfined(label) || UNIX_FS(sock->sk))) + error = fn_for_each_confined(label, profile, + profile_opt_perm(profile, op, request, + sock->sk, level, optname)); + end_current_label_crit_section(label); + + return error; +} + +/* null peer_label is allowed, in which case the peer_sk label is used */ +static int profile_peer_perm(struct aa_profile *profile, const char *op, u32 request, + struct sock *sk, struct sock *peer_sk, + struct aa_label *peer_label, + struct common_audit_data *sa) +{ + unsigned int state; + + AA_BUG(!profile); + AA_BUG(profile_unconfined(profile)); + AA_BUG(!sk); + AA_BUG(!peer_sk); + AA_BUG(UNIX_FS(peer_sk)); + + state = PROFILE_MEDIATES_AF(profile, AF_UNIX); + if (state) { + struct aa_sk_ctx *peer_ctx = SK_CTX(peer_sk); + struct aa_profile *peerp; + struct sockaddr_un *addr = NULL; + int len = 0; + if (unix_sk(peer_sk)->addr) { + addr = unix_sk(peer_sk)->addr->name; + len = unix_sk(peer_sk)->addr->len; + } + state = match_to_peer(profile, state, unix_sk(sk), + addr, len, &aad(sa)->info); + if (!peer_label) + peer_label = peer_ctx->label; + return fn_for_each_in_ns(peer_label, peerp, + match_label(profile, peerp, state, request, + sa)); + } + + return aa_profile_af_sk_perm(profile, sa, request, sk); +} + +/** + * + * Requires: lock held on both @sk and @peer_sk + */ +int aa_unix_peer_perm(struct aa_label *label, const char *op, u32 request, + struct sock *sk, struct sock *peer_sk, + struct aa_label *peer_label) +{ + struct unix_sock *peeru = unix_sk(peer_sk); + struct unix_sock *u = unix_sk(sk); + + AA_BUG(!label); + AA_BUG(!sk); + AA_BUG(!peer_sk); + + if (UNIX_FS(aa_sock(peeru))) + return unix_fs_perm(op, request, label, peeru, 0); + else if (UNIX_FS(aa_sock(u))) + return unix_fs_perm(op, request, label, u, 0); + else { + struct aa_profile *profile; + DEFINE_AUDIT_SK(sa, op, sk); + aad(&sa)->net.peer_sk = peer_sk; + + /* TODO: ns!!! */ + if (!net_eq(sock_net(sk), sock_net(peer_sk))) { + ; + } + + if (unconfined(label)) + return 0; + + return fn_for_each_confined(label, profile, + profile_peer_perm(profile, op, request, sk, + peer_sk, peer_label, &sa)); + } +} + + +/* from net/unix/af_unix.c */ +static void unix_state_double_lock(struct sock *sk1, struct sock *sk2) +{ + if (unlikely(sk1 == sk2) || !sk2) { + unix_state_lock(sk1); + return; + } + if (sk1 < sk2) { + unix_state_lock(sk1); + unix_state_lock_nested(sk2); + } else { + unix_state_lock(sk2); + unix_state_lock_nested(sk1); + } +} + +static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2) +{ + if (unlikely(sk1 == sk2) || !sk2) { + unix_state_unlock(sk1); + return; + } + unix_state_unlock(sk1); + unix_state_unlock(sk2); +} + +int aa_unix_file_perm(struct aa_label *label, const char *op, u32 request, + struct socket *sock) +{ + struct sock *peer_sk = NULL; + u32 sk_req = request & ~NET_PEER_MASK; + int error = 0; + + AA_BUG(!label); + AA_BUG(!sock); + AA_BUG(!sock->sk); + AA_BUG(sock->sk->sk_family != AF_UNIX); + + /* TODO: update sock label with new task label */ + unix_state_lock(sock->sk); + peer_sk = unix_peer(sock->sk); + if (peer_sk) + sock_hold(peer_sk); + if (!unix_connected(sock) && sk_req) { + error = unix_label_sock_perm(label, op, sk_req, sock); + if (!error) { + // update label + } + } + unix_state_unlock(sock->sk); + if (!peer_sk) + return error; + + unix_state_double_lock(sock->sk, peer_sk); + if (UNIX_FS(sock->sk)) { + error = unix_fs_perm(op, request, label, unix_sk(sock->sk), + PATH_SOCK_COND); + } else if (UNIX_FS(peer_sk)) { + error = unix_fs_perm(op, request, label, unix_sk(peer_sk), + PATH_SOCK_COND); + } else { + struct aa_sk_ctx *pctx = SK_CTX(peer_sk); + if (sk_req) + error = aa_unix_label_sk_perm(label, op, sk_req, + sock->sk); + last_error(error, + xcheck(aa_unix_peer_perm(label, op, + MAY_READ | MAY_WRITE, + sock->sk, peer_sk, NULL), + aa_unix_peer_perm(pctx->label, op, + MAY_READ | MAY_WRITE, + peer_sk, sock->sk, label))); + } + + unix_state_double_unlock(sock->sk, peer_sk); + sock_put(peer_sk); + + return error; +} diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 40e3a098f6fb5..3f411ea09017d 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -2258,6 +2258,11 @@ static struct aa_sfs_entry aa_sfs_entry_ns[] = { { } }; +static struct aa_sfs_entry aa_sfs_entry_dbus[] = { + AA_SFS_FILE_STRING("mask", "acquire send receive"), + { } +}; + static struct aa_sfs_entry aa_sfs_entry_query_label[] = { AA_SFS_FILE_STRING("perms", "allow deny audit quiet"), AA_SFS_FILE_BOOLEAN("data", 1), @@ -2274,6 +2279,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = { AA_SFS_DIR("domain", aa_sfs_entry_domain), AA_SFS_DIR("file", aa_sfs_entry_file), AA_SFS_DIR("network_v8", aa_sfs_entry_network), + AA_SFS_DIR("network", aa_sfs_entry_network_compat), AA_SFS_DIR("mount", aa_sfs_entry_mount), AA_SFS_DIR("namespaces", aa_sfs_entry_ns), AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), @@ -2281,6 +2287,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = { AA_SFS_DIR("caps", aa_sfs_entry_caps), AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace), AA_SFS_DIR("signal", aa_sfs_entry_signal), + AA_SFS_DIR("dbus", aa_sfs_entry_dbus), AA_SFS_DIR("query", aa_sfs_entry_query), { } }; diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 4285943f7260f..765408fb7a989 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -16,6 +16,7 @@ #include #include +#include "include/af_unix.h" #include "include/apparmor.h" #include "include/audit.h" #include "include/cred.h" @@ -284,7 +285,8 @@ int __aa_path_perm(const char *op, struct aa_profile *profile, const char *name, { int e = 0; - if (profile_unconfined(profile)) + if (profile_unconfined(profile) || + ((flags & PATH_SOCK_COND) && !PROFILE_MEDIATES_AF(profile, AF_UNIX))) return 0; aa_str_perms(profile->file.dfa, profile->file.start, name, cond, perms); if (request & ~perms->allow) diff --git a/security/apparmor/include/af_unix.h b/security/apparmor/include/af_unix.h new file mode 100644 index 0000000000000..d1b7f2316be47 --- /dev/null +++ b/security/apparmor/include/af_unix.h @@ -0,0 +1,114 @@ +/* + * AppArmor security module + * + * This file contains AppArmor af_unix fine grained mediation + * + * Copyright 2014 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_AF_UNIX_H + +#include + +#include "label.h" +//#include "include/net.h" + +#define unix_addr_len(L) ((L) - sizeof(sa_family_t)) +#define unix_abstract_name_len(L) (unix_addr_len(L) - 1) +#define unix_abstract_len(U) (unix_abstract_name_len((U)->addr->len)) +#define addr_unix_abstract_name(B) ((B)[0] == 0) +#define addr_unix_anonymous(U) (addr_unix_len(U) <= 0) +#define addr_unix_abstract(U) (!addr_unix_anonymous(U) && addr_unix_abstract_name((U)->addr)) +//#define unix_addr_fs(U) (!unix_addr_anonymous(U) && !unix_addr_abstract_name((U)->addr)) + +#define unix_addr(A) ((struct sockaddr_un *)(A)) +#define unix_addr_anon(A, L) ((A) && unix_addr_len(L) <= 0) +#define unix_addr_fs(A, L) (!unix_addr_anon(A, L) && !addr_unix_abstract_name(unix_addr(A)->sun_path)) + +#define UNIX_ANONYMOUS(U) (!unix_sk(U)->addr) +/* from net/unix/af_unix.c */ +#define UNIX_ABSTRACT(U) (!UNIX_ANONYMOUS(U) && \ + unix_sk(U)->addr->hash < UNIX_HASH_SIZE) +#define UNIX_FS(U) (!UNIX_ANONYMOUS(U) && unix_sk(U)->addr->name->sun_path[0]) +#define unix_peer(sk) (unix_sk(sk)->peer) +#define unix_connected(S) ((S)->state == SS_CONNECTED) + +static inline void print_unix_addr(struct sockaddr_un *A, int L) +{ + char *buf = (A) ? (char *) &(A)->sun_path : NULL; + int len = unix_addr_len(L); + if (!buf || len <= 0) + printk(" "); + else if (buf[0]) + printk(" %s", buf); + else + /* abstract name len includes leading \0 */ + printk(" %d @%.*s", len - 1, len - 1, buf+1); +}; + +/* + printk("%s: %s: f %d, t %d, p %d", __FUNCTION__, \ + #SK , \ +*/ +#define print_unix_sk(SK) \ +do { \ + struct unix_sock *u = unix_sk(SK); \ + printk("%s: f %d, t %d, p %d", #SK , \ + (SK)->sk_family, (SK)->sk_type, (SK)->sk_protocol); \ + if (u->addr) \ + print_unix_addr(u->addr->name, u->addr->len); \ + else \ + print_unix_addr(NULL, sizeof(sa_family_t)); \ + /* printk("\n");*/ \ +} while (0) + +#define print_sk(SK) \ +do { \ + if (!(SK)) { \ + printk("%s: %s is null\n", __FUNCTION__, #SK); \ + } else if ((SK)->sk_family == PF_UNIX) { \ + print_unix_sk(SK); \ + printk("\n"); \ + } else { \ + printk("%s: %s: family %d\n", __FUNCTION__, #SK , \ + (SK)->sk_family); \ + } \ +} while (0) + +#define print_sock_addr(U) \ +do { \ + printk("%s:\n", __FUNCTION__); \ + printk(" sock %s:", sock_ctx && sock_ctx->label ? aa_label_printk(sock_ctx->label, GFP_ATOMIC); : ""); print_sk(sock); \ + printk(" other %s:", other_ctx && other_ctx->label ? aa_label_printk(other_ctx->label, GFP_ATOMIC); : ""); print_sk(other); \ + printk(" new %s", new_ctx && new_ctx->label ? aa_label_printk(new_ctx->label, GFP_ATOMIC); : ""); print_sk(newsk); \ +} while (0) + + + + +int aa_unix_peer_perm(struct aa_label *label, const char *op, u32 request, + struct sock *sk, struct sock *peer_sk, + struct aa_label *peer_label); +int aa_unix_label_sk_perm(struct aa_label *label, const char *op, u32 request, + struct sock *sk); +int aa_unix_sock_perm(const char *op, u32 request, struct socket *sock); +int aa_unix_create_perm(struct aa_label *label, int family, int type, + int protocol); +int aa_unix_bind_perm(struct socket *sock, struct sockaddr *address, + int addrlen); +int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address, + int addrlen); +int aa_unix_listen_perm(struct socket *sock, int backlog); +int aa_unix_accept_perm(struct socket *sock, struct socket *newsock); +int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock, + struct msghdr *msg, int size); +int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock, int level, + int optname); +int aa_unix_file_perm(struct aa_label *label, const char *op, u32 request, + struct socket *sock); + +#endif /* __AA_AF_UNIX_H */ diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 73d63b58d875b..17d89f3badc65 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -24,7 +24,7 @@ #define AA_CLASS_UNKNOWN 1 #define AA_CLASS_FILE 2 #define AA_CLASS_CAP 3 -#define AA_CLASS_DEPRECATED 4 +#define AA_CLASS_NET_COMPAT 4 #define AA_CLASS_RLIMITS 5 #define AA_CLASS_DOMAIN 6 #define AA_CLASS_MOUNT 7 diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h index ec7228e857a90..48e07dcbb44d0 100644 --- a/security/apparmor/include/net.h +++ b/security/apparmor/include/net.h @@ -53,6 +53,7 @@ struct aa_sk_ctx { struct aa_label *label; struct aa_label *peer; + struct path path; }; #define SK_CTX(X) ((X)->sk_security) @@ -72,11 +73,24 @@ struct aa_sk_ctx { DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ (SK)->sk_protocol) +/* struct aa_net - network confinement data + * @allow: basic network families permissions + * @audit: which network permissions to force audit + * @quiet: which network permissions to quiet rejects + */ +struct aa_net_compat { + u16 allow[AF_MAX]; + u16 audit[AF_MAX]; + u16 quiet[AF_MAX]; +}; #define af_select(FAMILY, FN, DEF_FN) \ ({ \ int __e; \ switch ((FAMILY)) { \ + case AF_UNIX: \ + __e = aa_unix_ ## FN; \ + break; \ default: \ __e = DEF_FN; \ } \ @@ -84,6 +98,7 @@ struct aa_sk_ctx { }) extern struct aa_sfs_entry aa_sfs_entry_network[]; +extern struct aa_sfs_entry aa_sfs_entry_network_compat[]; void audit_net_cb(struct audit_buffer *ab, void *va); int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, diff --git a/security/apparmor/include/path.h b/security/apparmor/include/path.h index b6380c5f00972..ab1c3e4fda66f 100644 --- a/security/apparmor/include/path.h +++ b/security/apparmor/include/path.h @@ -18,6 +18,7 @@ enum path_flags { PATH_IS_DIR = 0x1, /* path is a directory */ + PATH_SOCK_COND = 0x2, PATH_CONNECT_PATH = 0x4, /* connect disconnected paths to / */ PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */ PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 28c098fb6208b..35e258e2bdb83 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -112,6 +112,7 @@ struct aa_data { * @policy: general match rules governing policy * @file: The set of rules governing basic file access and domain transitions * @caps: capabilities for the profile + * @net_compat: v2 compat network controls for the profile * @rlimits: rlimits for the profile * * @dents: dentries for the profiles file entries in apparmorfs @@ -149,6 +150,7 @@ struct aa_profile { struct aa_policydb policy; struct aa_file_rules file; struct aa_caps caps; + struct aa_net_compat *net_compat; int xattr_count; char **xattrs; @@ -229,9 +231,13 @@ static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile, unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET); __be16 be_af = cpu_to_be16(AF); - if (!state) - return 0; - return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); + if (!state) { + state = PROFILE_MEDIATES(profile, AA_CLASS_NET_COMPAT); + if (!state) + return 0; + } + state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); + return state; } /** diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 8b8b70620bbe7..76995ec637a21 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -23,8 +23,10 @@ #include #include #include +#include #include +#include "include/af_unix.h" #include "include/apparmor.h" #include "include/apparmorfs.h" #include "include/audit.h" @@ -785,6 +787,7 @@ static void apparmor_sk_free_security(struct sock *sk) SK_CTX(sk) = NULL; aa_put_label(ctx->label); aa_put_label(ctx->peer); + path_put(&ctx->path); kfree(ctx); } @@ -799,6 +802,99 @@ static void apparmor_sk_clone_security(const struct sock *sk, new->label = aa_get_label(ctx->label); new->peer = aa_get_label(ctx->peer); + new->path = ctx->path; + path_get(&new->path); +} + +static struct path *UNIX_FS_CONN_PATH(struct sock *sk, struct sock *newsk) +{ + if (sk->sk_family == PF_UNIX && UNIX_FS(sk)) + return &unix_sk(sk)->path; + else if (newsk->sk_family == PF_UNIX && UNIX_FS(newsk)) + return &unix_sk(newsk)->path; + return NULL; +} + +/** + * apparmor_unix_stream_connect - check perms before making unix domain conn + * + * peer is locked when this hook is called + */ +static int apparmor_unix_stream_connect(struct sock *sk, struct sock *peer_sk, + struct sock *newsk) +{ + struct aa_sk_ctx *sk_ctx = SK_CTX(sk); + struct aa_sk_ctx *peer_ctx = SK_CTX(peer_sk); + struct aa_sk_ctx *new_ctx = SK_CTX(newsk); + struct aa_label *label; + struct path *path; + int error; + + label = __begin_current_label_crit_section(); + error = aa_unix_peer_perm(label, OP_CONNECT, + (AA_MAY_CONNECT | AA_MAY_SEND | AA_MAY_RECEIVE), + sk, peer_sk, NULL); + if (!UNIX_FS(peer_sk)) { + last_error(error, + aa_unix_peer_perm(peer_ctx->label, OP_CONNECT, + (AA_MAY_ACCEPT | AA_MAY_SEND | AA_MAY_RECEIVE), + peer_sk, sk, label)); + } + __end_current_label_crit_section(label); + + if (error) + return error; + + /* label newsk if it wasn't labeled in post_create. Normally this + * would be done in sock_graft, but because we are directly looking + * at the peer_sk to obtain peer_labeling for unix socks this + * does not work + */ + if (!new_ctx->label) + new_ctx->label = aa_get_label(peer_ctx->label); + + /* Cross reference the peer labels for SO_PEERSEC */ + if (new_ctx->peer) + aa_put_label(new_ctx->peer); + + if (sk_ctx->peer) + aa_put_label(sk_ctx->peer); + + new_ctx->peer = aa_get_label(sk_ctx->label); + sk_ctx->peer = aa_get_label(peer_ctx->label); + + path = UNIX_FS_CONN_PATH(sk, peer_sk); + if (path) { + new_ctx->path = *path; + sk_ctx->path = *path; + path_get(path); + path_get(path); + } + return 0; +} + +/** + * apparmor_unix_may_send - check perms before conn or sending unix dgrams + * + * other is locked when this hook is called + * + * dgram connect calls may_send, peer setup but path not copied????? + */ +static int apparmor_unix_may_send(struct socket *sock, struct socket *peer) +{ + struct aa_sk_ctx *peer_ctx = SK_CTX(peer->sk); + struct aa_label *label; + int error; + + label = __begin_current_label_crit_section(); + error = xcheck(aa_unix_peer_perm(label, OP_SENDMSG, AA_MAY_SEND, + sock->sk, peer->sk, NULL), + aa_unix_peer_perm(peer_ctx->label, OP_SENDMSG, + AA_MAY_RECEIVE, + peer->sk, sock->sk, label)); + __end_current_label_crit_section(label); + + return error; } /** @@ -1036,12 +1132,28 @@ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) static struct aa_label *sk_peer_label(struct sock *sk) { + struct sock *peer_sk; struct aa_sk_ctx *ctx = SK_CTX(sk); + struct aa_label *label = ERR_PTR(-ENOPROTOOPT); if (ctx->peer) - return ctx->peer; + return aa_get_label(ctx->peer); - return ERR_PTR(-ENOPROTOOPT); + if (sk->sk_family != PF_UNIX) + return ERR_PTR(-ENOPROTOOPT); + + /* check for sockpair peering which does not go through + * security_unix_stream_connect + */ + peer_sk = unix_peer_get(sk); + if (peer_sk) { + ctx = SK_CTX(peer_sk); + if (ctx->label) + label = aa_get_label(ctx->label); + sock_put(peer_sk); + } + + return label; } /** @@ -1085,6 +1197,7 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock, } + aa_put_label(peer); done: end_current_label_crit_section(label); @@ -1164,6 +1277,9 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), + LSM_HOOK_INIT(unix_stream_connect, apparmor_unix_stream_connect), + LSM_HOOK_INIT(unix_may_send, apparmor_unix_may_send), + 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), diff --git a/security/apparmor/net.c b/security/apparmor/net.c index bb24cfa0a164c..042aee4408c1b 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c @@ -12,6 +12,7 @@ * License. */ +#include "include/af_unix.h" #include "include/apparmor.h" #include "include/audit.h" #include "include/cred.h" @@ -27,6 +28,12 @@ struct aa_sfs_entry aa_sfs_entry_network[] = { { } }; +struct aa_sfs_entry aa_sfs_entry_network_compat[] = { + AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), + AA_SFS_FILE_BOOLEAN("af_unix", 1), + { } +}; + static const char * const net_mask_names[] = { "unknown", "send", @@ -69,6 +76,36 @@ static const char * const net_mask_names[] = { "unknown", }; +static void audit_unix_addr(struct audit_buffer *ab, const char *str, + struct sockaddr_un *addr, int addrlen) +{ + int len = unix_addr_len(addrlen); + + if (!addr || len <= 0) { + audit_log_format(ab, " %s=none", str); + } else if (addr->sun_path[0]) { + audit_log_format(ab, " %s=", str); + audit_log_untrustedstring(ab, addr->sun_path); + } else { + audit_log_format(ab, " %s=\"@", str); + if (audit_string_contains_control(&addr->sun_path[1], len - 1)) + audit_log_n_hex(ab, &addr->sun_path[1], len - 1); + else + audit_log_format(ab, "%.*s", len - 1, + &addr->sun_path[1]); + audit_log_format(ab, "\""); + } +} + +static void audit_unix_sk_addr(struct audit_buffer *ab, const char *str, + struct sock *sk) +{ + struct unix_sock *u = unix_sk(sk); + if (u && u->addr) + audit_unix_addr(ab, str, u->addr->name, u->addr->len); + else + audit_unix_addr(ab, str, NULL, 0); +} /* audit callback for net specific fields */ void audit_net_cb(struct audit_buffer *ab, void *va) @@ -98,6 +135,23 @@ void audit_net_cb(struct audit_buffer *ab, void *va) net_mask_names, NET_PERMS_MASK); } } + if (sa->u.net->family == AF_UNIX) { + if ((aad(sa)->request & ~NET_PEER_MASK) && aad(sa)->net.addr) + audit_unix_addr(ab, "addr", + unix_addr(aad(sa)->net.addr), + aad(sa)->net.addrlen); + else + audit_unix_sk_addr(ab, "addr", sa->u.net->sk); + if (aad(sa)->request & NET_PEER_MASK) { + if (aad(sa)->net.addr) + audit_unix_addr(ab, "peer_addr", + unix_addr(aad(sa)->net.addr), + aad(sa)->net.addrlen); + else + audit_unix_sk_addr(ab, "peer_addr", + aad(sa)->net.peer_sk); + } + } if (aad(sa)->peer) { audit_log_format(ab, " peer="); aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, @@ -119,14 +173,26 @@ int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, if (profile_unconfined(profile)) return 0; state = PROFILE_MEDIATES(profile, AA_CLASS_NET); - if (!state) + if (state) { + if (!state) + return 0; + buffer[0] = cpu_to_be16(family); + buffer[1] = cpu_to_be16((u16) type); + state = aa_dfa_match_len(profile->policy.dfa, state, + (char *) &buffer, 4); + aa_compute_perms(profile->policy.dfa, state, &perms); + } else if (profile->net_compat) { + /* 2.x socket mediation compat */ + perms.allow = (profile->net_compat->allow[family] & (1 << type)) ? + ALL_PERMS_MASK : 0; + perms.audit = (profile->net_compat->audit[family] & (1 << type)) ? + ALL_PERMS_MASK : 0; + perms.quiet = (profile->net_compat->quiet[family] & (1 << type)) ? + ALL_PERMS_MASK : 0; + + } else { return 0; - - buffer[0] = cpu_to_be16(family); - buffer[1] = cpu_to_be16((u16) type); - state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer, - 4); - aa_compute_perms(profile->policy.dfa, state, &perms); + } aa_apply_modes_to_perms(profile, &perms); return aa_check_perms(profile, &perms, request, sa, audit_net_cb); @@ -183,5 +249,7 @@ int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, AA_BUG(!sock); AA_BUG(!sock->sk); - return aa_label_sk_perm(label, op, request, sock->sk); + return af_select(sock->sk->sk_family, + file_perm(label, op, request, sock), + aa_label_sk_perm(label, op, request, sock->sk)); } diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 1590e2de4e841..1a8e0502fe604 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -227,6 +227,7 @@ void aa_free_profile(struct aa_profile *profile) aa_free_file_rules(&profile->file); aa_free_cap_rules(&profile->caps); aa_free_rlimit_rules(&profile->rlimits); + kzfree(profile->net_compat); for (i = 0; i < profile->xattr_count; i++) kzfree(profile->xattrs[i]); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 612f737cee836..a068f37fcdfb7 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -37,7 +37,7 @@ #define v5 5 /* base version */ #define v6 6 /* per entry policydb mediation check */ -#define v7 7 +#define v7 7 /* v2 compat networking */ #define v8 8 /* full network masking */ /* @@ -297,6 +297,19 @@ static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name) return 0; } +static bool unpack_u16(struct aa_ext *e, u16 *data, const char *name) +{ + if (unpack_nameX(e, AA_U16, name)) { + if (!inbounds(e, sizeof(u16))) + return false; + if (data) + *data = le16_to_cpu(get_unaligned((__le16 *) e->pos)); + e->pos += sizeof(u16); + return true; + } + return false; +} + static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) { void *pos = e->pos; @@ -615,7 +628,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) struct aa_profile *profile = NULL; const char *tmpname, *tmpns = NULL, *name = NULL; const char *info = "failed to unpack profile"; - size_t ns_len; + size_t size = 0, ns_len; struct rhashtable_params params = { 0 }; char *key = NULL; struct aa_data *data; @@ -753,6 +766,43 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) goto fail; } + size = unpack_array(e, "net_allowed_af"); + if (size || VERSION_LT(e->version, v8)) { + profile->net_compat = kzalloc(sizeof(struct aa_net_compat), GFP_KERNEL); + if (!profile->net_compat) { + info = "out of memory"; + goto fail; + } + for (i = 0; i < size; i++) { + /* discard extraneous rules that this kernel will + * never request + */ + if (i >= AF_MAX) { + u16 tmp; + + if (!unpack_u16(e, &tmp, NULL) || + !unpack_u16(e, &tmp, NULL) || + !unpack_u16(e, &tmp, NULL)) + goto fail; + continue; + } + if (!unpack_u16(e, &profile->net_compat->allow[i], NULL)) + goto fail; + if (!unpack_u16(e, &profile->net_compat->audit[i], NULL)) + goto fail; + if (!unpack_u16(e, &profile->net_compat->quiet[i], NULL)) + goto fail; + } + if (size && !unpack_nameX(e, AA_ARRAYEND, NULL)) + goto fail; + if (VERSION_LT(e->version, v7)) { + /* pre v7 policy always allowed these */ + profile->net_compat->allow[AF_UNIX] = 0xffff; + profile->net_compat->allow[AF_NETLINK] = 0xffff; + } + } + + if (unpack_nameX(e, AA_STRUCT, "policydb")) { /* generic policy dfa - optional and may be NULL */ info = "failed to unpack policydb"; From 629a09fa238675b47183426670c4000fe88050a3 Mon Sep 17 00:00:00 2001 From: Daniel Llewellyn Date: Mon, 21 Oct 2019 23:55:45 +0100 Subject: [PATCH 2/2] Update Microsoft/config-wsl* * Add AppArmor for arm64 * Change LOCALVERSION for snapd identification Signed-off-by: Daniel Llewellyn --- Microsoft/config-wsl | 2 +- Microsoft/config-wsl-arm64 | 32 ++++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/Microsoft/config-wsl b/Microsoft/config-wsl index 9c96f3c3b4bed..7ca4148d8beba 100644 --- a/Microsoft/config-wsl +++ b/Microsoft/config-wsl @@ -19,7 +19,7 @@ CONFIG_THREAD_INFO_IN_TASK=y # CONFIG_INIT_ENV_ARG_LIMIT=32 # CONFIG_COMPILE_TEST is not set -CONFIG_LOCALVERSION="-microsoft-standard" +CONFIG_LOCALVERSION="-microsoft-snapd" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_BUILD_SALT="" CONFIG_HAVE_KERNEL_GZIP=y diff --git a/Microsoft/config-wsl-arm64 b/Microsoft/config-wsl-arm64 index b3c7b97597732..44bf511b3bd2c 100644 --- a/Microsoft/config-wsl-arm64 +++ b/Microsoft/config-wsl-arm64 @@ -4,10 +4,10 @@ # # -# Compiler: aarch64-msft-linux-gcc (GCC) 8.2.0 +# Compiler: gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0 # CONFIG_CC_IS_GCC=y -CONFIG_GCC_VERSION=80200 +CONFIG_GCC_VERSION=70400 CONFIG_CLANG_VERSION=0 CONFIG_CC_HAS_ASM_GOTO=y CONFIG_IRQ_WORK=y @@ -19,7 +19,7 @@ CONFIG_THREAD_INFO_IN_TASK=y # CONFIG_INIT_ENV_ARG_LIMIT=32 # CONFIG_COMPILE_TEST is not set -CONFIG_LOCALVERSION="-microsoft-standard" +CONFIG_LOCALVERSION="-microsoft-snapd" # CONFIG_LOCALVERSION_AUTO is not set CONFIG_BUILD_SALT="" CONFIG_DEFAULT_HOSTNAME="(none)" @@ -30,8 +30,11 @@ CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE_SYSCTL=y CONFIG_CROSS_MEMORY_ATTACH=y # CONFIG_USELIB is not set -# CONFIG_AUDIT is not set +CONFIG_AUDIT=y CONFIG_HAVE_ARCH_AUDITSYSCALL=y +CONFIG_AUDITSYSCALL=y +CONFIG_AUDIT_WATCH=y +CONFIG_AUDIT_TREE=y # # IRQ subsystem @@ -943,6 +946,7 @@ CONFIG_NETFILTER_XT_SET=y # # Xtables targets # +# CONFIG_NETFILTER_XT_TARGET_AUDIT is not set CONFIG_NETFILTER_XT_TARGET_CHECKSUM=y # CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set # CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set @@ -2508,22 +2512,29 @@ CONFIG_KEYS=y # CONFIG_KEY_DH_OPERATIONS is not set CONFIG_SECURITY_DMESG_RESTRICT=y CONFIG_SECURITY=y -# CONFIG_SECURITYFS is not set -# CONFIG_SECURITY_NETWORK is not set -# CONFIG_SECURITY_PATH is not set +CONFIG_SECURITYFS=y +CONFIG_SECURITY_NETWORK=y +# CONFIG_SECURITY_NETWORK_XFRM is not set +CONFIG_SECURITY_PATH=y CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y # CONFIG_HARDENED_USERCOPY is not set # CONFIG_FORTIFY_SOURCE is not set CONFIG_STATIC_USERMODEHELPER=y CONFIG_STATIC_USERMODEHELPER_PATH="/sbin/usermode-helper" +# CONFIG_SECURITY_SELINUX is not set # CONFIG_SECURITY_SMACK is not set # CONFIG_SECURITY_TOMOYO is not set -# CONFIG_SECURITY_APPARMOR is not set +CONFIG_SECURITY_APPARMOR=y +CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE=1 +CONFIG_SECURITY_APPARMOR_HASH=y +CONFIG_SECURITY_APPARMOR_HASH_DEFAULT=y +# CONFIG_SECURITY_APPARMOR_DEBUG is not set # CONFIG_SECURITY_LOADPIN is not set # CONFIG_SECURITY_YAMA is not set # CONFIG_INTEGRITY is not set -CONFIG_DEFAULT_SECURITY_DAC=y -CONFIG_DEFAULT_SECURITY="" +CONFIG_DEFAULT_SECURITY_APPARMOR=y +# CONFIG_DEFAULT_SECURITY_DAC is not set +CONFIG_DEFAULT_SECURITY="apparmor" CONFIG_CRYPTO=y # @@ -2722,6 +2733,7 @@ CONFIG_CRC32_SLICEBY8=y CONFIG_LIBCRC32C=y # CONFIG_CRC8 is not set CONFIG_XXHASH=y +CONFIG_AUDIT_GENERIC=y CONFIG_AUDIT_ARCH_COMPAT_GENERIC=y # CONFIG_RANDOM32_SELFTEST is not set CONFIG_ZLIB_INFLATE=y