diff options
| -rw-r--r-- | include/net/netfilter/nf_tables.h | 22 | ||||
| -rw-r--r-- | net/netfilter/ipvs/ip_vs_sync.c | 3 | ||||
| -rw-r--r-- | net/netfilter/nf_tables_api.c | 61 | ||||
| -rw-r--r-- | net/netfilter/nft_compat.c | 14 |
4 files changed, 65 insertions, 35 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 9eaaa7884586..decb9a095ae7 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
| @@ -119,6 +119,22 @@ int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg, | |||
| 119 | const struct nft_data *data, | 119 | const struct nft_data *data, |
| 120 | enum nft_data_types type); | 120 | enum nft_data_types type); |
| 121 | 121 | ||
| 122 | |||
| 123 | /** | ||
| 124 | * struct nft_userdata - user defined data associated with an object | ||
| 125 | * | ||
| 126 | * @len: length of the data | ||
| 127 | * @data: content | ||
| 128 | * | ||
| 129 | * The presence of user data is indicated in an object specific fashion, | ||
| 130 | * so a length of zero can't occur and the value "len" indicates data | ||
| 131 | * of length len + 1. | ||
| 132 | */ | ||
| 133 | struct nft_userdata { | ||
| 134 | u8 len; | ||
| 135 | unsigned char data[0]; | ||
| 136 | }; | ||
| 137 | |||
| 122 | /** | 138 | /** |
| 123 | * struct nft_set_elem - generic representation of set elements | 139 | * struct nft_set_elem - generic representation of set elements |
| 124 | * | 140 | * |
| @@ -380,7 +396,7 @@ static inline void *nft_expr_priv(const struct nft_expr *expr) | |||
| 380 | * @handle: rule handle | 396 | * @handle: rule handle |
| 381 | * @genmask: generation mask | 397 | * @genmask: generation mask |
| 382 | * @dlen: length of expression data | 398 | * @dlen: length of expression data |
| 383 | * @ulen: length of user data (used for comments) | 399 | * @udata: user data is appended to the rule |
| 384 | * @data: expression data | 400 | * @data: expression data |
| 385 | */ | 401 | */ |
| 386 | struct nft_rule { | 402 | struct nft_rule { |
| @@ -388,7 +404,7 @@ struct nft_rule { | |||
| 388 | u64 handle:42, | 404 | u64 handle:42, |
| 389 | genmask:2, | 405 | genmask:2, |
| 390 | dlen:12, | 406 | dlen:12, |
| 391 | ulen:8; | 407 | udata:1; |
| 392 | unsigned char data[] | 408 | unsigned char data[] |
| 393 | __attribute__((aligned(__alignof__(struct nft_expr)))); | 409 | __attribute__((aligned(__alignof__(struct nft_expr)))); |
| 394 | }; | 410 | }; |
| @@ -476,7 +492,7 @@ static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule) | |||
| 476 | return (struct nft_expr *)&rule->data[rule->dlen]; | 492 | return (struct nft_expr *)&rule->data[rule->dlen]; |
| 477 | } | 493 | } |
| 478 | 494 | ||
| 479 | static inline void *nft_userdata(const struct nft_rule *rule) | 495 | static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule) |
| 480 | { | 496 | { |
| 481 | return (void *)&rule->data[rule->dlen]; | 497 | return (void *)&rule->data[rule->dlen]; |
| 482 | } | 498 | } |
diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index c47ffd7a0a70..d93ceeb3ef04 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c | |||
| @@ -896,6 +896,8 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param, | |||
| 896 | IP_VS_DBG(2, "BACKUP, add new conn. failed\n"); | 896 | IP_VS_DBG(2, "BACKUP, add new conn. failed\n"); |
| 897 | return; | 897 | return; |
| 898 | } | 898 | } |
| 899 | if (!(flags & IP_VS_CONN_F_TEMPLATE)) | ||
| 900 | kfree(param->pe_data); | ||
| 899 | } | 901 | } |
| 900 | 902 | ||
| 901 | if (opt) | 903 | if (opt) |
| @@ -1169,6 +1171,7 @@ static inline int ip_vs_proc_sync_conn(struct net *net, __u8 *p, __u8 *msg_end) | |||
| 1169 | (opt_flags & IPVS_OPT_F_SEQ_DATA ? &opt : NULL) | 1171 | (opt_flags & IPVS_OPT_F_SEQ_DATA ? &opt : NULL) |
| 1170 | ); | 1172 | ); |
| 1171 | #endif | 1173 | #endif |
| 1174 | ip_vs_pe_put(param.pe); | ||
| 1172 | return 0; | 1175 | return 0; |
| 1173 | /* Error exit */ | 1176 | /* Error exit */ |
| 1174 | out: | 1177 | out: |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 199fd0f27b0e..6ab777912237 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -227,7 +227,7 @@ nft_rule_deactivate_next(struct net *net, struct nft_rule *rule) | |||
| 227 | 227 | ||
| 228 | static inline void nft_rule_clear(struct net *net, struct nft_rule *rule) | 228 | static inline void nft_rule_clear(struct net *net, struct nft_rule *rule) |
| 229 | { | 229 | { |
| 230 | rule->genmask = 0; | 230 | rule->genmask &= ~(1 << gencursor_next(net)); |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | static int | 233 | static int |
| @@ -1711,9 +1711,12 @@ static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net, | |||
| 1711 | } | 1711 | } |
| 1712 | nla_nest_end(skb, list); | 1712 | nla_nest_end(skb, list); |
| 1713 | 1713 | ||
| 1714 | if (rule->ulen && | 1714 | if (rule->udata) { |
| 1715 | nla_put(skb, NFTA_RULE_USERDATA, rule->ulen, nft_userdata(rule))) | 1715 | struct nft_userdata *udata = nft_userdata(rule); |
| 1716 | goto nla_put_failure; | 1716 | if (nla_put(skb, NFTA_RULE_USERDATA, udata->len + 1, |
| 1717 | udata->data) < 0) | ||
| 1718 | goto nla_put_failure; | ||
| 1719 | } | ||
| 1717 | 1720 | ||
| 1718 | nlmsg_end(skb, nlh); | 1721 | nlmsg_end(skb, nlh); |
| 1719 | return 0; | 1722 | return 0; |
| @@ -1896,11 +1899,12 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
| 1896 | struct nft_table *table; | 1899 | struct nft_table *table; |
| 1897 | struct nft_chain *chain; | 1900 | struct nft_chain *chain; |
| 1898 | struct nft_rule *rule, *old_rule = NULL; | 1901 | struct nft_rule *rule, *old_rule = NULL; |
| 1902 | struct nft_userdata *udata; | ||
| 1899 | struct nft_trans *trans = NULL; | 1903 | struct nft_trans *trans = NULL; |
| 1900 | struct nft_expr *expr; | 1904 | struct nft_expr *expr; |
| 1901 | struct nft_ctx ctx; | 1905 | struct nft_ctx ctx; |
| 1902 | struct nlattr *tmp; | 1906 | struct nlattr *tmp; |
| 1903 | unsigned int size, i, n, ulen = 0; | 1907 | unsigned int size, i, n, ulen = 0, usize = 0; |
| 1904 | int err, rem; | 1908 | int err, rem; |
| 1905 | bool create; | 1909 | bool create; |
| 1906 | u64 handle, pos_handle; | 1910 | u64 handle, pos_handle; |
| @@ -1968,12 +1972,19 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
| 1968 | n++; | 1972 | n++; |
| 1969 | } | 1973 | } |
| 1970 | } | 1974 | } |
| 1975 | /* Check for overflow of dlen field */ | ||
| 1976 | err = -EFBIG; | ||
| 1977 | if (size >= 1 << 12) | ||
| 1978 | goto err1; | ||
| 1971 | 1979 | ||
| 1972 | if (nla[NFTA_RULE_USERDATA]) | 1980 | if (nla[NFTA_RULE_USERDATA]) { |
| 1973 | ulen = nla_len(nla[NFTA_RULE_USERDATA]); | 1981 | ulen = nla_len(nla[NFTA_RULE_USERDATA]); |
| 1982 | if (ulen > 0) | ||
| 1983 | usize = sizeof(struct nft_userdata) + ulen; | ||
| 1984 | } | ||
| 1974 | 1985 | ||
| 1975 | err = -ENOMEM; | 1986 | err = -ENOMEM; |
| 1976 | rule = kzalloc(sizeof(*rule) + size + ulen, GFP_KERNEL); | 1987 | rule = kzalloc(sizeof(*rule) + size + usize, GFP_KERNEL); |
| 1977 | if (rule == NULL) | 1988 | if (rule == NULL) |
| 1978 | goto err1; | 1989 | goto err1; |
| 1979 | 1990 | ||
| @@ -1981,10 +1992,13 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
| 1981 | 1992 | ||
| 1982 | rule->handle = handle; | 1993 | rule->handle = handle; |
| 1983 | rule->dlen = size; | 1994 | rule->dlen = size; |
| 1984 | rule->ulen = ulen; | 1995 | rule->udata = ulen ? 1 : 0; |
| 1985 | 1996 | ||
| 1986 | if (ulen) | 1997 | if (ulen) { |
| 1987 | nla_memcpy(nft_userdata(rule), nla[NFTA_RULE_USERDATA], ulen); | 1998 | udata = nft_userdata(rule); |
| 1999 | udata->len = ulen - 1; | ||
| 2000 | nla_memcpy(udata->data, nla[NFTA_RULE_USERDATA], ulen); | ||
| 2001 | } | ||
| 1988 | 2002 | ||
| 1989 | expr = nft_expr_first(rule); | 2003 | expr = nft_expr_first(rule); |
| 1990 | for (i = 0; i < n; i++) { | 2004 | for (i = 0; i < n; i++) { |
| @@ -2031,12 +2045,6 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb, | |||
| 2031 | 2045 | ||
| 2032 | err3: | 2046 | err3: |
| 2033 | list_del_rcu(&rule->list); | 2047 | list_del_rcu(&rule->list); |
| 2034 | if (trans) { | ||
| 2035 | list_del_rcu(&nft_trans_rule(trans)->list); | ||
| 2036 | nft_rule_clear(net, nft_trans_rule(trans)); | ||
| 2037 | nft_trans_destroy(trans); | ||
| 2038 | chain->use++; | ||
| 2039 | } | ||
| 2040 | err2: | 2048 | err2: |
| 2041 | nf_tables_rule_destroy(&ctx, rule); | 2049 | nf_tables_rule_destroy(&ctx, rule); |
| 2042 | err1: | 2050 | err1: |
| @@ -3612,12 +3620,11 @@ static int nf_tables_commit(struct sk_buff *skb) | |||
| 3612 | &te->elem, | 3620 | &te->elem, |
| 3613 | NFT_MSG_DELSETELEM, 0); | 3621 | NFT_MSG_DELSETELEM, 0); |
| 3614 | te->set->ops->get(te->set, &te->elem); | 3622 | te->set->ops->get(te->set, &te->elem); |
| 3615 | te->set->ops->remove(te->set, &te->elem); | ||
| 3616 | nft_data_uninit(&te->elem.key, NFT_DATA_VALUE); | 3623 | nft_data_uninit(&te->elem.key, NFT_DATA_VALUE); |
| 3617 | if (te->elem.flags & NFT_SET_MAP) { | 3624 | if (te->set->flags & NFT_SET_MAP && |
| 3618 | nft_data_uninit(&te->elem.data, | 3625 | !(te->elem.flags & NFT_SET_ELEM_INTERVAL_END)) |
| 3619 | te->set->dtype); | 3626 | nft_data_uninit(&te->elem.data, te->set->dtype); |
| 3620 | } | 3627 | te->set->ops->remove(te->set, &te->elem); |
| 3621 | nft_trans_destroy(trans); | 3628 | nft_trans_destroy(trans); |
| 3622 | break; | 3629 | break; |
| 3623 | } | 3630 | } |
| @@ -3658,7 +3665,7 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
| 3658 | { | 3665 | { |
| 3659 | struct net *net = sock_net(skb->sk); | 3666 | struct net *net = sock_net(skb->sk); |
| 3660 | struct nft_trans *trans, *next; | 3667 | struct nft_trans *trans, *next; |
| 3661 | struct nft_set *set; | 3668 | struct nft_trans_elem *te; |
| 3662 | 3669 | ||
| 3663 | list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { | 3670 | list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) { |
| 3664 | switch (trans->msg_type) { | 3671 | switch (trans->msg_type) { |
| @@ -3719,9 +3726,13 @@ static int nf_tables_abort(struct sk_buff *skb) | |||
| 3719 | break; | 3726 | break; |
| 3720 | case NFT_MSG_NEWSETELEM: | 3727 | case NFT_MSG_NEWSETELEM: |
| 3721 | nft_trans_elem_set(trans)->nelems--; | 3728 | nft_trans_elem_set(trans)->nelems--; |
| 3722 | set = nft_trans_elem_set(trans); | 3729 | te = (struct nft_trans_elem *)trans->data; |
| 3723 | set->ops->get(set, &nft_trans_elem(trans)); | 3730 | te->set->ops->get(te->set, &te->elem); |
| 3724 | set->ops->remove(set, &nft_trans_elem(trans)); | 3731 | nft_data_uninit(&te->elem.key, NFT_DATA_VALUE); |
| 3732 | if (te->set->flags & NFT_SET_MAP && | ||
| 3733 | !(te->elem.flags & NFT_SET_ELEM_INTERVAL_END)) | ||
| 3734 | nft_data_uninit(&te->elem.data, te->set->dtype); | ||
| 3735 | te->set->ops->remove(te->set, &te->elem); | ||
| 3725 | nft_trans_destroy(trans); | 3736 | nft_trans_destroy(trans); |
| 3726 | break; | 3737 | break; |
| 3727 | case NFT_MSG_DELSETELEM: | 3738 | case NFT_MSG_DELSETELEM: |
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 1279cd85663e..213584cf04b3 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
| @@ -123,7 +123,7 @@ static void | |||
| 123 | nft_target_set_tgchk_param(struct xt_tgchk_param *par, | 123 | nft_target_set_tgchk_param(struct xt_tgchk_param *par, |
| 124 | const struct nft_ctx *ctx, | 124 | const struct nft_ctx *ctx, |
| 125 | struct xt_target *target, void *info, | 125 | struct xt_target *target, void *info, |
| 126 | union nft_entry *entry, u8 proto, bool inv) | 126 | union nft_entry *entry, u16 proto, bool inv) |
| 127 | { | 127 | { |
| 128 | par->net = ctx->net; | 128 | par->net = ctx->net; |
| 129 | par->table = ctx->table->name; | 129 | par->table = ctx->table->name; |
| @@ -137,7 +137,7 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par, | |||
| 137 | entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; | 137 | entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; |
| 138 | break; | 138 | break; |
| 139 | case NFPROTO_BRIDGE: | 139 | case NFPROTO_BRIDGE: |
| 140 | entry->ebt.ethproto = proto; | 140 | entry->ebt.ethproto = (__force __be16)proto; |
| 141 | entry->ebt.invflags = inv ? EBT_IPROTO : 0; | 141 | entry->ebt.invflags = inv ? EBT_IPROTO : 0; |
| 142 | break; | 142 | break; |
| 143 | } | 143 | } |
| @@ -171,7 +171,7 @@ static const struct nla_policy nft_rule_compat_policy[NFTA_RULE_COMPAT_MAX + 1] | |||
| 171 | [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 }, | 171 | [NFTA_RULE_COMPAT_FLAGS] = { .type = NLA_U32 }, |
| 172 | }; | 172 | }; |
| 173 | 173 | ||
| 174 | static int nft_parse_compat(const struct nlattr *attr, u8 *proto, bool *inv) | 174 | static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv) |
| 175 | { | 175 | { |
| 176 | struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1]; | 176 | struct nlattr *tb[NFTA_RULE_COMPAT_MAX+1]; |
| 177 | u32 flags; | 177 | u32 flags; |
| @@ -203,7 +203,7 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
| 203 | struct xt_target *target = expr->ops->data; | 203 | struct xt_target *target = expr->ops->data; |
| 204 | struct xt_tgchk_param par; | 204 | struct xt_tgchk_param par; |
| 205 | size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO])); | 205 | size_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO])); |
| 206 | u8 proto = 0; | 206 | u16 proto = 0; |
| 207 | bool inv = false; | 207 | bool inv = false; |
| 208 | union nft_entry e = {}; | 208 | union nft_entry e = {}; |
| 209 | int ret; | 209 | int ret; |
| @@ -334,7 +334,7 @@ static const struct nla_policy nft_match_policy[NFTA_MATCH_MAX + 1] = { | |||
| 334 | static void | 334 | static void |
| 335 | nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, | 335 | nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, |
| 336 | struct xt_match *match, void *info, | 336 | struct xt_match *match, void *info, |
| 337 | union nft_entry *entry, u8 proto, bool inv) | 337 | union nft_entry *entry, u16 proto, bool inv) |
| 338 | { | 338 | { |
| 339 | par->net = ctx->net; | 339 | par->net = ctx->net; |
| 340 | par->table = ctx->table->name; | 340 | par->table = ctx->table->name; |
| @@ -348,7 +348,7 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, | |||
| 348 | entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; | 348 | entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; |
| 349 | break; | 349 | break; |
| 350 | case NFPROTO_BRIDGE: | 350 | case NFPROTO_BRIDGE: |
| 351 | entry->ebt.ethproto = proto; | 351 | entry->ebt.ethproto = (__force __be16)proto; |
| 352 | entry->ebt.invflags = inv ? EBT_IPROTO : 0; | 352 | entry->ebt.invflags = inv ? EBT_IPROTO : 0; |
| 353 | break; | 353 | break; |
| 354 | } | 354 | } |
| @@ -385,7 +385,7 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
| 385 | struct xt_match *match = expr->ops->data; | 385 | struct xt_match *match = expr->ops->data; |
| 386 | struct xt_mtchk_param par; | 386 | struct xt_mtchk_param par; |
| 387 | size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO])); | 387 | size_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO])); |
| 388 | u8 proto = 0; | 388 | u16 proto = 0; |
| 389 | bool inv = false; | 389 | bool inv = false; |
| 390 | union nft_entry e = {}; | 390 | union nft_entry e = {}; |
| 391 | int ret; | 391 | int ret; |
