Skip to content

Commit ab9f211

Browse files
mjg59jrjohansen
authored andcommitted
apparmor: Allow filtering based on secmark policy
Add support for dropping or accepting packets based on their secmark tags. Signed-off-by: Matthew Garrett <[email protected]> Signed-off-by: John Johansen <[email protected]>
1 parent 9caafbe commit ab9f211

File tree

2 files changed

+177
-1
lines changed

2 files changed

+177
-1
lines changed

security/apparmor/lsm.c

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <linux/sysctl.h>
2424
#include <linux/audit.h>
2525
#include <linux/user_namespace.h>
26+
#include <linux/netfilter_ipv4.h>
27+
#include <linux/netfilter_ipv6.h>
2628
#include <net/sock.h>
2729

2830
#include "include/apparmor.h"
@@ -1030,7 +1032,13 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
10301032
*/
10311033
static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
10321034
{
1033-
return 0;
1035+
struct aa_sk_ctx *ctx = SK_CTX(sk);
1036+
1037+
if (!skb->secmark)
1038+
return 0;
1039+
1040+
return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE,
1041+
skb->secmark, sk);
10341042
}
10351043

10361044

@@ -1126,6 +1134,18 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
11261134
ctx->label = aa_get_current_label();
11271135
}
11281136

1137+
static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
1138+
struct request_sock *req)
1139+
{
1140+
struct aa_sk_ctx *ctx = SK_CTX(sk);
1141+
1142+
if (!skb->secmark)
1143+
return 0;
1144+
1145+
return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT,
1146+
skb->secmark, sk);
1147+
}
1148+
11291149
static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
11301150
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
11311151
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -1183,6 +1203,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
11831203
LSM_HOOK_INIT(socket_getpeersec_dgram,
11841204
apparmor_socket_getpeersec_dgram),
11851205
LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
1206+
LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request),
11861207

11871208
LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
11881209
LSM_HOOK_INIT(cred_free, apparmor_cred_free),
@@ -1538,6 +1559,95 @@ static inline int apparmor_init_sysctl(void)
15381559
}
15391560
#endif /* CONFIG_SYSCTL */
15401561

