summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-11-02 13:04:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-11-02 13:04:26 -0400
commitd81f50bd34646d8373b989e55180c0fc9af94e0b (patch)
treea72b051a41717a7b8bacd7cf61965ff0e0dfa4ed /security
parentc2aa1a444cab2c673650ada80a7dffc4345ce2e6 (diff)
parent566f52ece7bd1099d20dfe2f6f0801896643cf8f (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.c2
-rw-r--r--security/apparmor/file.c2
-rw-r--r--security/apparmor/include/cred.h2
-rw-r--r--security/apparmor/include/net.h10
-rw-r--r--security/apparmor/include/policy.h3
-rw-r--r--security/apparmor/include/secid.h3
-rw-r--r--security/apparmor/lib.c6
-rw-r--r--security/apparmor/lsm.c130
-rw-r--r--security/apparmor/net.c83
-rw-r--r--security/apparmor/policy.c3
-rw-r--r--security/apparmor/policy_unpack.c61
-rw-r--r--security/apparmor/secid.c3
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
86struct aa_secmark {
87 u8 audit;
88 u8 deny;
89 u32 secid;
90 char *label;
91};
92
86extern struct aa_sfs_entry aa_sfs_entry_network[]; 93extern struct aa_sfs_entry aa_sfs_entry_network[];
87 94
88void audit_net_cb(struct audit_buffer *ab, void *va); 95void 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);
103int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, 110int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
104 struct socket *sock); 111 struct socket *sock);
105 112
113int 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
25struct aa_label *aa_secid_to_label(u32 secid); 28struct aa_label *aa_secid_to_label(u32 secid);
26int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); 29int apparmor_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
27int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); 30int 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 */
1031static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 1034static 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
1037static struct aa_label *sk_peer_label(struct sock *sk) 1047static 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
1140static 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
1129static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { 1153static 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)
1571static 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
1594static 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
1601static 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
1608static 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
1625static 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
1634static 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
1640static struct pernet_operations apparmor_net_ops = {
1641 .init = apparmor_nf_register,
1642 .exit = apparmor_nf_unregister,
1643};
1644
1645static 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
1541static int __init apparmor_init(void) 1661static 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,
146static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, 147static 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
162int aa_sk_perm(const char *op, u32 request, struct sock *sk) 166int 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
194static 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
215static 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
248int 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
295static 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
295static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) 308static 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
545static 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
576fail:
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
532static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) 588static 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
38static DEFINE_IDR(aa_secids); 37static DEFINE_IDR(aa_secids);
39static DEFINE_SPINLOCK(secid_lock); 38static DEFINE_SPINLOCK(secid_lock);