From patchwork Wed Sep 19 23:14:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Christian_G=C3=B6ttsche?= X-Patchwork-Id: 10606691 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2AB1115A6 for ; Wed, 19 Sep 2018 23:14:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 19D8C2CE2F for ; Wed, 19 Sep 2018 23:14:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0DD582CE37; Wed, 19 Sep 2018 23:14:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5D28B2CE2F for ; Wed, 19 Sep 2018 23:14:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1725790AbeITEyb (ORCPT ); Thu, 20 Sep 2018 00:54:31 -0400 Received: from mail-wm1-f67.google.com ([209.85.128.67]:56143 "EHLO mail-wm1-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725755AbeITEyb (ORCPT ); Thu, 20 Sep 2018 00:54:31 -0400 Received: by mail-wm1-f67.google.com with SMTP id f21-v6so7920509wmc.5; Wed, 19 Sep 2018 16:14:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=1ZkCy9BDjKtS+RtDTCXwFfQMhHVf0s2rtMCS0C9ZKTc=; b=qncYjeD8FZGbSTLhN78K/QFFXz4HevM01GxhpGYSUhR2u9pW67sqyxy7Cfpdiok6Ky zdw3DyypyOTahqSZMnjVdxTArc2lAnTgruQHOEawnJV3Fsw1AsHMoZUm4LtDx1vB75Ty Z7w1A3xpUelKiIRvxwHgSNz943hBqvSwRIEau2pfcjjr3FzhGffDVc0gQU0kl4/4DQT5 93jvyMCfzVzhYnG275twK0ubpRsK+k38uv5cxEB21dBye2LB1sm8dFxJPCRj+x+gJ3aD eaEaDGK89dKNlbRozymMu2fAPrMMZcHbd21PRfVPI2NuWqg5coHT1XcrQ+InTQTG12Fh hnTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=1ZkCy9BDjKtS+RtDTCXwFfQMhHVf0s2rtMCS0C9ZKTc=; b=I2OrHzlOA7TLzDG0Btx0UpgLpw+sp/9BaxJx0SIzSJvBb/B0v3w7+LQqUpEbUD3z0e A9ufNZz+/r7v7x429OXEdchDoDd1r4YfFsmZnVZzfQP6UK0bVShKsx+uwRZwOimdbV3Q YSfdd7J8yVJrqbZUrgGji2xv+4A95PzJ5g/Y/43Z45efuN4nGlv1nz5qdquqSBa4w9Lv ebZlrZdy6p+EgGAAuX0Oe8eb9LXd2bhmg6v4h1ml4BmfjAEArgrrazBSjOKdKn1kBjfC t+qEL1EYeUz2Q7q48wq+haUAC1y41JM88+2NnEsWSiwip4q5//w2xK7EtKpHFiOttfFm oNyA== X-Gm-Message-State: APzg51A0qO8FEMmn7h6vi8qqhHGUwBBEvr6cj/bmBat0tLmufKCY9z3U kYOfoliQ96NzVoS/dHpiG+94siLfnMk= X-Google-Smtp-Source: ANB0Vdbro5bVyKjET5N/MCDt94qhbNZ7xcQsiPvJcsaV507LRLMyDolYlgrRdIQw/HhA20rtaMoQQg== X-Received: by 2002:a1c:d98a:: with SMTP id q132-v6mr117391wmg.78.1537398855558; Wed, 19 Sep 2018 16:14:15 -0700 (PDT) Received: from desktopdebian.localdomain (x4dba2007.dyn.telefonica.de. [77.186.32.7]) by smtp.gmail.com with ESMTPSA id d12-v6sm23398624wru.36.2018.09.19.16.14.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Wed, 19 Sep 2018 16:14:15 -0700 (PDT) From: =?utf-8?q?Christian_G=C3=B6ttsche?= To: pablo@netfilter.org, kadlec@blackhole.kfki.hu, fw@strlen.de, davem@davemloft.net, netfilter-devel@vger.kernel.org, coreteam@netfilter.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, paul@paul-moore.com, sds@tycho.nsa.gov, eparis@parisplace.org, jmorris@namei.org, serge@hallyn.com, selinux@tycho.nsa.gov, linux-security-module@vger.kernel.org Subject: [PATCH] netfilter: nf_tables: add SECMARK support Date: Thu, 20 Sep 2018 01:14:02 +0200 Message-Id: <20180919231402.4482-1-cgzones@googlemail.com> X-Mailer: git-send-email 2.19.0 MIME-Version: 1.0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Add the ability to set the security context of packets within the nf_tables framework. Add a nft_object for holding security contexts in the kernel and manipulating packets on the wire. The contexts are kept as strings and are evaluated to security identifiers at runtime (packet arrival), so that the nft_objects do not need to be refreshed after security changes. The maximum security context length is set to 256. Based on v4.18.6 Signed-off-by: Christian Göttsche --- include/net/netfilter/nf_tables_core.h | 4 + include/uapi/linux/netfilter/nf_tables.h | 18 ++++- net/netfilter/nf_tables_core.c | 28 ++++++- net/netfilter/nft_meta.c | 95 ++++++++++++++++++++++++ 4 files changed, 140 insertions(+), 5 deletions(-) diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h index a0513450..0d1f3b96 100644 --- a/include/net/netfilter/nf_tables_core.h +++ b/include/net/netfilter/nf_tables_core.h @@ -16,6 +16,10 @@ extern struct nft_expr_type nft_meta_type; extern struct nft_expr_type nft_rt_type; extern struct nft_expr_type nft_exthdr_type; +#ifdef CONFIG_NETWORK_SECMARK +extern struct nft_object_type nft_secmark_obj_type; +#endif + int nf_tables_core_module_init(void); void nf_tables_core_module_exit(void); diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index 89438e68..f1527962 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h @@ -1169,6 +1169,21 @@ enum nft_quota_attributes { }; #define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1) +/** + * enum nft_secmark_attributes - nf_tables secmark object netlink attributes + * + * @NFTA_SECMARK_CTX: security context (NLA_STRING) + */ +enum nft_secmark_attributes { + NFTA_SECMARK_UNSPEC, + NFTA_SECMARK_CTX, + __NFTA_SECMARK_MAX, +}; +#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1) + +/* Max security context length */ +#define NFT_SECMARK_CTX_MAXLEN 256 + /** * enum nft_reject_types - nf_tables reject expression reject types * @@ -1398,7 +1413,8 @@ enum nft_ct_helper_attributes { #define NFT_OBJECT_CT_HELPER 3 #define NFT_OBJECT_LIMIT 4 #define NFT_OBJECT_CONNLIMIT 5 -#define __NFT_OBJECT_MAX 6 +#define NFT_OBJECT_SECMARK 6 +#define __NFT_OBJECT_MAX 7 #define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) /** diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index 8de912ca..d59ebba0 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -235,12 +235,24 @@ static struct nft_expr_type *nft_basic_types[] = { &nft_exthdr_type, }; +static struct nft_object_type *nft_basic_objects[] = { +#ifdef CONFIG_NETWORK_SECMARK + &nft_secmark_obj_type, +#endif +}; + int __init nf_tables_core_module_init(void) { - int err, i; + int err, i, j = 0; + + for (i = 0; i < ARRAY_SIZE(nft_basic_objects); i++) { + err = nft_register_obj(nft_basic_objects[i]); + if (err) + goto err; + } - for (i = 0; i < ARRAY_SIZE(nft_basic_types); i++) { - err = nft_register_expr(nft_basic_types[i]); + for (j = 0; j < ARRAY_SIZE(nft_basic_types); j++) { + err = nft_register_expr(nft_basic_types[j]); if (err) goto err; } @@ -248,8 +260,12 @@ int __init nf_tables_core_module_init(void) return 0; err: + while (j-- > 0) + nft_unregister_expr(nft_basic_types[j]); + while (i-- > 0) - nft_unregister_expr(nft_basic_types[i]); + nft_unregister_obj(nft_basic_objects[i]); + return err; } @@ -260,4 +276,8 @@ void nf_tables_core_module_exit(void) i = ARRAY_SIZE(nft_basic_types); while (i-- > 0) nft_unregister_expr(nft_basic_types[i]); + + i = ARRAY_SIZE(nft_basic_objects); + while (i-- > 0) + nft_unregister_obj(nft_basic_objects[i]); } diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 1105a23b..26b79a3c 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c @@ -540,3 +540,98 @@ struct nft_expr_type nft_meta_type __read_mostly = { .maxattr = NFTA_META_MAX, .owner = THIS_MODULE, }; + +#ifdef CONFIG_NETWORK_SECMARK + +struct nft_secmark { + char ctx[NFT_SECMARK_CTX_MAXLEN]; + int len; +}; + +static const struct nla_policy nft_secmark_policy[NFTA_SECMARK_MAX + 1] = { + [NFTA_SECMARK_CTX] = { .type = NLA_STRING, .len = NFT_SECMARK_CTX_MAXLEN }, +}; + + +static void nft_secmark_obj_eval(struct nft_object *obj, struct nft_regs *regs, const struct nft_pktinfo *pkt) +{ + const struct nft_secmark *priv = nft_obj_data(obj); + struct sk_buff *skb = pkt->skb; + int err; + u32 secid = 0; + + /* skip if packet has already a secmark */ + if (skb->secmark) + return; + + err = security_secctx_to_secid(priv->ctx, priv->len, &secid); + if (err) { + if (err == -EINVAL) + pr_notice_ratelimited("invalid security context \'%s\'\n", priv->ctx); + else + pr_notice_ratelimited("unable to convert security context \'%s\': %d\n", priv->ctx, -err); + return; + } + + if (!secid) { + pr_notice_ratelimited("unable to map security context \'%s\'\n", priv->ctx); + return; + } + + err = security_secmark_relabel_packet(secid); + if (err) { + pr_notice_ratelimited("unable to obtain relabeling permission: %d\n", -err); + return; + } + + skb->secmark = secid; +} + + +static int nft_secmark_obj_init(const struct nft_ctx *ctx, const struct nlattr * const tb[], struct nft_object *obj) +{ + struct nft_secmark *priv = nft_obj_data(obj); + + if (tb[NFTA_SECMARK_CTX] == NULL) + return -EINVAL; + + nla_strlcpy(priv->ctx, tb[NFTA_SECMARK_CTX], NFT_SECMARK_CTX_MAXLEN); + priv->len = strlen(priv->ctx); + + security_secmark_refcount_inc(); + + return 0; +} + +static int nft_secmark_obj_dump(struct sk_buff *skb, struct nft_object *obj, bool reset) +{ + const struct nft_secmark *priv = nft_obj_data(obj); + + if (nla_put_string(skb, NFTA_SECMARK_CTX, priv->ctx)) + return -1; + + return 0; +} + +static void nft_secmark_obj_destroy(const struct nft_ctx *ctx, struct nft_object *obj) +{ + security_secmark_refcount_dec(); +} + +static const struct nft_object_ops nft_secmark_obj_ops = { + .type = &nft_secmark_obj_type, + .size = sizeof(struct nft_secmark), + .init = nft_secmark_obj_init, + .eval = nft_secmark_obj_eval, + .dump = nft_secmark_obj_dump, + .destroy = nft_secmark_obj_destroy, +}; +struct nft_object_type nft_secmark_obj_type __read_mostly = { + .type = NFT_OBJECT_SECMARK, + .ops = &nft_secmark_obj_ops, + .maxattr = NFTA_SECMARK_MAX, + .policy = nft_secmark_policy, + .owner = THIS_MODULE, +}; + +#endif /* CONFIG_NETWORK_SECMARK */