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

Signed-off-by: Matthew Garrett <[email protected]>
---
 security/apparmor/include/net.h |   3 +
 security/apparmor/lsm.c         | 112 +++++++++++++++++++++++++++++++-
 security/apparmor/net.c         |  59 +++++++++++++++++
 3 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
index 31f45fed1541..f53b887861ba 100644
--- a/security/apparmor/include/net.h
+++ b/security/apparmor/include/net.h
@@ -110,4 +110,7 @@ int aa_sk_perm(const char *op, u32 request, struct sock 
*sk);
 int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
                      struct socket *sock);
 
+int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
+                          u32 secid, struct sock *sk);
+
 #endif /* __AA_NET_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index dab5409f2608..a366b501fb6a 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -23,6 +23,8 @@
 #include <linux/sysctl.h>
 #include <linux/audit.h>
 #include <linux/user_namespace.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/netfilter_ipv6.h>
 #include <net/sock.h>
 
 #include "include/apparmor.h"
@@ -1029,7 +1031,13 @@ static int apparmor_socket_shutdown(struct socket *sock, 
int how)
  */
 static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
 {
-       return 0;
+       struct aa_sk_ctx *ctx = SK_CTX(sk);
+
+       if (!skb->secmark)
+               return 0;
+
+       return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE,
+                                     skb->secmark, sk);
 }
 
 
@@ -1125,6 +1133,18 @@ static void apparmor_sock_graft(struct sock *sk, struct 
socket *parent)
                ctx->label = aa_get_current_label();
 }
 
+static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+                                     struct request_sock *req)
+{
+       struct aa_sk_ctx *ctx = SK_CTX(sk);
+
+       if (!skb->secmark)
+               return 0;
+
+       return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT,
+                                     skb->secmark, sk);
+}
+
 static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
        LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
        LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
@@ -1182,6 +1202,7 @@ static struct security_hook_list apparmor_hooks[] 
__lsm_ro_after_init = {
        LSM_HOOK_INIT(socket_getpeersec_dgram,
                      apparmor_socket_getpeersec_dgram),
        LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
+       LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request),
 
        LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
        LSM_HOOK_INIT(cred_free, apparmor_cred_free),
@@ -1536,6 +1557,95 @@ static inline int apparmor_init_sysctl(void)
 }
 #endif /* CONFIG_SYSCTL */
 
+static unsigned int apparmor_ip_postroute(void *priv,
+                                         struct sk_buff *skb,
+                                         const struct nf_hook_state *state)
+{
+       struct aa_sk_ctx *ctx;
+       struct sock *sk;
+
+       if (!skb->secmark)
+               return NF_ACCEPT;
+
+       sk = skb_to_full_sk(skb);
+       if (sk == NULL)
+               return NF_ACCEPT;
+
+       ctx = SK_CTX(sk);
+       if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND,
+                                   skb->secmark, sk))
+               return NF_ACCEPT;
+
+       return NF_DROP_ERR(-ECONNREFUSED);
+
+}
+
+static unsigned int apparmor_ipv4_postroute(void *priv,
+                                           struct sk_buff *skb,
+                                           const struct nf_hook_state *state)
+{
+       return apparmor_ip_postroute(priv, skb, state);
+}
+
+static unsigned int apparmor_ipv6_postroute(void *priv,
+                                           struct sk_buff *skb,
+                                           const struct nf_hook_state *state)
+{
+       return apparmor_ip_postroute(priv, skb, state);
+}
+
+static const struct nf_hook_ops apparmor_nf_ops[] = {
+       {
+               .hook =         apparmor_ipv4_postroute,
+               .pf =           NFPROTO_IPV4,
+               .hooknum =      NF_INET_POST_ROUTING,
+               .priority =     NF_IP_PRI_SELINUX_FIRST,
+       },
+#if IS_ENABLED(CONFIG_IPV6)
+       {
+               .hook =         apparmor_ipv6_postroute,
+               .pf =           NFPROTO_IPV6,
+               .hooknum =      NF_INET_POST_ROUTING,
+               .priority =     NF_IP6_PRI_SELINUX_FIRST,
+       },
+#endif
+};
+
+static int __net_init apparmor_nf_register(struct net *net)
+{
+       int ret;
+
+       ret = nf_register_net_hooks(net, apparmor_nf_ops,
+                                   ARRAY_SIZE(apparmor_nf_ops));
+       return ret;
+}
+
+static void __net_exit apparmor_nf_unregister(struct net *net)
+{
+       nf_unregister_net_hooks(net, apparmor_nf_ops,
+                               ARRAY_SIZE(apparmor_nf_ops));
+}
+
+static struct pernet_operations apparmor_net_ops = {
+       .init = apparmor_nf_register,
+       .exit = apparmor_nf_unregister,
+};
+
+static int __init apparmor_nf_ip_init(void)
+{
+       int err;
+
+       if (!apparmor_enabled)
+               return 0;
+
+       err = register_pernet_subsys(&apparmor_net_ops);
+       if (err)
+               panic("Apparmor: register_pernet_subsys: error %d\n", err);
+
+       return 0;
+}
+__initcall(apparmor_nf_ip_init);
+
 static int __init apparmor_init(void)
 {
        int error;
diff --git a/security/apparmor/net.c b/security/apparmor/net.c
index bb24cfa0a164..e94971ba84d0 100644
--- a/security/apparmor/net.c
+++ b/security/apparmor/net.c
@@ -185,3 +185,62 @@ int aa_sock_file_perm(struct aa_label *label, const char 
*op, u32 request,
 
        return aa_label_sk_perm(label, op, request, sock->sk);
 }
+
+static int apparmor_secmark_init(struct aa_secmark *secmark)
+{
+       struct aa_label *label;
+
+       label = aa_label_strn_parse(&root_ns->unconfined->label,
+                                   secmark->label, strlen(secmark->label),
+                                   GFP_ATOMIC, false, false);
+
+       if (IS_ERR(label))
+               return PTR_ERR(label);
+
+       secmark->secid = label->secid;
+
+       return 0;
+}
+
+static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
+                          struct common_audit_data *sa, struct sock *sk)
+{
+       int i, ret;
+       struct aa_perms perms = { };
+
+       if (profile->secmark_count == 0)
+               return 0;
+
+       for (i = 0; i < profile->secmark_count; i++) {
+               if (!profile->secmark[i].secid) {
+                       ret = apparmor_secmark_init(&profile->secmark[i]);
+                       if (ret)
+                               return ret;
+               }
+
+               if (profile->secmark[i].secid == secid) {
+                       if (profile->secmark[i].deny)
+                               perms.deny = ALL_PERMS_MASK;
+                       else
+                               perms.allow = ALL_PERMS_MASK;
+
+                       if (profile->secmark[i].audit)
+                               perms.audit = ALL_PERMS_MASK;
+               }
+       }
+
+       aa_apply_modes_to_perms(profile, &perms);
+
+       return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
+}
+
+int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
+                          u32 secid, struct sock *sk)
+{
+       struct aa_profile *profile;
+       DEFINE_AUDIT_SK(sa, op, sk);
+
+       return fn_for_each_confined(label, profile,
+                                   aa_secmark_perm(profile, request, secid,
+                                                   &sa, sk));
+}
-- 
2.17.0.441.gb46fe60e1d-goog


-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to