cregit-Linux how code gets into the kernel

Release 4.8 net/netfilter/nft_compat.c

Directory: net/netfilter
/*
 * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This software has been sponsored by Sophos Astaro <http://www.sophos.com>
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nf_tables_compat.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_arp/arp_tables.h>
#include <net/netfilter/nf_tables.h>


struct nft_xt {
	
struct list_head	head;
	
struct nft_expr_ops	ops;
	
unsigned int		refcnt;
};


static void nft_xt_put(struct nft_xt *xt) { if (--xt->refcnt == 0) { list_del(&xt->head); kfree(xt); } }

Contributors

PersonTokensPropCommitsCommitProp
liping zhangliping zhang35100.00%1100.00%
Total35100.00%1100.00%


static int nft_compat_chain_validate_dependency(const char *tablename, const struct nft_chain *chain) { const struct nft_base_chain *basechain; if (!tablename || !(chain->flags & NFT_BASE_CHAIN)) return 0; basechain = nft_base_chain(chain); if (strcmp(tablename, "nat") == 0 && basechain->type->type != NFT_CHAIN_T_NAT) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso73100.00%2100.00%
Total73100.00%2100.00%

union nft_entry { struct ipt_entry e4; struct ip6t_entry e6; struct ebt_entry ebt; struct arpt_entry arp; };
static inline void nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info) { par->target = xt; par->targinfo = xt_info; par->hotdrop = false; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso39100.00%1100.00%
Total39100.00%1100.00%


static void nft_target_eval_xt(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { void *info = nft_expr_priv(expr); struct xt_target *target = expr->ops->data; struct sk_buff *skb = pkt->skb; int ret; nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info); ret = target->target(skb, &pkt->xt); if (pkt->xt.hotdrop) ret = NF_DROP; switch (ret) { case XT_CONTINUE: regs->verdict.code = NFT_CONTINUE; break; default: regs->verdict.code = ret; break; } }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso11389.68%133.33%
patrick mchardypatrick mchardy118.73%133.33%
arturo borrero gonzalezarturo borrero gonzalez21.59%133.33%
Total126100.00%3100.00%


static void nft_target_eval_bridge(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { void *info = nft_expr_priv(expr); struct xt_target *target = expr->ops->data; struct sk_buff *skb = pkt->skb; int ret; nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info); ret = target->target(skb, &pkt->xt); if (pkt->xt.hotdrop) ret = NF_DROP; switch (ret) { case EBT_ACCEPT: regs->verdict.code = NF_ACCEPT; break; case EBT_DROP: regs->verdict.code = NF_DROP; break; case EBT_CONTINUE: regs->verdict.code = NFT_CONTINUE; break; case EBT_RETURN: regs->verdict.code = NFT_RETURN; break; default: regs->verdict.code = ret; break; } }

Contributors

PersonTokensPropCommitsCommitProp
arturo borrero gonzalezarturo borrero gonzalez13885.19%133.33%
patrick mchardypatrick mchardy2314.20%133.33%
pablo neira ayusopablo neira ayuso10.62%133.33%
Total162100.00%3100.00%

static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { [NFTA_TARGET_NAME] = { .type = NLA_NUL_STRING }, [NFTA_TARGET_REV] = { .type = NLA_U32 }, [NFTA_TARGET_INFO] = { .type = NLA_BINARY }, };
static void nft_target_set_tgchk_param(struct xt_tgchk_param *par, const struct nft_ctx *ctx, struct xt_target *target, void *info, union nft_entry *entry, u16 proto, bool inv) { par->net = ctx->net; par->table = ctx->table->name; switch (ctx->afi->family) { case AF_INET: entry->e4.ip.proto = proto; entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0; break; case AF_INET6: if (proto) entry->e6.ipv6.flags |= IP6T_F_PROTO; entry->e6.ipv6.proto = proto; entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; break; case NFPROTO_BRIDGE: entry->ebt.ethproto = (__force __be16)proto; entry->ebt.invflags = inv ? EBT_IPROTO : 0; break; case NFPROTO_ARP: break; } par->entryinfo = entry; par->target = target; par->targinfo = info; if (ctx->chain->flags & NFT_BASE_CHAIN) { const struct nft_base_chain *basechain = nft_base_chain(ctx->chain); const struct nf_hook_ops *ops = &basechain->ops[0]; par->hook_mask = 1 << ops->hooknum; } else { par->hook_mask = 0; } par->family = ctx->afi->family; par->nft_compat = true; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso22386.10%555.56%
arturo borrero gonzalezarturo borrero gonzalez3312.74%333.33%
patrick mchardypatrick mchardy31.16%111.11%
Total259100.00%9100.00%


static void target_compat_from_user(struct xt_target *t, void *in, void *out) { int pad; memcpy(out, in, t->targetsize); pad = XT_ALIGN(t->targetsize) - t->targetsize; if (pad > 0) memset(out + t->targetsize, 0, pad); }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso65100.00%2100.00%
Total65100.00%2100.00%

static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] = { [NFTA_RULE_COMPAT_PROTO] = { .type = NLA_U32 }, [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 }, };
static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv) { struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1]; u32 flags; int err; err = nla_parse_nested(tb, NFTA_RULE_COMPAT_MAX, attr, nft_rule_compat_policy); if (err < 0) return err; if (!tb[NFTA_RULE_COMPAT_PROTO] || !tb[NFTA_RULE_COMPAT_FLAGS]) return -EINVAL; flags = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_FLAGS])); if (flags & ~NFT_RULE_COMPAT_F_MASK) return -EINVAL; if (flags & NFT_RULE_COMPAT_F_INV) *inv = true; *proto = ntohl(nla_get_be32(tb[NFTA_RULE_COMPAT_PROTO])); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso12799.22%266.67%
arturo borrero gonzalezarturo borrero gonzalez10.78%133.33%
Total128100.00%3100.00%


static int nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { void *info = nft_expr_priv(expr); struct xt_target *target = expr->ops->data; struct xt_tgchk_param par; size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO])); u16 proto = 0; bool inv = false; union nft_entry e = {}; int ret; ret = nft_compat_chain_validate_dependency(target->table, ctx->chain); if (ret < 0) goto err; target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); if (ctx->nla[NFTA_RULE_COMPAT]) { ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); if (ret < 0) goto err; } nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv); ret = xt_check_target(&par, size, proto, inv); if (ret < 0) goto err; /* The standard target cannot be used */ if (target->target == NULL) { ret = -EINVAL; goto err; } return 0; err: module_put(target->me); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso23399.57%375.00%
arturo borrero gonzalezarturo borrero gonzalez10.43%125.00%
Total234100.00%4100.00%


