diff options
| -rw-r--r-- | security/apparmor/lsm.c | 112 | ||||
| -rw-r--r-- | security/apparmor/net.c | 66 |
2 files changed, 177 insertions, 1 deletions
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f09fea0b4db7..2c842f24821b 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" |
| @@ -1030,7 +1032,13 @@ static int apparmor_socket_shutdown(struct socket *sock, int how) | |||
| 1030 | */ | 1032 | */ |
| 1031 | static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | 1033 | static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) |
| 1032 | { | 1034 | { |
| 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); | ||
| 1034 | } | 1042 | } |
| 1035 | 1043 | ||
| 1036 | 1044 | ||
| @@ -1126,6 +1134,18 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent) | |||
| 1126 | ctx->label = aa_get_current_label(); | 1134 | ctx->label = aa_get_current_label(); |
| 1127 | } | 1135 | } |
| 1128 | 1136 | ||
| 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 | |||
| 1129 | static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | 1149 | static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { |
| 1130 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), | 1150 | LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), |
| 1131 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), | 1151 | LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), |
| @@ -1183,6 +1203,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { | |||
| 1183 | LSM_HOOK_INIT(socket_getpeersec_dgram, | 1203 | LSM_HOOK_INIT(socket_getpeersec_dgram, |
| 1184 | apparmor_socket_getpeersec_dgram), | 1204 | apparmor_socket_getpeersec_dgram), |
| 1185 | LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), | 1205 | LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), |
| 1206 | LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request), | ||
| 1186 | 1207 | ||
| 1187 | LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), | 1208 | LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), |
| 1188 | LSM_HOOK_INIT(cred_free, apparmor_cred_free), | 1209 | LSM_HOOK_INIT(cred_free, apparmor_cred_free), |
| @@ -1538,6 +1559,95 @@ static inline int apparmor_init_sysctl(void) | |||
| 1538 | } | 1559 | } |
| 1539 | #endif /* CONFIG_SYSCTL */ | 1560 | #endif /* CONFIG_SYSCTL */ |
| 1540 | 1561 | ||
| 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 | |||
| 1541 | static int __init apparmor_init(void) | 1651 | static int __init apparmor_init(void) |
| 1542 | { | 1652 | { |
| 1543 | int error; | 1653 | int error; |
diff --git a/security/apparmor/net.c b/security/apparmor/net.c index d5d72dd1ca1f..f9a678ce994f 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 | ||
| @@ -188,3 +189,68 @@ int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, | |||
| 188 | 189 | ||
| 189 | return aa_label_sk_perm(label, op, request, sock->sk); | 190 | return aa_label_sk_perm(label, op, request, sock->sk); |
| 190 | } | 191 | } |
| 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-> | ||