1562+
static unsigned int apparmor_ip_postroute(void *priv,
1563+
struct sk_buff *skb,
1564+
const struct nf_hook_state *state)
1565+
{
1566+
struct aa_sk_ctx *ctx;
1567+
struct sock *sk;
1568+
1569+
if (!skb->secmark)
1570+
return NF_ACCEPT;
1571+
1572+
sk = skb_to_full_sk(skb);
1573+
if (sk == NULL)
1574+
return NF_ACCEPT;
1575+
1576+
ctx = SK_CTX(sk);
1577+
if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND,
1578+
skb->secmark, sk))
1579+
return NF_ACCEPT;
1580+
1581+
return NF_DROP_ERR(-ECONNREFUSED);
1582+
1583+
}
1584+
1585+
static unsigned int apparmor_ipv4_postroute(void *priv,
1586+
struct sk_buff *skb,
1587+
const struct nf_hook_state *state)
1588+
{
1589+
return apparmor_ip_postroute(priv, skb, state);
1590+
}
1591+
1592+
static unsigned int apparmor_ipv6_postroute(void *priv,
1593+
struct sk_buff *skb,
1594+
const struct nf_hook_state *state)
1595+
{
1596+
return apparmor_ip_postroute(priv, skb, state);
1597+
}
1598+
1599+
static const struct nf_hook_ops apparmor_nf_ops[] = {
1600+
{
1601+
.hook = apparmor_ipv4_postroute,
1602+
.pf = NFPROTO_IPV4,
1603+
.hooknum = NF_INET_POST_ROUTING,
1604+
.priority = NF_IP_PRI_SELINUX_FIRST,
1605+
},
1606+
#if IS_ENABLED(CONFIG_IPV6)
1607+
{
1608+
.hook = apparmor_ipv6_postroute,
1609+
.pf = NFPROTO_IPV6,
1610+
.hooknum = NF_INET_POST_ROUTING,
1611+
.priority = NF_IP6_PRI_SELINUX_FIRST,
1612+
},
1613+
#endif
1614+
};
1615+
1616+
static int __net_init apparmor_nf_register(struct net *net)
1617+
{
1618+
int ret;
1619+
1620+
ret = nf_register_net_hooks(net, apparmor_nf_ops,
1621+
ARRAY_SIZE(apparmor_nf_ops));
1622+
return ret;
1623+
}
1624+
1625+
static void __net_exit apparmor_nf_unregister(struct net *net)
1626+
{
1627+
nf_unregister_net_hooks(net, apparmor_nf_ops,
1628+
ARRAY_SIZE(apparmor_nf_ops));
1629+
}
1630+
1631+
static struct pernet_operations apparmor_net_ops = {
1632+
.init = apparmor_nf_register,
1633+
.exit = apparmor_nf_unregister,
1634+
};
1635+
1636+
static int __init apparmor_nf_ip_init(void)
1637+
{
1638+
int err;
1639+
1640+
if (!apparmor_enabled)
1641+
return 0;
1642+
1643+
err = register_pernet_subsys(&apparmor_net_ops);
1644+
if (err)
1645+
panic("Apparmor: register_pernet_subsys: error %d\n", err);
1646+
1647+
return 0;
1648+
}
1649+
__initcall(apparmor_nf_ip_init);
1650+
15411651
static int __init apparmor_init(void)
15421652
{
15431653
int error;

security/apparmor/net.c

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "include/label.h"
1919
#include "include/net.h"
2020
#include "include/policy.h"
21+
#include "include/secid.h"
2122

2223
#include "net_names.h"
2324

@@ -188,3 +189,68 @@ int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
188189

189190
return aa_label_sk_perm(label, op, request, sock->sk);
190191
}
192+
193+
static int apparmor_secmark_init(struct aa_secmark *secmark)
194+
{
195+
struct aa_label *label;
196+
197+
if (secmark->label[0] == '*') {
198+
secmark->secid = AA_SECID_WILDCARD;
199+
return 0;
200+
}
201+
202+
label = aa_label_strn_parse(&root_ns->unconfined->label,
203+
secmark->label, strlen(secmark->label),
204+
GFP_ATOMIC, false, false);
205+
206+
if (IS_ERR(label))
207+
return PTR_ERR(label);
208+
209+
secmark->secid = label->secid;
210+
211+
return 0;
212+
}
213+
214+
static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
215+
struct common_audit_data *sa, struct sock *sk)
216+
{
217+
int i, ret;
218+
struct aa_perms perms = { };
219+
220+
if (profile->secmark_count == 0)
221+
return 0;
222+
223+
for (i = 0; i < profile->secmark_count; i++) {
224+
if (!profile->secmark[i].secid) {
225+
ret = apparmor_secmark_init(&profile->secmark[i]);
226+
if (ret)
227+
return ret;
228+
}
229+
230+
if (profile->secmark[i].secid == secid ||
231+
profile->secmark[i].secid == AA_SECID_WILDCARD) {
232+
if (profile->secmark[i].deny)
233+
perms.deny = ALL_PERMS_MASK;
234+
else
235+
perms.allow = ALL_PERMS_MASK;
236+
237+
if (profile->secmark[i].audit)
238+
perms.audit = ALL_PERMS_MASK;
239+
}
240+
}
241+
242+
aa_apply_modes_to_perms(profile, &perms);
243+
244+
return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
245+
}
246+
247+
int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
248+
u32 secid, struct sock *sk)
249+
{
250+
struct aa_profile *profile;
251+
DEFINE_AUDIT_SK(sa, op, sk);
252+
253+
return fn_for_each_confined(label, profile,
254+
aa_secmark_perm(profile, request, secid,
255+
&sa, sk));
256+
}

0 commit comments

Comments
 (0)