static void nft_target_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct xt_target *target = expr->ops->data; void *info = nft_expr_priv(expr); struct xt_tgdtor_param par; par.net = ctx->net; par.target = target; par.targinfo = info; par.family = ctx->afi->family; if (par.target->destroy != NULL) par.target->destroy(&par); nft_xt_put(container_of(expr->ops, struct nft_xt, ops)); module_put(target->me); }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso9381.58%250.00%
liping zhangliping zhang1513.16%125.00%
patrick mchardypatrick mchardy65.26%125.00%
Total114100.00%4100.00%


static int nft_target_dump(struct sk_buff *skb, const struct nft_expr *expr) { const struct xt_target *target = expr->ops->data; void *info = nft_expr_priv(expr); if (nla_put_string(skb, NFTA_TARGET_NAME, target->name) || nla_put_be32(skb, NFTA_TARGET_REV, htonl(target->revision)) || nla_put(skb, NFTA_TARGET_INFO, XT_ALIGN(target->targetsize), info)) goto nla_put_failure; return 0; nla_put_failure: return -1; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso93100.00%2100.00%
Total93100.00%2100.00%


static int nft_target_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nft_data **data) { struct xt_target *target = expr->ops->data; unsigned int hook_mask = 0; int ret; if (ctx->chain->flags & NFT_BASE_CHAIN) { const struct nft_base_chain *basechain = nft_base_chain(ctx->chain); const struct nf_hook_ops *ops = &basechain->ops[0]; hook_mask = 1 << ops->hooknum; if (!(hook_mask & target->hooks)) return -EINVAL; ret = nft_compat_chain_validate_dependency(target->table, ctx->chain); if (ret < 0) return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso12997.73%266.67%
patrick mchardypatrick mchardy32.27%133.33%
Total132100.00%3100.00%


static void nft_match_eval(const struct nft_expr *expr, struct nft_regs *regs, const struct nft_pktinfo *pkt) { void *info = nft_expr_priv(expr); struct xt_match *match = expr->ops->data; struct sk_buff *skb = pkt->skb; bool ret; nft_compat_set_par((struct xt_action_param *)&pkt->xt, match, info); ret = match->match(skb, (struct xt_action_param *)&pkt->xt); if (pkt->xt.hotdrop) { regs->verdict.code = NF_DROP; return; } switch (ret ? 1 : 0) { case 1: regs->verdict.code = NFT_CONTINUE; break; case 0: regs->verdict.code = NFT_BREAK; break; } }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso12385.42%133.33%
patrick mchardypatrick mchardy1510.42%133.33%
david s. millerdavid s. miller64.17%133.33%
Total144100.00%3100.00%

static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { [NFTA_MATCH_NAME] = { .type = NLA_NUL_STRING }, [NFTA_MATCH_REV] = { .type = NLA_U32 }, [NFTA_MATCH_INFO] = { .type = NLA_BINARY }, }; /* struct xt_mtchk_param and xt_tgchk_param look very similar */
static void nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, struct xt_match *match, void *info, union nft_entry *entry, u16 proto, bool inv) { par->net = ctx->net; par->table = ctx->table->name; switch (ctx->afi->family) { case AF_INET: entry->e4.ip.proto = proto; entry->e4.ip.invflags = inv ? IPT_INV_PROTO : 0; break; case AF_INET6: if (proto) entry->e6.ipv6.flags |= IP6T_F_PROTO; entry->e6.ipv6.proto = proto; entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; break; case NFPROTO_BRIDGE: entry->ebt.ethproto = (__force __be16)proto; entry->ebt.invflags = inv ? EBT_IPROTO : 0; break; case NFPROTO_ARP: break; } par->entryinfo = entry; par->match = match; par->matchinfo = info; if (ctx->chain->flags & NFT_BASE_CHAIN) { const struct nft_base_chain *basechain = nft_base_chain(ctx->chain); const struct nf_hook_ops *ops = &basechain->ops[0]; par->hook_mask = 1 << ops->hooknum; } else { par->hook_mask = 0; } par->family = ctx->afi->family; par->nft_compat = true; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso22386.10%555.56%
arturo borrero gonzalezarturo borrero gonzalez3312.74%333.33%
patrick mchardypatrick mchardy31.16%111.11%
Total259100.00%9100.00%


static void match_compat_from_user(struct xt_match *m, void *in, void *out) { int pad; memcpy(out, in, m->matchsize); pad = XT_ALIGN(m->matchsize) - m->matchsize; if (pad > 0) memset(out + m->matchsize, 0, pad); }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso65100.00%2100.00%
Total65100.00%2100.00%


static int nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nlattr * const tb[]) { void *info = nft_expr_priv(expr); struct xt_match *match = expr->ops->data; struct xt_mtchk_param par; size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO])); u16 proto = 0; bool inv = false; union nft_entry e = {}; int ret; ret = nft_compat_chain_validate_dependency(match->table, ctx->chain); if (ret < 0) goto err; match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); if (ctx->nla[NFTA_RULE_COMPAT]) { ret = nft_parse_compat(ctx->nla[NFTA_RULE_COMPAT], &proto, &inv); if (ret < 0) goto err; } nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv); ret = xt_check_match(&par, size, proto, inv); if (ret < 0) goto err; return 0; err: module_put(match->me); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso21499.53%480.00%
arturo borrero gonzalezarturo borrero gonzalez10.47%120.00%
Total215100.00%5100.00%


