cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nft_log.c (7676B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
      4 * Copyright (c) 2012-2014 Pablo Neira Ayuso <pablo@netfilter.org>
      5 *
      6 * Development of this code funded by Astaro AG (http://www.astaro.com/)
      7 */
      8
      9#include <linux/audit.h>
     10#include <linux/kernel.h>
     11#include <linux/init.h>
     12#include <linux/module.h>
     13#include <linux/netlink.h>
     14#include <linux/netfilter.h>
     15#include <linux/netfilter/nf_tables.h>
     16#include <net/ipv6.h>
     17#include <net/ip.h>
     18#include <net/netfilter/nf_tables.h>
     19#include <net/netfilter/nf_log.h>
     20#include <linux/netdevice.h>
     21
     22static const char *nft_log_null_prefix = "";
     23
     24struct nft_log {
     25	struct nf_loginfo	loginfo;
     26	char			*prefix;
     27};
     28
     29static bool audit_ip4(struct audit_buffer *ab, struct sk_buff *skb)
     30{
     31	struct iphdr _iph;
     32	const struct iphdr *ih;
     33
     34	ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_iph), &_iph);
     35	if (!ih)
     36		return false;
     37
     38	audit_log_format(ab, " saddr=%pI4 daddr=%pI4 proto=%hhu",
     39			 &ih->saddr, &ih->daddr, ih->protocol);
     40
     41	return true;
     42}
     43
     44static bool audit_ip6(struct audit_buffer *ab, struct sk_buff *skb)
     45{
     46	struct ipv6hdr _ip6h;
     47	const struct ipv6hdr *ih;
     48	u8 nexthdr;
     49	__be16 frag_off;
     50
     51	ih = skb_header_pointer(skb, skb_network_offset(skb), sizeof(_ip6h), &_ip6h);
     52	if (!ih)
     53		return false;
     54
     55	nexthdr = ih->nexthdr;
     56	ipv6_skip_exthdr(skb, skb_network_offset(skb) + sizeof(_ip6h), &nexthdr, &frag_off);
     57
     58	audit_log_format(ab, " saddr=%pI6c daddr=%pI6c proto=%hhu",
     59			 &ih->saddr, &ih->daddr, nexthdr);
     60
     61	return true;
     62}
     63
     64static void nft_log_eval_audit(const struct nft_pktinfo *pkt)
     65{
     66	struct sk_buff *skb = pkt->skb;
     67	struct audit_buffer *ab;
     68	int fam = -1;
     69
     70	if (!audit_enabled)
     71		return;
     72
     73	ab = audit_log_start(NULL, GFP_ATOMIC, AUDIT_NETFILTER_PKT);
     74	if (!ab)
     75		return;
     76
     77	audit_log_format(ab, "mark=%#x", skb->mark);
     78
     79	switch (nft_pf(pkt)) {
     80	case NFPROTO_BRIDGE:
     81		switch (eth_hdr(skb)->h_proto) {
     82		case htons(ETH_P_IP):
     83			fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1;
     84			break;
     85		case htons(ETH_P_IPV6):
     86			fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1;
     87			break;
     88		}
     89		break;
     90	case NFPROTO_IPV4:
     91		fam = audit_ip4(ab, skb) ? NFPROTO_IPV4 : -1;
     92		break;
     93	case NFPROTO_IPV6:
     94		fam = audit_ip6(ab, skb) ? NFPROTO_IPV6 : -1;
     95		break;
     96	}
     97
     98	if (fam == -1)
     99		audit_log_format(ab, " saddr=? daddr=? proto=-1");
    100
    101	audit_log_end(ab);
    102}
    103
    104static void nft_log_eval(const struct nft_expr *expr,
    105			 struct nft_regs *regs,
    106			 const struct nft_pktinfo *pkt)
    107{
    108	const struct nft_log *priv = nft_expr_priv(expr);
    109
    110	if (priv->loginfo.type == NF_LOG_TYPE_LOG &&
    111	    priv->loginfo.u.log.level == NFT_LOGLEVEL_AUDIT) {
    112		nft_log_eval_audit(pkt);
    113		return;
    114	}
    115
    116	nf_log_packet(nft_net(pkt), nft_pf(pkt), nft_hook(pkt), pkt->skb,
    117		      nft_in(pkt), nft_out(pkt), &priv->loginfo, "%s",
    118		      priv->prefix);
    119}
    120
    121static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
    122	[NFTA_LOG_GROUP]	= { .type = NLA_U16 },
    123	[NFTA_LOG_PREFIX]	= { .type = NLA_STRING,
    124				    .len = NF_LOG_PREFIXLEN - 1 },
    125	[NFTA_LOG_SNAPLEN]	= { .type = NLA_U32 },
    126	[NFTA_LOG_QTHRESHOLD]	= { .type = NLA_U16 },
    127	[NFTA_LOG_LEVEL]	= { .type = NLA_U32 },
    128	[NFTA_LOG_FLAGS]	= { .type = NLA_U32 },
    129};
    130
    131static int nft_log_modprobe(struct net *net, enum nf_log_type t)
    132{
    133	switch (t) {
    134	case NF_LOG_TYPE_LOG:
    135		return nft_request_module(net, "%s", "nf_log_syslog");
    136	case NF_LOG_TYPE_ULOG:
    137		return nft_request_module(net, "%s", "nfnetlink_log");
    138	case NF_LOG_TYPE_MAX:
    139		break;
    140	}
    141
    142	return -ENOENT;
    143}
    144
    145static int nft_log_init(const struct nft_ctx *ctx,
    146			const struct nft_expr *expr,
    147			const struct nlattr * const tb[])
    148{
    149	struct nft_log *priv = nft_expr_priv(expr);
    150	struct nf_loginfo *li = &priv->loginfo;
    151	const struct nlattr *nla;
    152	int err;
    153
    154	li->type = NF_LOG_TYPE_LOG;
    155	if (tb[NFTA_LOG_LEVEL] != NULL &&
    156	    tb[NFTA_LOG_GROUP] != NULL)
    157		return -EINVAL;
    158	if (tb[NFTA_LOG_GROUP] != NULL) {
    159		li->type = NF_LOG_TYPE_ULOG;
    160		if (tb[NFTA_LOG_FLAGS] != NULL)
    161			return -EINVAL;
    162	}
    163
    164	nla = tb[NFTA_LOG_PREFIX];
    165	if (nla != NULL) {
    166		priv->prefix = kmalloc(nla_len(nla) + 1, GFP_KERNEL);
    167		if (priv->prefix == NULL)
    168			return -ENOMEM;
    169		nla_strscpy(priv->prefix, nla, nla_len(nla) + 1);
    170	} else {
    171		priv->prefix = (char *)nft_log_null_prefix;
    172	}
    173
    174	switch (li->type) {
    175	case NF_LOG_TYPE_LOG:
    176		if (tb[NFTA_LOG_LEVEL] != NULL) {
    177			li->u.log.level =
    178				ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));
    179		} else {
    180			li->u.log.level = NFT_LOGLEVEL_WARNING;
    181		}
    182		if (li->u.log.level > NFT_LOGLEVEL_AUDIT) {
    183			err = -EINVAL;
    184			goto err1;
    185		}
    186
    187		if (tb[NFTA_LOG_FLAGS] != NULL) {
    188			li->u.log.logflags =
    189				ntohl(nla_get_be32(tb[NFTA_LOG_FLAGS]));
    190			if (li->u.log.logflags & ~NF_LOG_MASK) {
    191				err = -EINVAL;
    192				goto err1;
    193			}
    194		}
    195		break;
    196	case NF_LOG_TYPE_ULOG:
    197		li->u.ulog.group = ntohs(nla_get_be16(tb[NFTA_LOG_GROUP]));
    198		if (tb[NFTA_LOG_SNAPLEN] != NULL) {
    199			li->u.ulog.flags |= NF_LOG_F_COPY_LEN;
    200			li->u.ulog.copy_len =
    201				ntohl(nla_get_be32(tb[NFTA_LOG_SNAPLEN]));
    202		}
    203		if (tb[NFTA_LOG_QTHRESHOLD] != NULL) {
    204			li->u.ulog.qthreshold =
    205				ntohs(nla_get_be16(tb[NFTA_LOG_QTHRESHOLD]));
    206		}
    207		break;
    208	}
    209
    210	if (li->u.log.level == NFT_LOGLEVEL_AUDIT)
    211		return 0;
    212
    213	err = nf_logger_find_get(ctx->family, li->type);
    214	if (err < 0) {
    215		if (nft_log_modprobe(ctx->net, li->type) == -EAGAIN)
    216			err = -EAGAIN;
    217
    218		goto err1;
    219	}
    220
    221	return 0;
    222
    223err1:
    224	if (priv->prefix != nft_log_null_prefix)
    225		kfree(priv->prefix);
    226	return err;
    227}
    228
    229static void nft_log_destroy(const struct nft_ctx *ctx,
    230			    const struct nft_expr *expr)
    231{
    232	struct nft_log *priv = nft_expr_priv(expr);
    233	struct nf_loginfo *li = &priv->loginfo;
    234
    235	if (priv->prefix != nft_log_null_prefix)
    236		kfree(priv->prefix);
    237
    238	if (li->u.log.level == NFT_LOGLEVEL_AUDIT)
    239		return;
    240
    241	nf_logger_put(ctx->family, li->type);
    242}
    243
    244static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr)
    245{
    246	const struct nft_log *priv = nft_expr_priv(expr);
    247	const struct nf_loginfo *li = &priv->loginfo;
    248
    249	if (priv->prefix != nft_log_null_prefix)
    250		if (nla_put_string(skb, NFTA_LOG_PREFIX, priv->prefix))
    251			goto nla_put_failure;
    252	switch (li->type) {
    253	case NF_LOG_TYPE_LOG:
    254		if (nla_put_be32(skb, NFTA_LOG_LEVEL, htonl(li->u.log.level)))
    255			goto nla_put_failure;
    256
    257		if (li->u.log.logflags) {
    258			if (nla_put_be32(skb, NFTA_LOG_FLAGS,
    259					 htonl(li->u.log.logflags)))
    260				goto nla_put_failure;
    261		}
    262		break;
    263	case NF_LOG_TYPE_ULOG:
    264		if (nla_put_be16(skb, NFTA_LOG_GROUP, htons(li->u.ulog.group)))
    265			goto nla_put_failure;
    266
    267		if (li->u.ulog.flags & NF_LOG_F_COPY_LEN) {
    268			if (nla_put_be32(skb, NFTA_LOG_SNAPLEN,
    269					 htonl(li->u.ulog.copy_len)))
    270				goto nla_put_failure;
    271		}
    272		if (li->u.ulog.qthreshold) {
    273			if (nla_put_be16(skb, NFTA_LOG_QTHRESHOLD,
    274					 htons(li->u.ulog.qthreshold)))
    275				goto nla_put_failure;
    276		}
    277		break;
    278	}
    279	return 0;
    280
    281nla_put_failure:
    282	return -1;
    283}
    284
    285static struct nft_expr_type nft_log_type;
    286static const struct nft_expr_ops nft_log_ops = {
    287	.type		= &nft_log_type,
    288	.size		= NFT_EXPR_SIZE(sizeof(struct nft_log)),
    289	.eval		= nft_log_eval,
    290	.init		= nft_log_init,
    291	.destroy	= nft_log_destroy,
    292	.dump		= nft_log_dump,
    293	.reduce		= NFT_REDUCE_READONLY,
    294};
    295
    296static struct nft_expr_type nft_log_type __read_mostly = {
    297	.name		= "log",
    298	.ops		= &nft_log_ops,
    299	.policy		= nft_log_policy,
    300	.maxattr	= NFTA_LOG_MAX,
    301	.owner		= THIS_MODULE,
    302};
    303
    304static int __init nft_log_module_init(void)
    305{
    306	return nft_register_expr(&nft_log_type);
    307}
    308
    309static void __exit nft_log_module_exit(void)
    310{
    311	nft_unregister_expr(&nft_log_type);
    312}
    313
    314module_init(nft_log_module_init);
    315module_exit(nft_log_module_exit);
    316
    317MODULE_LICENSE("GPL");
    318MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
    319MODULE_ALIAS_NFT_EXPR("log");
    320MODULE_DESCRIPTION("Netfilter nf_tables log module");