diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-02 13:04:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-11-02 13:04:26 -0400 |
commit | d81f50bd34646d8373b989e55180c0fc9af94e0b (patch) | |
tree | a72b051a41717a7b8bacd7cf61965ff0e0dfa4ed /security | |
parent | c2aa1a444cab2c673650ada80a7dffc4345ce2e6 (diff) | |
parent | 566f52ece7bd1099d20dfe2f6f0801896643cf8f (diff) |
Merge tag 'apparmor-pr-2018-11-01' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
Pull apparmor updates from John Johansen:
"Features/Improvements:
- replace spin_is_locked() with lockdep
- add base support for secmark labeling and matching
Cleanups:
- clean an indentation issue, remove extraneous space
- remove no-op permission check in policy_unpack
- fix checkpatch missing spaces error in Parse secmark policy
- fix network performance issue in aa_label_sk_perm
Bug fixes:
- add #ifdef checks for secmark filtering
- fix an error code in __aa_create_ns()
- don't try to replace stale label in ptrace checks
- fix failure to audit context info in build_change_hat
- check buffer bounds when mapping permissions mask
- fully initialize aa_perms struct when answering userspace query
- fix uninitialized value in aa_split_fqname"
* tag 'apparmor-pr-2018-11-01' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor:
apparmor: clean an indentation issue, remove extraneous space
apparmor: fix checkpatch error in Parse secmark policy
apparmor: add #ifdef checks for secmark filtering
apparmor: Fix uninitialized value in aa_split_fqname
apparmor: don't try to replace stale label in ptraceme check
apparmor: Replace spin_is_locked() with lockdep
apparmor: Allow filtering based on secmark policy
apparmor: Parse secmark policy
apparmor: Add a wildcard secid
apparmor: don't try to replace stale label in ptrace access check
apparmor: Fix network performance issue in aa_label_sk_perm
Diffstat (limited to 'security')
-rw-r--r-- | security/apparmor/apparmorfs.c | 2 | ||||
-rw-r--r-- | security/apparmor/file.c | 2 | ||||
-rw-r--r-- | security/apparmor/include/cred.h | 2 | ||||
-rw-r--r-- | security/apparmor/include/net.h | 10 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 3 | ||||
-rw-r--r-- | security/apparmor/include/secid.h | 3 | ||||
-rw-r--r-- | security/apparmor/lib.c | 6 | ||||
-rw-r--r-- | security/apparmor/lsm.c | 130 | ||||
-rw-r--r-- | security/apparmor/net.c | 83 | ||||
-rw-r--r-- | security/apparmor/policy.c | 3 | ||||
-rw-r--r-- | security/apparmor/policy_unpack.c | 61 | ||||
-rw-r--r-- | security/apparmor/secid.c | 3 |
12 files changed, 291 insertions, 17 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index e09fe4d7307c..8963203319ea 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c | |||
@@ -1742,7 +1742,7 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) | |||
1742 | if (error) | 1742 | if (error) |
1743 | return error; | 1743 | return error; |
1744 | 1744 | ||
1745 | parent = aa_get_ns(dir->i_private); | 1745 | parent = aa_get_ns(dir->i_private); |
1746 | /* rmdir calls the generic securityfs functions to remove files | 1746 | /* rmdir calls the generic securityfs functions to remove files |
1747 | * from the apparmor dir. It is up to the apparmor ns locking | 1747 | * from the apparmor dir. It is up to the apparmor ns locking |
1748 | * to avoid races. | 1748 | * to avoid races. |
diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 4285943f7260..d0afed9ebd0e 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c | |||
@@ -496,7 +496,7 @@ static void update_file_ctx(struct aa_file_ctx *fctx, struct aa_label *label, | |||
496 | /* update caching of label on file_ctx */ | 496 | /* update caching of label on file_ctx */ |
497 | spin_lock(&fctx->lock); | 497 | spin_lock(&fctx->lock); |
498 | old = rcu_dereference_protected(fctx->label, | 498 | old = rcu_dereference_protected(fctx->label, |
499 | spin_is_locked(&fctx->lock)); | 499 | lockdep_is_held(&fctx->lock)); |
500 | l = aa_label_merge(old, label, GFP_ATOMIC); | 500 | l = aa_label_merge(old, label, GFP_ATOMIC); |
501 | if (l) { | 501 | if (l) { |
502 | if (l != old) { | 502 | if (l != old) { |
diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h index e287b7d0d4be..265ae6641a06 100644 --- a/security/apparmor/include/cred.h +++ b/security/apparmor/include/cred.h | |||
@@ -151,6 +151,8 @@ static inline struct aa_label *begin_current_label_crit_section(void) | |||
151 | { | 151 | { |
152 | struct aa_label *label = aa_current_raw_label(); | 152 | struct aa_label *label = aa_current_raw_label(); |
153 | 153 | ||
154 | might_sleep(); | ||
155 | |||
154 | if (label_is_stale(label)) { | 156 | if (label_is_stale(label)) { |
155 | label = aa_get_newest_label(label); | 157 | label = aa_get_newest_label(label); |
156 | if (aa_replace_current_label(label) == 0) | 158 | if (aa_replace_current_label(label) == 0) |
diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h index ec7228e857a9..7334ac966d01 100644 --- a/security/apparmor/include/net.h +++ b/security/apparmor/include/net.h | |||
@@ -83,6 +83,13 @@ struct aa_sk_ctx { | |||
83 | __e; \ | 83 | __e; \ |
84 | }) | 84 | }) |
85 | 85 | ||
86 | struct aa_secmark { | ||
87 | u8 audit; | ||
88 | u8 deny; | ||
89 | u32 secid; | ||
90 | char *label; | ||
91 | }; | ||
92 | |||
86 | extern struct aa_sfs_entry aa_sfs_entry_network[]; | 93 | extern struct aa_sfs_entry aa_sfs_entry_network[]; |
87 | 94 | ||
88 | void audit_net_cb(struct audit_buffer *ab, void *va); | 95 | void audit_net_cb(struct audit_buffer *ab, void *va); |
@@ -103,4 +110,7 @@ int aa_sk_perm(const char *op, u32 request, struct sock *sk); | |||
103 | int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, | 110 | int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, |
104 | struct socket *sock); | 111 | struct socket *sock); |
105 | 112 | ||
113 | int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, | ||
114 | u32 secid, struct sock *sk); | ||
115 | |||
106 | #endif /* __AA_NET_H */ | 116 | #endif /* __AA_NET_H */ |
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index ab64c6b5db5a..8e6707c837be 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h | |||
@@ -155,6 +155,9 @@ struct aa_profile { | |||
155 | 155 | ||
156 | struct aa_rlimit rlimits; | 156 | struct aa_rlimit rlimits; |
157 | 157 | ||
158 | int secmark_count; | ||
159 | struct aa_secmark *secmark; | ||
160 | |||
158 | struct aa_loaddata *rawdata; | 161 | struct aa_loaddata *rawdata; |
159 | unsigned char *hash; | 162 | unsigned char *hash; |
160 | char *dirname; | 163 | char *dirname; |
diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h index dee6fa3b6081..fa2062711b63 100644 --- a/security/apparmor/include/secid.h +++ b/security/apparmor/include/secid.h | |||
@@ -22,6 +22,9 @@ struct aa_label; | |||
22 | /* secid value that will not be allocated */ | 22 | /* secid value that will not be allocated */ |
23 | #define AA_SECID_INVALID 0 | 23 | #define AA_SECID_INVALID 0 |
24 | 24 | ||
25 | /* secid value that matches any other secid */ | ||
26 | #define AA_SECID_WILDCARD 1 | ||
27 | |||
25 | struct aa_label *aa_secid_to_label(u32 secid); | 28 | struct aa_label *aa_secid_to_label(u32 secid); |
26 | int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); | 29 | int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); |
27 | int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); | 30 | int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); |
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 974affe50531..76491e7f4177 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c | |||
@@ -90,10 +90,12 @@ const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, | |||
90 | const char *end = fqname + n; | 90 | const char *end = fqname + n; |
91 | const char *name = skipn_spaces(fqname, n); | 91 | const char *name = skipn_spaces(fqname, n); |
92 | 92 | ||
93 | if (!name) | ||
94 | return NULL; | ||
95 | *ns_name = NULL; | 93 | *ns_name = NULL; |
96 | *ns_len = 0; | 94 | *ns_len = 0; |
95 | |||
96 | if (!name) | ||
97 | return NULL; | ||
98 | |||
97 | if (name[0] == ':') { | 99 | if (name[0] == ':') { |
98 | char *split = strnchr(&name[1], end - &name[1], ':'); | 100 | char *split = strnchr(&name[1], end - &name[1], ':'); |
99 | *ns_name = skipn_spaces(&name[1], end - &name[1]); | 101 | *ns_name = skipn_spaces(&name[1], end - &name[1]); |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index aa35939443c4..42446a216f3b 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/sysctl.h> | 23 | #include <linux/sysctl.h> |
24 | #include <linux/audit.h> | 24 | #include <linux/audit.h> |
25 | #include <linux/user_namespace.h> | 25 | #include <linux/user_namespace.h> |
26 | #include <linux/netfilter_ipv4.h> | ||
27 | #include <linux/netfilter_ipv6.h> | ||
26 | #include <net/sock.h> | 28 | #include <net/sock.h> |
27 | 29 | ||
28 | #include "include/apparmor.h" | 30 | #include "include/apparmor.h" |
@@ -114,13 +116,13 @@ static int apparmor_ptrace_access_check(struct task_struct *child, | |||
114 | struct aa_label *tracer, *tracee; | 116 | struct aa_label *tracer, *tracee; |
115 | int error; | 117 | int error; |
116 | 118 | ||
117 | tracer = begin_current_label_crit_section(); | 119 | tracer = __begin_current_label_crit_section(); |
118 | tracee = aa_get_task_label(child); | 120 | tracee = aa_get_task_label(child); |
119 | error = aa_may_ptrace(tracer, tracee, | 121 | error = aa_may_ptrace(tracer, tracee, |
120 | (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ | 122 | (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ |
121 | : AA_PTRACE_TRACE); | 123 | : AA_PTRACE_TRACE); |
122 | aa_put_label(tracee); | 124 | aa_put_label(tracee); |
123 | end_current_label_crit_section(tracer); | 125 | __end_current_label_crit_section(tracer); |
124 | 126 | ||
125 | return error; | 127 | return error; |
126 | } | 128 | } |
@@ -130,11 +132,11 @@ static int apparmor_ptrace_traceme(struct task_struct *parent) | |||
130 | struct aa_label *tracer, *tracee; | 132 | struct aa_label *tracer, *tracee; |
131 | int error; | 133 | int error; |
132 | 134 | ||
133 | tracee = begin_current_label_crit_section(); | 135 | tracee = __begin_current_label_crit_section(); |
134 | tracer = aa_get_task_label(parent); | 136 | tracer = aa_get_task_label(parent); |
135 | error = aa_may_ptrace(tracer, tracee, AA_PTRACE_TRACE); | 137 | error = aa_may_ptrace(tracer, tracee, AA_PTRACE_TRACE); |
136 | aa_put_label(tracer); | 138 | aa_put_label(tracer); |
137 | end_current_label_crit_section(tracee); | 139 | __end_current_label_crit_section(tracee); |
138 | 140 | ||
139 | return error; | 141 | return error; |
140 | } | 142 | } |
@@ -1020,6 +1022,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how) | |||
1020 | return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock); | 1022 | return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock); |
1021 | } | 1023 | } |
1022 | 1024 | ||
1025 | #ifdef CONFIG_NETWORK_SECMARK | ||
1023 | /** | 1026 | /** |
1024 | * apparmor_socket_sock_recv_skb - check perms before associating skb to sk | 1027 | * apparmor_socket_sock_recv_skb - check perms before associating skb to sk |
1025 | * | 1028 | * |
@@ -1030,8 +1033,15 @@ static int apparmor_socket_shutdown(struct socket *sock, int how) | |||
1030 | */ | 1033 | */ |
1031 | static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 1034 | static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) |
1032 | { | 1035 | { |
1033 | return 0; | 1036 | struct aa_sk_ctx *ctx = SK_CTX(sk); |
1037 | |||
1038 | if (!skb->secmark) | ||
1039 | return 0; | ||
1040 | |||
1041 | return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE, | ||
1042 | skb->secmark, sk); | ||
1034 | } | 1043 | } |
1044 | #endif | ||
1035 | 1045 | ||
1036 | 1046 | ||
1037 | static struct aa_label *sk_peer_label(struct sock *sk) | 1047 | static struct aa_label *sk_peer_label(struct sock *sk) |
@@ -1126,6 +1136,20 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent) | |||
1126 | ctx->label = aa_get_current_label(); | 1136 | ctx->label = aa_get_current_label(); |
1127 | } | 1137 | } |
1128 | 1138 | ||
1139 | #ifdef CONFIG_NETWORK_SECMARK | ||
1140 | static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb, | ||
1141 | struct request_sock *req) | ||
1142 | { | ||
1143 | struct aa_sk_ctx *ctx = SK_CTX(sk); | ||
1144 | |||
1145 | if (!skb->secmark) | ||
1146 | return 0; | ||
1147 | |||
1148 | return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT, | ||
1149 | skb->secmark, sk); | ||
1150 | } | ||
1151 | #endif | ||
1152 | |||
1129 | static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | 1153 | static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { |
1130 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), | 1154 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), |
1131 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), | 1155 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), |
@@ -1177,12 +1201,17 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |||
1177 | LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt), | 1201 | LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt), |
1178 | LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt), | 1202 | LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt), |
1179 | LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown), | 1203 | LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown), |
1204 | #ifdef CONFIG_NETWORK_SECMARK | ||
1180 | LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb), | 1205 | LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb), |
1206 | #endif | ||
1181 | LSM_HOOK_INIT(socket_getpeersec_stream, | 1207 | LSM_HOOK_INIT(socket_getpeersec_stream, |
1182 | apparmor_socket_getpeersec_stream), | 1208 | apparmor_socket_getpeersec_stream), |
1183 | LSM_HOOK_INIT(socket_getpeersec_dgram, | 1209 | LSM_HOOK_INIT(socket_getpeersec_dgram, |
1184 | apparmor_socket_getpeersec_dgram), | 1210 | apparmor_socket_getpeersec_dgram), |
1185 | LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), | 1211 | LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), |
1212 | #ifdef CONFIG_NETWORK_SECMARK | ||
1213 | LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request), | ||
1214 | #endif | ||
1186 | 1215 | ||
1187 | LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), | 1216 | LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), |
1188 | LSM_HOOK_INIT(cred_free, apparmor_cred_free), | 1217 | LSM_HOOK_INIT(cred_free, apparmor_cred_free), |
@@ -1538,6 +1567,97 @@ static inline int apparmor_init_sysctl(void) | |||
1538 | } | 1567 | } |
1539 | #endif /* CONFIG_SYSCTL */ | 1568 | #endif /* CONFIG_SYSCTL */ |
1540 | 1569 | ||
1570 | #if defined(CONFIG_NETFILTER) && defined(CONFIG_NETWORK_SECMARK) | ||
1571 | static unsigned int apparmor_ip_postroute(void *priv, | ||
1572 | struct sk_buff *skb, | ||
1573 | const struct nf_hook_state *state) | ||
1574 | { | ||
1575 | struct aa_sk_ctx *ctx; | ||
1576 | struct sock *sk; | ||
1577 | |||
1578 | if (!skb->secmark) | ||
1579 | return NF_ACCEPT; | ||
1580 | |||
1581 | sk = skb_to_full_sk(skb); | ||
1582 | if (sk == NULL) | ||
1583 | return NF_ACCEPT; | ||
1584 | |||
1585 | ctx = SK_CTX(sk); | ||
1586 | if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND, | ||
1587 | skb->secmark, sk)) | ||
1588 | return NF_ACCEPT; | ||
1589 | |||
1590 | return NF_DROP_ERR(-ECONNREFUSED); | ||
1591 | |||
1592 | } | ||
1593 | |||
1594 | static unsigned int apparmor_ipv4_postroute(void *priv, | ||
1595 | struct sk_buff *skb, | ||
1596 | const struct nf_hook_state *state) | ||
1597 | { | ||
1598 | return apparmor_ip_postroute(priv, skb, state); | ||
1599 | } | ||
1600 | |||
1601 | static unsigned int apparmor_ipv6_postroute(void *priv, | ||
1602 | struct sk_buff *skb, | ||
1603 | const struct nf_hook_state *state) | ||
1604 | { | ||
1605 | return apparmor_ip_postroute(priv, skb, state); | ||
1606 | } | ||
1607 | |||
1608 | static const struct nf_hook_ops apparmor_nf_ops[] = { | ||
1609 | { | ||
1610 | .hook = apparmor_ipv4_postroute, | ||
1611 | .pf = NFPROTO_IPV4, | ||
1612 | .hooknum = NF_INET_POST_ROUTING, | ||
1613 | .priority = NF_IP_PRI_SELINUX_FIRST, | ||
1614 | }, | ||
1615 | #if IS_ENABLED(CONFIG_IPV6) | ||
1616 | { | ||
1617 | .hook = apparmor_ipv6_postroute, | ||
1618 | .pf = NFPROTO_IPV6, | ||
1619 | .hooknum = NF_INET_POST_ROUTING, | ||
1620 | .priority = NF_IP6_PRI_SELINUX_FIRST, | ||
1621 | }, | ||
1622 | #endif | ||
1623 | }; | ||
1624 | |||
1625 | static int __net_init apparmor_nf_register(struct net *net) | ||
1626 | { | ||
1627 | int ret; | ||
1628 | |||
1629 | ret = nf_register_net_hooks(net, apparmor_nf_ops, | ||
1630 | ARRAY_SIZE(apparmor_nf_ops)); | ||
1631 | return ret; | ||
1632 | } | ||
1633 | |||
1634 | static void __net_exit apparmor_nf_unregister(struct net *net) | ||
1635 | { | ||
1636 | nf_unregister_net_hooks(net, apparmor_nf_ops, | ||
1637 | ARRAY_SIZE(apparmor_nf_ops)); | ||
1638 | } | ||
1639 | |||
1640 | static struct pernet_operations apparmor_net_ops = { | ||
1641 | .init = apparmor_nf_register, | ||
1642 | .exit = apparmor_nf_unregister, | ||
1643 | }; | ||
1644 | |||
1645 | static int __init apparmor_nf_ip_init(void) | ||
1646 | { | ||
1647 | int err; | ||
1648 | |||
1649 | if (!apparmor_enabled) | ||
1650 | return 0; | ||
1651 | |||
1652 | err = register_pernet_subsys(&apparmor_net_ops); | ||
1653 | if (err) | ||
1654 | panic("Apparmor: register_pernet_subsys: error %d\n", err); | ||
1655 | |||
1656 | return 0; | ||
1657 | } | ||
1658 | __initcall(apparmor_nf_ip_init); | ||
1659 | #endif | ||
1660 | |||
1541 | static int __init apparmor_init(void) | 1661 | static int __init apparmor_init(void) |
1542 | { | 1662 | { |
1543 | int error; | 1663 | int error; |
diff --git a/security/apparmor/net.c b/security/apparmor/net.c index bb24cfa0a164..c07fde444792 100644 --- a/security/apparmor/net.c +++ b/security/apparmor/net.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include "include/label.h" | 18 | #include "include/label.h" |
19 | #include "include/net.h" | 19 | #include "include/net.h" |
20 | #include "include/policy.h" | 20 | #include "include/policy.h" |
21 | #include "include/secid.h" | ||
21 | 22 | ||
22 | #include "net_names.h" | 23 | #include "net_names.h" |
23 | 24 | ||
@@ -146,17 +147,20 @@ int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, | |||
146 | static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, | 147 | static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, |
147 | struct sock *sk) | 148 | struct sock *sk) |
148 | { | 149 | { |
149 | struct aa_profile *profile; | 150 | int error = 0; |
150 | DEFINE_AUDIT_SK(sa, op, sk); | ||
151 | 151 | ||
152 | AA_BUG(!label); | 152 | AA_BUG(!label); |
153 | AA_BUG(!sk); | 153 | AA_BUG(!sk); |
154 | 154 | ||
155 | if (unconfined(label)) | 155 | if (!unconfined(label)) { |
156 | return 0; | 156 | struct aa_profile *profile; |
157 | DEFINE_AUDIT_SK(sa, op, sk); | ||
157 | 158 | ||
158 | return fn_for_each_confined(label, profile, | 159 | error = fn_for_each_confined(label, profile, |
159 | aa_profile_af_sk_perm(profile, &sa, request, sk)); | 160 | aa_profile_af_sk_perm(profile, &sa, request, sk)); |
161 | } | ||
162 | |||
163 | return error; | ||
160 | } | 164 | } |
161 | 165 | ||
162 | int aa_sk_perm(const char *op, u32 request, struct sock *sk) | 166 | int aa_sk_perm(const char *op, u32 request, struct sock *sk) |
@@ -185,3 +189,70 @@ int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, | |||
185 | 189 | ||
186 | return aa_label_sk_perm(label, op, request, sock->sk); | 190 | return aa_label_sk_perm(label, op, request, sock->sk); |
187 | } | 191 | } |
192 | |||
193 | #ifdef CONFIG_NETWORK_SECMARK | ||
194 | static int apparmor_secmark_init(struct aa_secmark *secmark) | ||
195 | { | ||
196 | struct aa_label *label; | ||
197 | |||
198 | if (secmark->label[0] == '*') { | ||
199 | secmark->secid = AA_SECID_WILDCARD; | ||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | label = aa_label_strn_parse(&root_ns->unconfined->label, | ||
204 | secmark->label, strlen(secmark->label), | ||
205 | GFP_ATOMIC, false, false); | ||
206 | |||
207 | if (IS_ERR(label)) | ||
208 | return PTR_ERR(label); | ||
209 | |||
210 | secmark->secid = label->secid; | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, | ||
216 | struct common_audit_data *sa, struct sock *sk) | ||
217 | { | ||
218 | int i, ret; | ||
219 | struct aa_perms perms = { }; | ||
220 | |||
221 | if (profile->secmark_count == 0) | ||
222 | return 0; | ||
223 | |||
224 | for (i = 0; i < profile->secmark_count; i++) { | ||
225 | if (!profile->secmark[i].secid) { | ||
226 | ret = apparmor_secmark_init(&profile->secmark[i]); | ||
227 | if (ret) | ||
228 | return ret; | ||
229 | } | ||
230 | |||
231 | if (profile->secmark[i].secid == secid || | ||
232 | profile->secmark[i].secid == AA_SECID_WILDCARD) { | ||
233 | if (profile->secmark[i].deny) | ||
234 | perms.deny = ALL_PERMS_MASK; | ||
235 | else | ||
236 | perms.allow = ALL_PERMS_MASK; | ||
237 | |||
238 | if (profile->secmark[i].audit) | ||
239 | perms.audit = ALL_PERMS_MASK; | ||
240 | } | ||
241 | } | ||
242 | |||
243 | aa_apply_modes_to_perms(profile, &perms); | ||
244 | |||
245 | return aa_check_perms(profile, &perms, request, sa, audit_net_cb); | ||
246 | } | ||
247 | |||
248 | int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, | ||
249 | u32 secid, struct sock *sk) | ||
250 | { | ||
251 | struct aa_profile *profile; | ||
252 | DEFINE_AUDIT_SK(sa, op, sk); | ||
253 | |||
254 | return fn_for_each_confined(label, profile, | ||
255 | aa_secmark_perm(profile, request, secid, | ||
256 | &sa, sk)); | ||
257 | } | ||
258 | #endif | ||
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 1590e2de4e84..df9c5890a878 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c | |||
@@ -231,6 +231,9 @@ void aa_free_profile(struct aa_profile *profile) | |||
231 | for (i = 0; i < profile->xattr_count; i++) | 231 | for (i = 0; i < profile->xattr_count; i++) |
232 | kzfree(profile->xattrs[i]); | 232 | kzfree(profile->xattrs[i]); |
233 | kzfree(profile->xattrs); | 233 | kzfree(profile->xattrs); |
234 | for (i = 0; i < profile->secmark_count; i++) | ||
235 | kzfree(profile->secmark[i].label); | ||
236 | kzfree(profile->secmark); | ||
234 | kzfree(profile->dirname); | 237 | kzfree(profile->dirname); |
235 | aa_put_dfa(profile->xmatch); | 238 | aa_put_dfa(profile->xmatch); |
236 | aa_put_dfa(profile->policy.dfa); | 239 | aa_put_dfa(profile->policy.dfa); |
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 21cb384d712a..379682e2a8d5 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c | |||
@@ -292,6 +292,19 @@ fail: | |||
292 | return 0; | 292 | return 0; |
293 | } | 293 | } |
294 | 294 | ||
295 | static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name) | ||
296 | { | ||
297 | if (unpack_nameX(e, AA_U8, name)) { | ||
298 | if (!inbounds(e, sizeof(u8))) | ||
299 | return 0; | ||
300 | if (data) | ||
301 | *data = get_unaligned((u8 *)e->pos); | ||
302 | e->pos += sizeof(u8); | ||
303 | return 1; | ||
304 | } | ||
305 | return 0; | ||
306 | } | ||
307 | |||
295 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) | 308 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) |
296 | { | 309 | { |
297 | if (unpack_nameX(e, AA_U32, name)) { | 310 | if (unpack_nameX(e, AA_U32, name)) { |
@@ -529,6 +542,49 @@ fail: | |||
529 | return 0; | 542 | return 0; |
530 | } | 543 | } |
531 | 544 | ||
545 | static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile) | ||
546 | { | ||
547 | void *pos = e->pos; | ||
548 | int i, size; | ||
549 | |||
550 | if (unpack_nameX(e, AA_STRUCT, "secmark")) { | ||
551 | size = unpack_array(e, NULL); | ||
552 | |||
553 | profile->secmark = kcalloc(size, sizeof(struct aa_secmark), | ||
554 | GFP_KERNEL); | ||
555 | if (!profile->secmark) | ||
556 | goto fail; | ||
557 | |||
558 | profile->secmark_count = size; | ||
559 | |||
560 | for (i = 0; i < size; i++) { | ||
561 | if (!unpack_u8(e, &profile->secmark[i].audit, NULL)) | ||
562 | goto fail; | ||
563 | if (!unpack_u8(e, &profile->secmark[i].deny, NULL)) | ||
564 | goto fail; | ||
565 | if (!unpack_strdup(e, &profile->secmark[i].label, NULL)) | ||
566 | goto fail; | ||
567 | } | ||
568 | if (!unpack_nameX(e, AA_ARRAYEND, NULL)) | ||
569 | goto fail; | ||
570 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) | ||
571 | goto fail; | ||
572 | } | ||
573 | |||
574 | return 1; | ||
575 | |||
576 | fail: | ||
577 | if (profile->secmark) { | ||
578 | for (i = 0; i < size; i++) | ||
579 | kfree(profile->secmark[i].label); | ||
580 | kfree(profile->secmark); | ||
581 | profile->secmark_count = 0; | ||
582 | } | ||
583 | |||
584 | e->pos = pos; | ||
585 | return 0; | ||
586 | } | ||
587 | |||
532 | static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) | 588 | static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) |
533 | { | 589 | { |
534 | void *pos = e->pos; | 590 | void *pos = e->pos; |
@@ -727,6 +783,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e, char **ns_name) | |||
727 | goto fail; | 783 | goto fail; |
728 | } | 784 | } |
729 | 785 | ||
786 | if (!unpack_secmark(e, profile)) { | ||
787 | info = "failed to unpack profile secmark rules"; | ||
788 | goto fail; | ||
789 | } | ||
790 | |||
730 | if (unpack_nameX(e, AA_STRUCT, "policydb")) { | 791 | if (unpack_nameX(e, AA_STRUCT, "policydb")) { |
731 | /* generic policy dfa - optional and may be NULL */ | 792 | /* generic policy dfa - optional and may be NULL */ |
732 | info = "failed to unpack policydb"; | 793 | info = "failed to unpack policydb"; |
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c index 4ccec1bcf6f5..05373d9a3d6a 100644 --- a/security/apparmor/secid.c +++ b/security/apparmor/secid.c | |||
@@ -32,8 +32,7 @@ | |||
32 | * secids - do not pin labels with a refcount. They rely on the label | 32 | * secids - do not pin labels with a refcount. They rely on the label |
33 | * properly updating/freeing them | 33 | * properly updating/freeing them |
34 | */ | 34 | */ |
35 | 35 | #define AA_FIRST_SECID 2 | |
36 | #define AA_FIRST_SECID 1 | ||
37 | 36 | ||
38 | static DEFINE_IDR(aa_secids); | 37 | static DEFINE_IDR(aa_secids); |
39 | static DEFINE_SPINLOCK(secid_lock); | 38 | static DEFINE_SPINLOCK(secid_lock); |