Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

apparmor: Allow filtering based on secmark policy

Add support for dropping or accepting packets based on their secmark
tags.

Signed-off-by: Matthew Garrett <mjg59@google.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>

authored by

Matthew Garrett and committed by
John Johansen
ab9f2115 9caafbe2

+177 -1
+111 -1
security/apparmor/lsm.c
··· 23 23 #include <linux/sysctl.h> 24 24 #include <linux/audit.h> 25 25 #include <linux/user_namespace.h> 26 + #include <linux/netfilter_ipv4.h> 27 + #include <linux/netfilter_ipv6.h> 26 28 #include <net/sock.h> 27 29 28 30 #include "include/apparmor.h" ··· 1032 1030 */ 1033 1031 static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 1034 1032 { 1035 - return 0; 1033 + struct aa_sk_ctx *ctx = SK_CTX(sk); 1034 + 1035 + if (!skb->secmark) 1036 + return 0; 1037 + 1038 + return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE, 1039 + skb->secmark, sk); 1036 1040 } 1037 1041 1038 1042 ··· 1134 1126 ctx->label = aa_get_current_label(); 1135 1127 } 1136 1128 1129 + static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb, 1130 + struct request_sock *req) 1131 + { 1132 + struct aa_sk_ctx *ctx = SK_CTX(sk); 1133 + 1134 + if (!skb->secmark) 1135 + return 0; 1136 + 1137 + return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT, 1138 + skb->secmark, sk); 1139 + } 1140 + 1137 1141 static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { 1138 1142 LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), 1139 1143 LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), ··· 1203 1183 LSM_HOOK_INIT(socket_getpeersec_dgram, 1204 1184 apparmor_socket_getpeersec_dgram), 1205 1185 LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), 1186 + LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request), 1206 1187 1207 1188 LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), 1208 1189 LSM_HOOK_INIT(cred_free, apparmor_cred_free), ··· 1558 1537 return 0; 1559 1538 } 1560 1539 #endif /* CONFIG_SYSCTL */ 1540 + 1541 + static unsigned int apparmor_ip_postroute(void *priv, 1542 + struct sk_buff *skb, 1543 + const struct nf_hook_state *state) 1544 + { 1545 + struct aa_sk_ctx *ctx; 1546 + struct sock *sk; 1547 + 1548 + if (!skb->secmark) 1549 + return NF_ACCEPT; 1550 + 1551 + sk = skb_to_full_sk(skb); 1552 + if (sk == NULL) 1553 + return NF_ACCEPT; 1554 + 1555 + ctx = SK_CTX(sk); 1556 + if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND, 1557 + skb->secmark, sk)) 1558 + return NF_ACCEPT; 1559 + 1560 + return NF_DROP_ERR(-ECONNREFUSED); 1561 + 1562 + } 1563 + 1564 + static unsigned int apparmor_ipv4_postroute(void *priv, 1565 + struct sk_buff *skb, 1566 + const struct nf_hook_state *state) 1567 + { 1568 + return apparmor_ip_postroute(priv, skb, state); 1569 + } 1570 + 1571 + static unsigned int apparmor_ipv6_postroute(void *priv, 1572 + struct sk_buff *skb, 1573 + const struct nf_hook_state *state) 1574 + { 1575 + return apparmor_ip_postroute(priv, skb, state); 1576 + } 1577 + 1578 + static const struct nf_hook_ops apparmor_nf_ops[] = { 1579 + { 1580 + .hook = apparmor_ipv4_postroute, 1581 + .pf = NFPROTO_IPV4, 1582 + .hooknum = NF_INET_POST_ROUTING, 1583 + .priority = NF_IP_PRI_SELINUX_FIRST, 1584 + }, 1585 + #if IS_ENABLED(CONFIG_IPV6) 1586 + { 1587 + .hook = apparmor_ipv6_postroute, 1588 + .pf = NFPROTO_IPV6, 1589 + .hooknum = NF_INET_POST_ROUTING, 1590 + .priority = NF_IP6_PRI_SELINUX_FIRST, 1591 + }, 1592 + #endif 1593 + }; 1594 + 1595 + static int __net_init apparmor_nf_register(struct net *net) 1596 + { 1597 + int ret; 1598 + 1599 + ret = nf_register_net_hooks(net, apparmor_nf_ops, 1600 + ARRAY_SIZE(apparmor_nf_ops)); 1601 + return ret; 1602 + } 1603 + 1604 + static void __net_exit apparmor_nf_unregister(struct net *net) 1605 + { 1606 + nf_unregister_net_hooks(net, apparmor_nf_ops, 1607 + ARRAY_SIZE(apparmor_nf_ops)); 1608 + } 1609 + 1610 + static struct pernet_operations apparmor_net_ops = { 1611 + .init = apparmor_nf_register, 1612 + .exit = apparmor_nf_unregister, 1613 + }; 1614 + 1615 + static int __init apparmor_nf_ip_init(void) 1616 + { 1617 + int err; 1618 + 1619 + if (!apparmor_enabled) 1620 + return 0; 1621 + 1622 + err = register_pernet_subsys(&apparmor_net_ops); 1623 + if (err) 1624 + panic("Apparmor: register_pernet_subsys: error %d\n", err); 1625 + 1626 + return 0; 1627 + } 1628 + __initcall(apparmor_nf_ip_init); 1561 1629 1562 1630 static int __init apparmor_init(void) 1563 1631 {
+66
security/apparmor/net.c
··· 18 18 #include "include/label.h" 19 19 #include "include/net.h" 20 20 #include "include/policy.h" 21 + #include "include/secid.h" 21 22 22 23 #include "net_names.h" 23 24 ··· 188 187 AA_BUG(!sock->sk); 189 188 190 189 return aa_label_sk_perm(label, op, request, sock->sk); 190 + } 191 + 192 + static int apparmor_secmark_init(struct aa_secmark *secmark) 193 + { 194 + struct aa_label *label; 195 + 196 + if (secmark->label[0] == '*') { 197 + secmark->secid = AA_SECID_WILDCARD; 198 + return 0; 199 + } 200 + 201 + label = aa_label_strn_parse(&root_ns->unconfined->label, 202 + secmark->label, strlen(secmark->label), 203 + GFP_ATOMIC, false, false); 204 + 205 + if (IS_ERR(label)) 206 + return PTR_ERR(label); 207 + 208 + secmark->secid = label->secid; 209 + 210 + return 0; 211 + } 212 + 213 + static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, 214 + struct common_audit_data *sa, struct sock *sk) 215 + { 216 + int i, ret; 217 + struct aa_perms perms = { }; 218 + 219 + if (profile->secmark_count == 0) 220 + return 0; 221 + 222 + for (i = 0; i < profile->secmark_count; i++) { 223 + if (!profile->secmark[i].secid) { 224 + ret = apparmor_secmark_init(&profile->secmark[i]); 225 + if (ret) 226 + return ret; 227 + } 228 + 229 + if (profile->secmark[i].secid == secid || 230 + profile->secmark[i].secid == AA_SECID_WILDCARD) { 231 + if (profile->secmark[i].deny) 232 + perms.deny = ALL_PERMS_MASK; 233 + else 234 + perms.allow = ALL_PERMS_MASK; 235 + 236 + if (profile->secmark[i].audit) 237 + perms.audit = ALL_PERMS_MASK; 238 + } 239 + } 240 + 241 + aa_apply_modes_to_perms(profile, &perms); 242 + 243 + return aa_check_perms(profile, &perms, request, sa, audit_net_cb); 244 + } 245 + 246 + int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, 247 + u32 secid, struct sock *sk) 248 + { 249 + struct aa_profile *profile; 250 + DEFINE_AUDIT_SK(sa, op, sk); 251 + 252 + return fn_for_each_confined(label, profile, 253 + aa_secmark_perm(profile, request, secid, 254 + &sa, sk)); 191 255 }