static void nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr) { struct xt_match *match = expr->ops->data; void *info = nft_expr_priv(expr); struct xt_mtdtor_param par; par.net = ctx->net; par.match = match; par.matchinfo = info; par.family = ctx->afi->family; if (par.match->destroy != NULL) par.match->destroy(&par); nft_xt_put(container_of(expr->ops, struct nft_xt, ops)); module_put(match->me); }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso9381.58%250.00%
liping zhangliping zhang1513.16%125.00%
patrick mchardypatrick mchardy65.26%125.00%
Total114100.00%4100.00%


static int nft_match_dump(struct sk_buff *skb, const struct nft_expr *expr) { void *info = nft_expr_priv(expr); struct xt_match *match = expr->ops->data; if (nla_put_string(skb, NFTA_MATCH_NAME, match->name) || nla_put_be32(skb, NFTA_MATCH_REV, htonl(match->revision)) || nla_put(skb, NFTA_MATCH_INFO, XT_ALIGN(match->matchsize), info)) goto nla_put_failure; return 0; nla_put_failure: return -1; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso92100.00%2100.00%
Total92100.00%2100.00%


static int nft_match_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, const struct nft_data **data) { struct xt_match *match = expr->ops->data; unsigned int hook_mask = 0; int ret; if (ctx->chain->flags & NFT_BASE_CHAIN) { const struct nft_base_chain *basechain = nft_base_chain(ctx->chain); const struct nf_hook_ops *ops = &basechain->ops[0]; hook_mask = 1 << ops->hooknum; if (!(hook_mask & match->hooks)) return -EINVAL; ret = nft_compat_chain_validate_dependency(match->table, ctx->chain); if (ret < 0) return ret; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso12997.73%375.00%
patrick mchardypatrick mchardy32.27%125.00%
Total132100.00%4100.00%


static int nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, int event, u16 family, const char *name, int rev, int target) { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; unsigned int flags = portid ? NLM_F_MULTI : 0; event |= NFNL_SUBSYS_NFT_COMPAT << 8; nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags); if (nlh == NULL) goto nlmsg_failure; nfmsg = nlmsg_data(nlh); nfmsg->nfgen_family = family; nfmsg->version = NFNETLINK_V0