6daa6cbf7e16771e106d8079f94e0ecf292712d5
[oweals/openwrt.git] /
1 From: Harsha Sharma <harshasharmaiitr@gmail.com>
2 Date: Wed, 27 Dec 2017 00:59:00 +0530
3 Subject: [PATCH] netfilter: nf_tables: allocate handle and delete objects via
4  handle
5
6 This patch allows deletion of objects via unique handle which can be
7 listed via '-a' option.
8
9 Signed-off-by: Harsha Sharma <harshasharmaiitr@gmail.com>
10 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
11 ---
12
13 --- a/include/net/netfilter/nf_tables.h
14 +++ b/include/net/netfilter/nf_tables.h
15 @@ -370,6 +370,7 @@ void nft_unregister_set(struct nft_set_t
16   *     @list: table set list node
17   *     @bindings: list of set bindings
18   *     @name: name of the set
19 + *     @handle: unique handle of the set
20   *     @ktype: key type (numeric type defined by userspace, not used in the kernel)
21   *     @dtype: data type (verdict or numeric type defined by userspace)
22   *     @objtype: object type (see NFT_OBJECT_* definitions)
23 @@ -392,6 +393,7 @@ struct nft_set {
24         struct list_head                list;
25         struct list_head                bindings;
26         char                            *name;
27 +       u64                             handle;
28         u32                             ktype;
29         u32                             dtype;
30         u32                             objtype;
31 @@ -941,6 +943,7 @@ unsigned int nft_do_chain(struct nft_pkt
32   *     @objects: stateful objects in the table
33   *     @flowtables: flow tables in the table
34   *     @hgenerator: handle generator state
35 + *     @handle: table handle
36   *     @use: number of chain references to this table
37   *     @flags: table flag (see enum nft_table_flags)
38   *     @genmask: generation mask
39 @@ -954,6 +957,7 @@ struct nft_table {
40         struct list_head                objects;
41         struct list_head                flowtables;
42         u64                             hgenerator;
43 +       u64                             handle;
44         u32                             use;
45         u16                             family:6,
46                                         flags:8,
47 @@ -978,9 +982,9 @@ int nft_verdict_dump(struct sk_buff *skb
48   *     @name: name of this stateful object
49   *     @genmask: generation mask
50   *     @use: number of references to this stateful object
51 - *     @data: object data, layout depends on type
52 + *     @handle: unique object handle
53   *     @ops: object operations
54 - *     @data: pointer to object data
55 + *     @data: object data, layout depends on type
56   */
57  struct nft_object {
58         struct list_head                list;
59 @@ -988,6 +992,7 @@ struct nft_object {
60         struct nft_table                *table;
61         u32                             genmask:2,
62                                         use:30;
63 +       u64                             handle;
64         /* runtime data below here */
65         const struct nft_object_ops     *ops ____cacheline_aligned;
66         unsigned char                   data[]
67 @@ -1069,6 +1074,7 @@ void nft_unregister_obj(struct nft_objec
68   *     @ops_len: number of hooks in array
69   *     @genmask: generation mask
70   *     @use: number of references to this flow table
71 + *     @handle: unique object handle
72   *     @data: rhashtable and garbage collector
73   *     @ops: array of hooks
74   */
75 @@ -1081,6 +1087,7 @@ struct nft_flowtable {
76         int                             ops_len;
77         u32                             genmask:2,
78                                         use:30;
79 +       u64                             handle;
80         /* runtime data below here */
81         struct nf_hook_ops              *ops ____cacheline_aligned;
82         struct nf_flowtable             data;
83 --- a/include/uapi/linux/netfilter/nf_tables.h
84 +++ b/include/uapi/linux/netfilter/nf_tables.h
85 @@ -174,6 +174,8 @@ enum nft_table_attributes {
86         NFTA_TABLE_NAME,
87         NFTA_TABLE_FLAGS,
88         NFTA_TABLE_USE,
89 +       NFTA_TABLE_HANDLE,
90 +       NFTA_TABLE_PAD,
91         __NFTA_TABLE_MAX
92  };
93  #define NFTA_TABLE_MAX         (__NFTA_TABLE_MAX - 1)
94 @@ -317,6 +319,7 @@ enum nft_set_desc_attributes {
95   * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32)
96   * @NFTA_SET_USERDATA: user data (NLA_BINARY)
97   * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
98 + * @NFTA_SET_HANDLE: set handle (NLA_U64)
99   */
100  enum nft_set_attributes {
101         NFTA_SET_UNSPEC,
102 @@ -335,6 +338,7 @@ enum nft_set_attributes {
103         NFTA_SET_USERDATA,
104         NFTA_SET_PAD,
105         NFTA_SET_OBJ_TYPE,
106 +       NFTA_SET_HANDLE,
107         __NFTA_SET_MAX
108  };
109  #define NFTA_SET_MAX           (__NFTA_SET_MAX - 1)
110 @@ -1314,6 +1318,7 @@ enum nft_ct_helper_attributes {
111   * @NFTA_OBJ_TYPE: stateful object type (NLA_U32)
112   * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED)
113   * @NFTA_OBJ_USE: number of references to this expression (NLA_U32)
114 + * @NFTA_OBJ_HANDLE: object handle (NLA_U64)
115   */
116  enum nft_object_attributes {
117         NFTA_OBJ_UNSPEC,
118 @@ -1322,6 +1327,8 @@ enum nft_object_attributes {
119         NFTA_OBJ_TYPE,
120         NFTA_OBJ_DATA,
121         NFTA_OBJ_USE,
122 +       NFTA_OBJ_HANDLE,
123 +       NFTA_OBJ_PAD,
124         __NFTA_OBJ_MAX
125  };
126  #define NFTA_OBJ_MAX           (__NFTA_OBJ_MAX - 1)
127 @@ -1333,6 +1340,7 @@ enum nft_object_attributes {
128   * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING)
129   * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
130   * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
131 + * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
132   */
133  enum nft_flowtable_attributes {
134         NFTA_FLOWTABLE_UNSPEC,
135 @@ -1340,6 +1348,8 @@ enum nft_flowtable_attributes {
136         NFTA_FLOWTABLE_NAME,
137         NFTA_FLOWTABLE_HOOK,
138         NFTA_FLOWTABLE_USE,
139 +       NFTA_FLOWTABLE_HANDLE,
140 +       NFTA_FLOWTABLE_PAD,
141         __NFTA_FLOWTABLE_MAX
142  };
143  #define NFTA_FLOWTABLE_MAX     (__NFTA_FLOWTABLE_MAX - 1)
144 --- a/net/netfilter/nf_tables_api.c
145 +++ b/net/netfilter/nf_tables_api.c
146 @@ -26,6 +26,7 @@
147  static LIST_HEAD(nf_tables_expressions);
148  static LIST_HEAD(nf_tables_objects);
149  static LIST_HEAD(nf_tables_flowtables);
150 +static u64 table_handle;
151  
152  static void nft_ctx_init(struct nft_ctx *ctx,
153                          struct net *net,
154 @@ -376,6 +377,20 @@ static struct nft_table *nft_table_looku
155         return NULL;
156  }
157  
158 +static struct nft_table *nft_table_lookup_byhandle(const struct net *net,
159 +                                                  const struct nlattr *nla,
160 +                                                  u8 genmask)
161 +{
162 +       struct nft_table *table;
163 +
164 +       list_for_each_entry(table, &net->nft.tables, list) {
165 +               if (be64_to_cpu(nla_get_be64(nla)) == table->handle &&
166 +                   nft_active_genmask(table, genmask))
167 +                       return table;
168 +       }
169 +       return NULL;
170 +}
171 +
172  static struct nft_table *nf_tables_table_lookup(const struct net *net,
173                                                 const struct nlattr *nla,
174                                                 u8 family, u8 genmask)
175 @@ -392,6 +407,22 @@ static struct nft_table *nf_tables_table
176         return ERR_PTR(-ENOENT);
177  }
178  
179 +static struct nft_table *nf_tables_table_lookup_byhandle(const struct net *net,
180 +                                                        const struct nlattr *nla,
181 +                                                        u8 genmask)
182 +{
183 +       struct nft_table *table;
184 +
185 +       if (nla == NULL)
186 +               return ERR_PTR(-EINVAL);
187 +
188 +       table = nft_table_lookup_byhandle(net, nla, genmask);
189 +       if (table != NULL)
190 +               return table;
191 +
192 +       return ERR_PTR(-ENOENT);
193 +}
194 +
195  static inline u64 nf_tables_alloc_handle(struct nft_table *table)
196  {
197         return ++table->hgenerator;
198 @@ -438,6 +469,7 @@ static const struct nla_policy nft_table
199         [NFTA_TABLE_NAME]       = { .type = NLA_STRING,
200                                     .len = NFT_TABLE_MAXNAMELEN - 1 },
201         [NFTA_TABLE_FLAGS]      = { .type = NLA_U32 },
202 +       [NFTA_TABLE_HANDLE]     = { .type = NLA_U64 },
203  };
204  
205  static int nf_tables_fill_table_info(struct sk_buff *skb, struct net *net,
206 @@ -459,7 +491,9 @@ static int nf_tables_fill_table_info(str
207  
208         if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
209             nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
210 -           nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)))
211 +           nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
212 +           nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
213 +                        NFTA_TABLE_PAD))
214                 goto nla_put_failure;
215  
216         nlmsg_end(skb, nlh);
217 @@ -718,6 +752,7 @@ static int nf_tables_newtable(struct net
218         INIT_LIST_HEAD(&table->flowtables);
219         table->family = family;
220         table->flags = flags;
221 +       table->handle = ++table_handle;
222  
223         nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
224         err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
225 @@ -835,11 +870,18 @@ static int nf_tables_deltable(struct net
226         struct nft_ctx ctx;
227  
228         nft_ctx_init(&ctx, net, skb, nlh, 0, NULL, NULL, nla);
229 -       if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
230 +       if (family == AF_UNSPEC ||
231 +           (!nla[NFTA_TABLE_NAME] && !nla[NFTA_TABLE_HANDLE]))
232                 return nft_flush(&ctx, family);
233  
234 -       table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME], family,
235 -                                      genmask);
236 +       if (nla[NFTA_TABLE_HANDLE])
237 +               table = nf_tables_table_lookup_byhandle(net,
238 +                                                       nla[NFTA_TABLE_HANDLE],
239 +                                                       genmask);
240 +       else
241 +               table = nf_tables_table_lookup(net, nla[NFTA_TABLE_NAME],
242 +                                              family, genmask);
243 +
244         if (IS_ERR(table))
245                 return PTR_ERR(table);
246  
247 @@ -1596,6 +1638,7 @@ static int nf_tables_delchain(struct net
248         struct nft_rule *rule;
249         int family = nfmsg->nfgen_family;
250         struct nft_ctx ctx;
251 +       u64 handle;
252         u32 use;
253         int err;
254  
255 @@ -1604,7 +1647,12 @@ static int nf_tables_delchain(struct net
256         if (IS_ERR(table))
257                 return PTR_ERR(table);
258  
259 -       chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
260 +       if (nla[NFTA_CHAIN_HANDLE]) {
261 +               handle = be64_to_cpu(nla_get_be64(nla[NFTA_CHAIN_HANDLE]));
262 +               chain = nf_tables_chain_lookup_byhandle(table, handle, genmask);
263 +       } else {
264 +               chain = nf_tables_chain_lookup(table, nla[NFTA_CHAIN_NAME], genmask);
265 +       }
266         if (IS_ERR(chain))
267                 return PTR_ERR(chain);
268  
269 @@ -2579,6 +2627,7 @@ static const struct nla_policy nft_set_p
270         [NFTA_SET_USERDATA]             = { .type = NLA_BINARY,
271                                             .len  = NFT_USERDATA_MAXLEN },
272         [NFTA_SET_OBJ_TYPE]             = { .type = NLA_U32 },
273 +       [NFTA_SET_HANDLE]               = { .type = NLA_U64 },
274  };
275  
276  static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
277 @@ -2622,6 +2671,22 @@ static struct nft_set *nf_tables_set_loo
278         return ERR_PTR(-ENOENT);
279  }
280  
281 +static struct nft_set *nf_tables_set_lookup_byhandle(const struct nft_table *table,
282 +                                                    const struct nlattr *nla, u8 genmask)
283 +{
284 +       struct nft_set *set;
285 +
286 +       if (nla == NULL)
287 +               return ERR_PTR(-EINVAL);
288 +
289 +       list_for_each_entry(set, &table->sets, list) {
290 +               if (be64_to_cpu(nla_get_be64(nla)) == set->handle &&
291 +                   nft_active_genmask(set, genmask))
292 +                       return set;
293 +       }
294 +       return ERR_PTR(-ENOENT);
295 +}
296 +
297  static struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
298                                                  const struct nlattr *nla,
299                                                  u8 genmask)
300 @@ -2738,6 +2803,9 @@ static int nf_tables_fill_set(struct sk_
301                 goto nla_put_failure;
302         if (nla_put_string(skb, NFTA_SET_NAME, set->name))
303                 goto nla_put_failure;
304 +       if (nla_put_be64(skb, NFTA_SET_HANDLE, cpu_to_be64(set->handle),
305 +                        NFTA_SET_PAD))
306 +               goto nla_put_failure;
307         if (set->flags != 0)
308                 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
309                         goto nla_put_failure;
310 @@ -3149,6 +3217,7 @@ static int nf_tables_newset(struct net *
311         set->udata  = udata;
312         set->timeout = timeout;
313         set->gc_int = gc_int;
314 +       set->handle = nf_tables_alloc_handle(table);
315  
316         err = ops->init(set, &desc, nla);
317         if (err < 0)
318 @@ -3208,7 +3277,10 @@ static int nf_tables_delset(struct net *
319         if (err < 0)
320                 return err;
321  
322 -       set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
323 +       if (nla[NFTA_SET_HANDLE])
324 +               set = nf_tables_set_lookup_byhandle(ctx.table, nla[NFTA_SET_HANDLE], genmask);
325 +       else
326 +               set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME], genmask);
327         if (IS_ERR(set))
328                 return PTR_ERR(set);
329  
330 @@ -4271,6 +4343,21 @@ struct nft_object *nf_tables_obj_lookup(
331  }
332  EXPORT_SYMBOL_GPL(nf_tables_obj_lookup);
333  
334 +struct nft_object *nf_tables_obj_lookup_byhandle(const struct nft_table *table,
335 +                                                const struct nlattr *nla,
336 +                                                u32 objtype, u8 genmask)
337 +{
338 +       struct nft_object *obj;
339 +
340 +       list_for_each_entry(obj, &table->objects, list) {
341 +               if (be64_to_cpu(nla_get_be64(nla)) == obj->handle &&
342 +                   objtype == obj->ops->type->type &&
343 +                   nft_active_genmask(obj, genmask))
344 +                       return obj;
345 +       }
346 +       return ERR_PTR(-ENOENT);
347 +}
348 +
349  static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
350         [NFTA_OBJ_TABLE]        = { .type = NLA_STRING,
351                                     .len = NFT_TABLE_MAXNAMELEN - 1 },
352 @@ -4278,6 +4365,7 @@ static const struct nla_policy nft_obj_p
353                                     .len = NFT_OBJ_MAXNAMELEN - 1 },
354         [NFTA_OBJ_TYPE]         = { .type = NLA_U32 },
355         [NFTA_OBJ_DATA]         = { .type = NLA_NESTED },
356 +       [NFTA_OBJ_HANDLE]       = { .type = NLA_U64},
357  };
358  
359  static struct nft_object *nft_obj_init(const struct nft_ctx *ctx,
360 @@ -4425,6 +4513,8 @@ static int nf_tables_newobj(struct net *
361                 goto err1;
362         }
363         obj->table = table;
364 +       obj->handle = nf_tables_alloc_handle(table);
365 +
366         obj->name = nla_strdup(nla[NFTA_OBJ_NAME], GFP_KERNEL);
367         if (!obj->name) {
368                 err = -ENOMEM;
369 @@ -4471,7 +4561,9 @@ static int nf_tables_fill_obj_info(struc
370             nla_put_string(skb, NFTA_OBJ_NAME, obj->name) ||
371             nla_put_be32(skb, NFTA_OBJ_TYPE, htonl(obj->ops->type->type)) ||
372             nla_put_be32(skb, NFTA_OBJ_USE, htonl(obj->use)) ||
373 -           nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset))
374 +           nft_object_dump(skb, NFTA_OBJ_DATA, obj, reset) ||
375 +           nla_put_be64(skb, NFTA_OBJ_HANDLE, cpu_to_be64(obj->handle),
376 +                        NFTA_OBJ_PAD))
377                 goto nla_put_failure;
378  
379         nlmsg_end(skb, nlh);
380 @@ -4669,7 +4761,7 @@ static int nf_tables_delobj(struct net *
381         u32 objtype;
382  
383         if (!nla[NFTA_OBJ_TYPE] ||
384 -           !nla[NFTA_OBJ_NAME])
385 +           (!nla[NFTA_OBJ_NAME] && !nla[NFTA_OBJ_HANDLE]))
386                 return -EINVAL;
387  
388         table = nf_tables_table_lookup(net, nla[NFTA_OBJ_TABLE], family,
389 @@ -4678,7 +4770,12 @@ static int nf_tables_delobj(struct net *
390                 return PTR_ERR(table);
391  
392         objtype = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
393 -       obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME], objtype, genmask);
394 +       if (nla[NFTA_OBJ_HANDLE])
395 +               obj = nf_tables_obj_lookup_byhandle(table, nla[NFTA_OBJ_HANDLE],
396 +                                                   objtype, genmask);
397 +       else
398 +               obj = nf_tables_obj_lookup(table, nla[NFTA_OBJ_NAME],
399 +                                          objtype, genmask);
400         if (IS_ERR(obj))
401                 return PTR_ERR(obj);
402         if (obj->use > 0)
403 @@ -4750,6 +4847,7 @@ static const struct nla_policy nft_flowt
404         [NFTA_FLOWTABLE_NAME]           = { .type = NLA_STRING,
405                                             .len = NFT_NAME_MAXLEN - 1 },
406         [NFTA_FLOWTABLE_HOOK]           = { .type = NLA_NESTED },
407 +       [NFTA_FLOWTABLE_HANDLE]         = { .type = NLA_U64 },
408  };
409  
410  struct nft_flowtable *nf_tables_flowtable_lookup(const struct nft_table *table,
411 @@ -4767,6 +4865,20 @@ struct nft_flowtable *nf_tables_flowtabl
412  }
413  EXPORT_SYMBOL_GPL(nf_tables_flowtable_lookup);
414  
415 +struct nft_flowtable *
416 +nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
417 +                                   const struct nlattr *nla, u8 genmask)
418 +{
419 +       struct nft_flowtable *flowtable;
420 +
421 +       list_for_each_entry(flowtable, &table->flowtables, list) {
422 +               if (be64_to_cpu(nla_get_be64(nla)) == flowtable->handle &&
423 +                   nft_active_genmask(flowtable, genmask))
424 +                       return flowtable;
425 +       }
426 +       return ERR_PTR(-ENOENT);
427 +}
428 +
429  #define NFT_FLOWTABLE_DEVICE_MAX       8
430  
431  static int nf_tables_parse_devices(const struct nft_ctx *ctx,
432 @@ -4975,6 +5087,8 @@ static int nf_tables_newflowtable(struct
433                 return -ENOMEM;
434  
435         flowtable->table = table;
436 +       flowtable->handle = nf_tables_alloc_handle(table);
437 +
438         flowtable->name = nla_strdup(nla[NFTA_FLOWTABLE_NAME], GFP_KERNEL);
439         if (!flowtable->name) {
440                 err = -ENOMEM;
441 @@ -5049,8 +5163,14 @@ static int nf_tables_delflowtable(struct
442         if (IS_ERR(table))
443                 return PTR_ERR(table);
444  
445 -       flowtable = nf_tables_flowtable_lookup(table, nla[NFTA_FLOWTABLE_NAME],
446 -                                              genmask);
447 +       if (nla[NFTA_FLOWTABLE_HANDLE])
448 +               flowtable = nf_tables_flowtable_lookup_byhandle(table,
449 +                                                               nla[NFTA_FLOWTABLE_HANDLE],
450 +                                                               genmask);
451 +       else
452 +               flowtable = nf_tables_flowtable_lookup(table,
453 +                                                      nla[NFTA_FLOWTABLE_NAME],
454 +                                                      genmask);
455         if (IS_ERR(flowtable))
456                  return PTR_ERR(flowtable);
457         if (flowtable->use > 0)
458 @@ -5083,7 +5203,9 @@ static int nf_tables_fill_flowtable_info
459  
460         if (nla_put_string(skb, NFTA_FLOWTABLE_TABLE, flowtable->table->name) ||
461             nla_put_string(skb, NFTA_FLOWTABLE_NAME, flowtable->name) ||
462 -           nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)))
463 +           nla_put_be32(skb, NFTA_FLOWTABLE_USE, htonl(flowtable->use)) ||
464 +           nla_put_be64(skb, NFTA_FLOWTABLE_HANDLE, cpu_to_be64(flowtable->handle),
465 +                        NFTA_FLOWTABLE_PAD))
466                 goto nla_put_failure;
467  
468         nest = nla_nest_start(skb, NFTA_FLOWTABLE_HOOK);