Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_tables: allocate handle and delete objects via handle

This patch allows deletion of objects via unique handle which can be
listed via '-a' option.

Signed-off-by: Harsha Sharma <harshasharmaiitr@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Harsha Sharma and committed by
Pablo Neira Ayuso
3ecbfd65 cc2d5863

+153 -14
+9 -2
include/net/netfilter/nf_tables.h
··· 374 374 * @list: table set list node 375 375 * @bindings: list of set bindings 376 376 * @name: name of the set 377 + * @handle: unique handle of the set 377 378 * @ktype: key type (numeric type defined by userspace, not used in the kernel) 378 379 * @dtype: data type (verdict or numeric type defined by userspace) 379 380 * @objtype: object type (see NFT_OBJECT_* definitions) ··· 397 396 struct list_head list; 398 397 struct list_head bindings; 399 398 char *name; 399 + u64 handle; 400 400 u32 ktype; 401 401 u32 dtype; 402 402 u32 objtype; ··· 948 946 * @objects: stateful objects in the table 949 947 * @flowtables: flow tables in the table 950 948 * @hgenerator: handle generator state 949 + * @handle: table handle 951 950 * @use: number of chain references to this table 952 951 * @flags: table flag (see enum nft_table_flags) 953 952 * @genmask: generation mask ··· 962 959 struct list_head objects; 963 960 struct list_head flowtables; 964 961 u64 hgenerator; 962 + u64 handle; 965 963 u32 use; 966 964 u16 family:6, 967 965 flags:8, ··· 987 983 * @name: name of this stateful object 988 984 * @genmask: generation mask 989 985 * @use: number of references to this stateful object 990 - * @data: object data, layout depends on type 986 + * @handle: unique object handle 991 987 * @ops: object operations 992 - * @data: pointer to object data 988 + * @data: object data, layout depends on type 993 989 */ 994 990 struct nft_object { 995 991 struct list_head list; ··· 997 993 struct nft_table *table; 998 994 u32 genmask:2, 999 995 use:30; 996 + u64 handle; 1000 997 /* runtime data below here */ 1001 998 const struct nft_object_ops *ops ____cacheline_aligned; 1002 999 unsigned char data[] ··· 1079 1074 * @ops_len: number of hooks in array 1080 1075 * @genmask: generation mask 1081 1076 * @use: number of references to this flow table 1077 + * @handle: unique object handle 1082 1078 * @data: rhashtable and garbage collector 1083 1079 * @ops: array of hooks 1084 1080 */ ··· 1092 1086 int ops_len; 1093 1087 u32 genmask:2, 1094 1088 use:30; 1089 + u64 handle; 1095 1090 /* runtime data below here */ 1096 1091 struct nf_hook_ops *ops ____cacheline_aligned; 1097 1092 struct nf_flowtable data;
+10
include/uapi/linux/netfilter/nf_tables.h
··· 174 174 NFTA_TABLE_NAME, 175 175 NFTA_TABLE_FLAGS, 176 176 NFTA_TABLE_USE, 177 + NFTA_TABLE_HANDLE, 178 + NFTA_TABLE_PAD, 177 179 __NFTA_TABLE_MAX 178 180 }; 179 181 #define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) ··· 319 317 * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32) 320 318 * @NFTA_SET_USERDATA: user data (NLA_BINARY) 321 319 * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*) 320 + * @NFTA_SET_HANDLE: set handle (NLA_U64) 322 321 */ 323 322 enum nft_set_attributes { 324 323 NFTA_SET_UNSPEC, ··· 338 335 NFTA_SET_USERDATA, 339 336 NFTA_SET_PAD, 340 337 NFTA_SET_OBJ_TYPE, 338 + NFTA_SET_HANDLE, 341 339 __NFTA_SET_MAX 342 340 }; 343 341 #define NFTA_SET_MAX (__NFTA_SET_MAX - 1) ··· 1318 1314 * @NFTA_OBJ_TYPE: stateful object type (NLA_U32) 1319 1315 * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED) 1320 1316 * @NFTA_OBJ_USE: number of references to this expression (NLA_U32) 1317 + * @NFTA_OBJ_HANDLE: object handle (NLA_U64) 1321 1318 */ 1322 1319 enum nft_object_attributes { 1323 1320 NFTA_OBJ_UNSPEC, ··· 1327 1322 NFTA_OBJ_TYPE, 1328 1323 NFTA_OBJ_DATA, 1329 1324 NFTA_OBJ_USE, 1325 + NFTA_OBJ_HANDLE, 1326 + NFTA_OBJ_PAD, 1330 1327 __NFTA_OBJ_MAX 1331 1328 }; 1332 1329 #define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1) ··· 1340 1333 * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING) 1341 1334 * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32) 1342 1335 * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32) 1336 + * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64) 1343 1337 */ 1344 1338 enum nft_flowtable_attributes { 1345 1339 NFTA_FLOWTABLE_UNSPEC, ··· 1348 1340 NFTA_FLOWTABLE_NAME, 1349 1341 NFTA_FLOWTABLE_HOOK, 1350 1342 NFTA_FLOWTABLE_USE, 1343 + NFTA_FLOWTABLE_HANDLE, 1344 + NFTA_FLOWTABLE_PAD, 1351 1345 __NFTA_FLOWTABLE_MAX 1352 1346 }; 1353 1347 #define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
+134 -12
net/netfilter/nf_tables_api.c
··· 26 26 static LIST_HEAD(nf_tables_expressions); 27 27 static LIST_HEAD(nf_tables_objects); 28 28 static LIST_HEAD(nf_tables_flowtables); 29 + static u64 table_handle; 29 30 30 31 static void nft_ctx_init(struct nft_ctx *ctx, 31 32 struct net *net, ··· 333 332 return NULL; 334 333 } 335 334 335 + static struct nft_table *nft_table_lookup_byhandle(const struct net *net, 336 + const struct nlattr *nla, 337 + u8 genmask) 338 + { 339 + struct nft_table *table; 340 + 341 + list_for_each_entry(table, &net->nft.tables, list) { 342 + if (be64_to_cpu(nla_get_be64(nla)) == table->handle && 343 + nft_active_genmask(table, genmask)) 344 + return table; 345 + } 346 + return NULL; 347 + } 348 + 336 349 static struct nft_table *nf_tables_table_lookup(const struct net *net, 337 350 const struct nlattr *nla, 338 351 u8 family, u8 genmask) ··· 357 342 return ERR_PTR(-EINVAL); 358 343 359 344 table = nft_table_lookup(net, nla, family, genmask); 345 + if (table != NULL) 346 + return table; 347 + 348 + return ERR_PTR(-ENOENT); 349 + } 350 + 351 + static struct nft_table *nf_tables_table_lookup_byhandle(const struct net *net, 352 + const struct nlattr *nla, 353 + u8 genmask) 354 + { 355 + struct nft_table *table; 356 + 357 + if (nla == NULL) 358 + return ERR_PTR(-EINVAL); 359 + 360 + table = nft_table_lookup_byhandle(net, nla, genmask); 360 361 if (table != NULL) 361 362 return table; 362 363 ··· 425 394 [NFTA_TABLE_NAME] = { .type = NLA_STRING, 426 395 .len = NFT_TABLE_MAXNAMELEN - 1 }, 427 396 [NFTA_TABLE_FLAGS] = { .type = NLA_U32 }, 397 + [NFTA_TABLE_HANDLE] = { .type = NLA_U64 }, 428 398 }; 429 399 430 400 static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net, ··· 447 415 448 416 if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) || 449 417 nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) || 450 - nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use))) 418 + nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) || 419 + nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle), 420 + NFTA_TABLE_PAD)) 451 421 goto nla_put_failure; 452 422 453 423 nlmsg_end(skb, nlh); ··· 708 674 INIT_LIST_HEAD(&table->flowtables); 709 675 table->family = family; 710 676 table->flags = flags; 677 + table->handle = ++table_handle; 711 678 712 679 nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla); 713 680 err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE); ··· 826 791 struct nft_ctx ctx; 827 792 828 793 nft_ctx_init(&ctx, net, skb, nlh, 0, NULL, NULL, nla); 829 - if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL) 794 + if (family == AF_UNSPEC || 795 + (!nla[NFTA_TABLE_NAME] && !nla[NFTA_TABLE_HANDLE])) 830 796 return nft_flush(&ctx, family); 831 797 832 - table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME], family, 833 - genmask); 798 + if (nla[NFTA_TABLE_HANDLE]) 799 + table = nf_tables_table_lookup_byhandle(net, 800 + nla[NFTA_TABLE_HANDLE], 801 + genmask); 802 + else 803 + table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME], 804 + family, genmask); 805 + 834 806 if (IS_ERR(table)) 835 807 return PTR_ERR(table); 836 808 ··· 1581 1539 struct nft_rule *rule; 1582 1540 int family = nfmsg->nfgen_family; 1583 1541 struct nft_ctx ctx; 1542 + u64 handle; 1584 1543 u32 use; 1585 1544 int err; 1586 1545 ··· 1590 1547 if (IS_ERR(table)) 1591 1548 return PTR_ERR(table); 1592 1549 1593 - chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask); 1550 + if (nla[NFTA_CHAIN_HANDLE]) { 1551 + handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE])); 1552 + chain = nf_tables_chain_lookup_byhandle(table, handle, genmask); 1553 + } else { 1554 + chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask); 1555 + } 1594 1556 if (IS_ERR(chain)) 1595 1557 return PTR_ERR(chain); 1596 1558 ··· 2551 2503 [NFTA_SET_USERDATA] = { .type = NLA_BINARY, 2552 2504 .len = NFT_USERDATA_MAXLEN }, 2553 2505 [NFTA_SET_OBJ_TYPE] = { .type = NLA_U32 }, 2506 + [NFTA_SET_HANDLE] = { .type = NLA_U64 }, 2554 2507 }; 2555 2508 2556 2509 static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = { ··· 2589 2540 2590 2541 list_for_each_entry(set, &table->sets, list) { 2591 2542 if (!nla_strcmp(nla, set->name) && 2543 + nft_active_genmask(set, genmask)) 2544 + return set; 2545 + } 2546 + return ERR_PTR(-ENOENT); 2547 + } 2548 + 2549 + static struct nft_set *nf_tables_set_lookup_byhandle(const struct nft_table *table, 2550 + const struct nlattr *nla, u8 genmask) 2551 + { 2552 + struct nft_set *set; 2553 + 2554 + if (nla == NULL) 2555 + return ERR_PTR(-EINVAL); 2556 + 2557 + list_for_each_entry(set, &table->sets, list) { 2558 + if (be64_to_cpu(nla_get_be64(nla)) == set->handle && 2592 2559 nft_active_genmask(set, genmask)) 2593 2560 return set; 2594 2561 } ··· 2725 2660 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name)) 2726 2661 goto nla_put_failure; 2727 2662 if (nla_put_string(skb, NFTA_SET_NAME, set->name)) 2663 + goto nla_put_failure; 2664 + if (nla_put_be64(skb, NFTA_SET_HANDLE, cpu_to_be64(set->handle), 2665 + NFTA_SET_PAD)) 2728 2666 goto nla_put_failure; 2729 2667 if (set->flags != 0) 2730 2668 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags))) ··· 3137 3069 set->udata = udata; 3138 3070 set->timeout = timeout; 3139 3071 set->gc_int = gc_int; 3072 + set->handle = nf_tables_alloc_handle(table); 3140 3073 3141 3074 err = ops->init(set, &desc, nla); 3142 3075 if (err < 0) ··· 3195 3126 if (err < 0) 3196 3127 return err; 3197 3128 3198 - set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask); 3129 + if (nla[NFTA_SET_HANDLE]) 3130 + set = nf_tables_set_lookup_byhandle(ctx.table, nla[NFTA_SET_HANDLE], genmask); 3131 + else 3132 + set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask); 3199 3133 if (IS_ERR(set)) 3200 3134 return PTR_ERR(set); 3201 3135 ··· 4328 4256 } 4329 4257 EXPORT_SYMBOL_GPL(nf_tables_obj_lookup); 4330 4258 4259 + struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table, 4260 + const struct nlattr *nla, 4261 + u32 objtype, u8 genmask) 4262 + { 4263 + struct nft_object *obj; 4264 + 4265 + list_for_each_entry(obj, &table->objects, list) { 4266 + if (be64_to_cpu(nla_get_be64(nla)) == obj->handle && 4267 + objtype == obj->ops->type->type && 4268 + nft_active_genmask(obj, genmask)) 4269 + return obj; 4270 + } 4271 + return ERR_PTR(-ENOENT); 4272 + } 4273 + 4331 4274 static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = { 4332 4275 [NFTA_OBJ_TABLE] = { .type = NLA_STRING, 4333 4276 .len = NFT_TABLE_MAXNAMELEN - 1 }, ··· 4350 4263 .len = NFT_OBJ_MAXNAMELEN - 1 }, 4351 4264 [NFTA_OBJ_TYPE] = { .type = NLA_U32 }, 4352 4265 [NFTA_OBJ_DATA] = { .type = NLA_NESTED }, 4266 + [NFTA_OBJ_HANDLE] = { .type = NLA_U64}, 4353 4267 }; 4354 4268 4355 4269 static struct nft_object *nft_obj_init(const struct nft_ctx *ctx, ··· 4498 4410 goto err1; 4499 4411 } 4500 4412 obj->table = table; 4413 + obj->handle = nf_tables_alloc_handle(table); 4414 + 4501 4415 obj->name = nla_strdup(nla[NFTA_OBJ_NAME], GFP_KERNEL); 4502 4416 if (!obj->name) { 4503 4417 err = -ENOMEM; ··· 4546 4456 nla_put_string(skb, NFTA_OBJ_NAME, obj->name) || 4547 4457 nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) || 4548 4458 nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) || 4549 - nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset)) 4459 + nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset) || 4460 + nla_put_be64(skb, NFTA_OBJ_HANDLE, cpu_to_be64(obj->handle), 4461 + NFTA_OBJ_PAD)) 4550 4462 goto nla_put_failure; 4551 4463 4552 4464 nlmsg_end(skb, nlh); ··· 4746 4654 u32 objtype; 4747 4655 4748 4656 if (!nla[NFTA_OBJ_TYPE] || 4749 - !nla[NFTA_OBJ_NAME]) 4657 + (!nla[NFTA_OBJ_NAME] && !nla[NFTA_OBJ_HANDLE])) 4750 4658 return -EINVAL; 4751 4659 4752 4660 table = nf_tables_table_lookup(net, nla[NFTA_OBJ_TABLE], family, ··· 4755 4663 return PTR_ERR(table); 4756 4664 4757 4665 objtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE])); 4758 - obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME], objtype, genmask); 4666 + if (nla[NFTA_OBJ_HANDLE]) 4667 + obj = nf_tables_obj_lookup_byhandle(table, nla[NFTA_OBJ_HANDLE], 4668 + objtype, genmask); 4669 + else 4670 + obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME], 4671 + objtype, genmask); 4759 4672 if (IS_ERR(obj)) 4760 4673 return PTR_ERR(obj); 4761 4674 if (obj->use > 0) ··· 4832 4735 [NFTA_FLOWTABLE_NAME] = { .type = NLA_STRING, 4833 4736 .len = NFT_NAME_MAXLEN - 1 }, 4834 4737 [NFTA_FLOWTABLE_HOOK] = { .type = NLA_NESTED }, 4738 + [NFTA_FLOWTABLE_HANDLE] = { .type = NLA_U64 }, 4835 4739 }; 4836 4740 4837 4741 struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table, ··· 4849 4751 return ERR_PTR(-ENOENT); 4850 4752 } 4851 4753 EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup); 4754 + 4755 + struct nft_flowtable * 4756 + nf_tables_flowtable_lookup_byhandle(const struct nft_table *table, 4757 + const struct nlattr *nla, u8 genmask) 4758 + { 4759 + struct nft_flowtable *flowtable; 4760 + 4761 + list_for_each_entry(flowtable, &table->flowtables, list) { 4762 + if (be64_to_cpu(nla_get_be64(nla)) == flowtable->handle && 4763 + nft_active_genmask(flowtable, genmask)) 4764 + return flowtable; 4765 + } 4766 + return ERR_PTR(-ENOENT); 4767 + } 4852 4768 4853 4769 #define NFT_FLOWTABLE_DEVICE_MAX 8 4854 4770 ··· 5072 4960 return -ENOMEM; 5073 4961 5074 4962 flowtable->table = table; 4963 + flowtable->handle = nf_tables_alloc_handle(table); 4964 + 5075 4965 flowtable->name = nla_strdup(nla[NFTA_FLOWTABLE_NAME], GFP_KERNEL); 5076 4966 if (!flowtable->name) { 5077 4967 err = -ENOMEM; ··· 5148 5034 if (IS_ERR(table)) 5149 5035 return PTR_ERR(table); 5150 5036 5151 - flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME], 5152 - genmask); 5037 + if (nla[NFTA_FLOWTABLE_HANDLE]) 5038 + flowtable = nf_tables_flowtable_lookup_byhandle(table, 5039 + nla[NFTA_FLOWTABLE_HANDLE], 5040 + genmask); 5041 + else 5042 + flowtable = nf_tables_flowtable_lookup(table, 5043 + nla[NFTA_FLOWTABLE_NAME], 5044 + genmask); 5153 5045 if (IS_ERR(flowtable)) 5154 5046 return PTR_ERR(flowtable); 5155 5047 if (flowtable->use > 0) ··· 5188 5068 5189 5069 if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) || 5190 5070 nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) || 5191 - nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use))) 5071 + nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) || 5072 + nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle), 5073 + NFTA_FLOWTABLE_PAD)) 5192 5074 goto nla_put_failure; 5193 5075 5194 5076 nest = nla_nest_start(skb, NFTA_FLOWTABLE_HOOK);