| @@ -5467,6 +5467,27 @@ err_set_elem_expr: · 5466 unmodified lines |
| 5467 | return ERR_PTR(err); | 5467 | return ERR_PTR(err); |
| 5468 | } | 5468 | } |
| 5469 | | 5469 | |
| | 5470 | static int nft_set_ext_check(const struct nft_set_ext_tmpl *tmpl, u8 id, u32 len) |
| | 5471 | { |
| | 5472 | len += nft_set_ext_types[id].len; |
| | 5473 | if (len > tmpl->ext_len[id] || |
| | 5474 | len > U8_MAX) |
| | 5475 | return -1; |
| | 5476 | |
| | 5477 | return 0; |
| | 5478 | } |
| | 5479 | |
| | 5480 | static int nft_set_ext_memcpy(const struct nft_set_ext_tmpl *tmpl, u8 id, |
| | 5481 | void *to, const void *from, u32 len) |
| | 5482 | { |
| | 5483 | if (nft_set_ext_check(tmpl, id, len) < 0) |
| | 5484 | return -1; |
| | 5485 | |
| | 5486 | memcpy(to, from, len); |
| | 5487 | |
| | 5488 | return 0; |
| | 5489 | } |
| | 5490 | |
| 5470 | void *nft_set_elem_init(const struct nft_set *set, | 5491 | void *nft_set_elem_init(const struct nft_set *set, |
| 5471 | const struct nft_set_ext_tmpl *tmpl, | 5492 | const struct nft_set_ext_tmpl *tmpl, |
| 5472 | const u32 *key, const u32 *key_end, | 5493 | const u32 *key, const u32 *key_end, |
| @@ -5477,17 +5498,26 @@ void *nft_set_elem_init(const struct nft_set *set, · 4 unmodified lines |
| 5477 | | 5498 | |
| 5478 | elem = kzalloc(set->ops->elemsize + tmpl->len, gfp); | 5499 | elem = kzalloc(set->ops->elemsize + tmpl->len, gfp); |
| 5479 | if (elem == NULL) | 5500 | if (elem == NULL) |
| 5480 | return NULL; | 5501 | return ERR_PTR(-ENOMEM); |
| 5481 | | 5502 | |
| 5482 | ext = nft_set_elem_ext(set, elem); | 5503 | ext = nft_set_elem_ext(set, elem); |
| 5483 | nft_set_ext_init(ext, tmpl); | 5504 | nft_set_ext_init(ext, tmpl); |
| 5484 | | 5505 | |
| 5485 | if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY)) | 5506 | if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY) && |
| 5486 | memcpy(nft_set_ext_key(ext), key, set->klen); | 5507 | nft_set_ext_memcpy(tmpl, NFT_SET_EXT_KEY, |
| 5487 | if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END)) | 5508 | nft_set_ext_key(ext), key, set->klen) < 0) |
| 5488 | memcpy(nft_set_ext_key_end(ext), key_end, set->klen); | 5509 | goto err_ext_check; |
| 5489 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) | 5510 | |
| 5490 | memcpy(nft_set_ext_data(ext), data, set->dlen); | 5511 | if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END) && |
| | 5512 | nft_set_ext_memcpy(tmpl, NFT_SET_EXT_KEY_END, |
| | 5513 | nft_set_ext_key_end(ext), key_end, set->klen) < 0) |
| | 5514 | goto err_ext_check; |
| | 5515 | |
| | 5516 | if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) && |
| | 5517 | nft_set_ext_memcpy(tmpl, NFT_SET_EXT_DATA, |
| | 5518 | nft_set_ext_data(ext), data, set->dlen) < 0) |
| | 5519 | goto err_ext_check; |
| | 5520 | |
| 5491 | if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { | 5521 | if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { |
| 5492 | *nft_set_ext_expiration(ext) = get_jiffies_64() + expiration; | 5522 | *nft_set_ext_expiration(ext) = get_jiffies_64() + expiration; |
| 5493 | if (expiration == 0) | 5523 | if (expiration == 0) |
| @@ -5497,6 +5527,11 @@ void *nft_set_elem_init(const struct nft_set *set, · 3 unmodified lines |
| 5497 | *nft_set_ext_timeout(ext) = timeout; | 5527 | *nft_set_ext_timeout(ext) = timeout; |
| 5498 | | 5528 | |
| 5499 | return elem; | 5529 | return elem; |
| | 5530 | |
| | 5531 | err_ext_check: |
| | 5532 | kfree(elem); |
| | 5533 | |
| | 5534 | return ERR_PTR(-EINVAL); |
| 5500 | } | 5535 | } |
| 5501 | | 5536 | |
| 5502 | static void __nft_set_elem_expr_destroy(const struct nft_ctx *ctx, | 5537 | static void __nft_set_elem_expr_destroy(const struct nft_ctx *ctx, |
| @@ -5584,14 +5619,25 @@ err_expr: · 81 unmodified lines |
| 5584 | } | 5619 | } |
| 5585 | | 5620 | |
| 5586 | static int nft_set_elem_expr_setup(struct nft_ctx *ctx, | 5621 | static int nft_set_elem_expr_setup(struct nft_ctx *ctx, |
| | 5622 | const struct nft_set_ext_tmpl *tmpl, |
| 5587 | const struct nft_set_ext *ext, | 5623 | const struct nft_set_ext *ext, |
| 5588 | struct nft_expr *expr_array[], | 5624 | struct nft_expr *expr_array[], |
| 5589 | u32 num_exprs) | 5625 | u32 num_exprs) |
| 5590 | { | 5626 | { |
| 5591 | struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext); | 5627 | struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext); |
| | 5628 | u32 len = sizeof(struct nft_set_elem_expr); |
| 5592 | struct nft_expr *expr; | 5629 | struct nft_expr *expr; |
| 5593 | int i, err; | 5630 | int i, err; |
| 5594 | | 5631 | |
| | 5632 | if (num_exprs == 0) |
| | 5633 | return 0; |
| | 5634 | |
| | 5635 | for (i = 0; i < num_exprs; i++) |
| | 5636 | len += expr_array[i]->ops->size; |
| | 5637 | |
| | 5638 | if (nft_set_ext_check(tmpl, NFT_SET_EXT_EXPRESSIONS, len) < 0) |
| | 5639 | return -EINVAL; |
| | 5640 | |
| 5595 | for (i = 0; i < num_exprs; i++) { | 5641 | for (i = 0; i < num_exprs; i++) { |
| 5596 | expr = nft_setelem_expr_at(elem_expr, elem_expr->size); | 5642 | expr = nft_setelem_expr_at(elem_expr, elem_expr->size); |
| 5597 | err = nft_expr_clone(expr, expr_array[i]); | 5643 | err = nft_expr_clone(expr, expr_array[i]); |
| @@ -6054,17 +6100,23 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, · 456 unmodified lines |
| 6054 | } | 6100 | } |
| 6055 | } | 6101 | } |
| 6056 | | 6102 | |
| 6057 | err = -ENOMEM; | | |
| 6058 | elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, | 6103 | elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, |
| 6059 | elem.key_end.val.data, elem.data.val.data, | 6104 | elem.key_end.val.data, elem.data.val.data, |
| 6060 | timeout, expiration, GFP_KERNEL_ACCOUNT); | 6105 | timeout, expiration, GFP_KERNEL_ACCOUNT); |
| 6061 | if (elem.priv == NULL) | 6106 | if (IS_ERR(elem.priv)) { |
| | 6107 | err = PTR_ERR(elem.priv); |
| 6062 | goto err_parse_data; | 6108 | goto err_parse_data; |
| | 6109 | } |
| 6063 | | 6110 | |
| 6064 | ext = nft_set_elem_ext(set, elem.priv); | 6111 | ext = nft_set_elem_ext(set, elem.priv); |
| 6065 | if (flags) | 6112 | if (flags) |
| 6066 | *nft_set_ext_flags(ext) = flags; | 6113 | *nft_set_ext_flags(ext) = flags; |
| | 6114 | |
| 6067 | if (ulen > 0) { | 6115 | if (ulen > 0) { |
| | 6116 | if (nft_set_ext_check(&tmpl, NFT_SET_EXT_USERDATA, ulen) < 0) { |
| | 6117 | err = -EINVAL; |
| | 6118 | goto err_elem_userdata; |
| | 6119 | } |
| 6068 | udata = nft_set_ext_userdata(ext); | 6120 | udata = nft_set_ext_userdata(ext); |
| 6069 | udata->len = ulen - 1; | 6121 | udata->len = ulen - 1; |
| 6070 | nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen); | 6122 | nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen); |
| @@ -6073,14 +6125,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, · 2 unmodified lines |
| 6073 | *nft_set_ext_obj(ext) = obj; | 6125 | *nft_set_ext_obj(ext) = obj; |
| 6074 | obj->use++; | 6126 | obj->use++; |
| 6075 | } | 6127 | } |
| 6076 | err = nft_set_elem_expr_setup(ctx, ext, expr_array, num_exprs); | 6128 | err = nft_set_elem_expr_setup(ctx, &tmpl, ext, expr_array, num_exprs); |
| 6077 | if (err < 0) | 6129 | if (err < 0) |
| 6078 | goto err_elem_expr; | 6130 | goto err_elem_free; |
| 6079 | | 6131 | |
| 6080 | trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set); | 6132 | trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set); |
| 6081 | if (trans == NULL) { | 6133 | if (trans == NULL) { |
| 6082 | err = -ENOMEM; | 6134 | err = -ENOMEM; |
| 6083 | goto err_elem_expr; | 6135 | goto err_elem_free; |
| 6084 | } | 6136 | } |
| 6085 | | 6137 | |
| 6086 | ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK; | 6138 | ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK; |
| @@ -6126,10 +6178,10 @@ err_set_full: · 39 unmodified lines |
| 6126 | nft_setelem_remove(ctx->net, set, &elem); | 6178 | nft_setelem_remove(ctx->net, set, &elem); |
| 6127 | err_element_clash: | 6179 | err_element_clash: |
| 6128 | kfree(trans); | 6180 | kfree(trans); |
| 6129 | err_elem_expr: | 6181 | err_elem_free: |
| 6130 | if (obj) | 6182 | if (obj) |
| 6131 | obj->use--; | 6183 | obj->use--; |
| 6132 | | 6184 | err_elem_userdata: |
| 6133 | nf_tables_set_elem_destroy(ctx, set, elem.priv); | 6185 | nf_tables_set_elem_destroy(ctx, set, elem.priv); |
| 6134 | err_parse_data: | 6186 | err_parse_data: |
| 6135 | if (nla[NFTA_SET_ELEM_DATA] != NULL) | 6187 | if (nla[NFTA_SET_ELEM_DATA] != NULL) |
| @@ -6311,8 +6363,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, · 175 unmodified lines |
| 6311 | elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, | 6363 | elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, |
| 6312 | elem.key_end.val.data, NULL, 0, 0, | 6364 | elem.key_end.val.data, NULL, 0, 0, |
| 6313 | GFP_KERNEL_ACCOUNT); | 6365 | GFP_KERNEL_ACCOUNT); |
| 6314 | if (elem.priv == NULL) | 6366 | if (IS_ERR(elem.priv)) { |
| | 6367 | err = PTR_ERR(elem.priv); |
| 6315 | goto fail_elem_key_end; | 6368 | goto fail_elem_key_end; |
| | 6369 | } |
| 6316 | | 6370 | |
| 6317 | ext = nft_set_elem_ext(set, elem.priv); | 6371 | ext = nft_set_elem_ext(set, elem.priv); |
| 6318 | if (flags) | 6372 | if (flags) |