| @@ -5467,6 +5467,27 @@ err_set_elem_expr: · 5466 unmodified lines |
| 5467 | 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 | 5491 | void *nft_set_elem_init(const struct nft_set *set, |
| 5471 | 5492 | const struct nft_set_ext_tmpl *tmpl, |
| 5472 | 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 | 5499 | elem = kzalloc(set->ops->elemsize + tmpl->len, gfp); |
| 5479 | 5500 | if (elem == NULL) |
| 5480 | | − return NULL; |
| 5501 | + return ERR_PTR(-ENOMEM); |
| 5481 | 5502 | |
| 5482 | 5503 | ext = nft_set_elem_ext(set, elem); |
| 5483 | 5504 | nft_set_ext_init(ext, tmpl); |
| 5484 | 5505 | |
| 5485 | | − if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY)) |
| 5486 | | − memcpy(nft_set_ext_key(ext), key, set->klen); |
| 5487 | | − if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END)) |
| 5488 | | − memcpy(nft_set_ext_key_end(ext), key_end, set->klen); |
| 5489 | | − if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) |
| 5490 | | − memcpy(nft_set_ext_data(ext), data, set->dlen); |
| 5506 | + if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY) && |
| 5507 | + nft_set_ext_memcpy(tmpl, NFT_SET_EXT_KEY, |
| 5508 | + nft_set_ext_key(ext), key, set->klen) < 0) |
| 5509 | + goto err_ext_check; |
| 5510 | + |
| 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 | 5521 | if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { |
| 5492 | 5522 | *nft_set_ext_expiration(ext) = get_jiffies_64() + expiration; |
| 5493 | 5523 | if (expiration == 0) |
| @@ -5497,6 +5527,11 @@ void *nft_set_elem_init(const struct nft_set *set, · 3 unmodified lines |
| 5497 | 5527 | *nft_set_ext_timeout(ext) = timeout; |
| 5498 | 5528 | |
| 5499 | 5529 | return elem; |
| 5530 | + |
| 5531 | +err_ext_check: |
| 5532 | + kfree(elem); |
| 5533 | + |
| 5534 | + return ERR_PTR(-EINVAL); |
| 5500 | 5535 | } |
| 5501 | 5536 | |
| 5502 | 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 | 5621 | static int nft_set_elem_expr_setup(struct nft_ctx *ctx, |
| 5622 | + const struct nft_set_ext_tmpl *tmpl, |
| 5587 | 5623 | const struct nft_set_ext *ext, |
| 5588 | 5624 | struct nft_expr *expr_array[], |
| 5589 | 5625 | u32 num_exprs) |
| 5590 | 5626 | { |
| 5591 | 5627 | struct nft_set_elem_expr *elem_expr = nft_set_ext_expr(ext); |
| 5628 | + u32 len = sizeof(struct nft_set_elem_expr); |
| 5592 | 5629 | struct nft_expr *expr; |
| 5593 | 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 | 5641 | for (i = 0; i < num_exprs; i++) { |
| 5596 | 5642 | expr = nft_setelem_expr_at(elem_expr, elem_expr->size); |
| 5597 | 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 | 6103 | elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, |
| 6059 | 6104 | elem.key_end.val.data, elem.data.val.data, |
| 6060 | 6105 | timeout, expiration, GFP_KERNEL_ACCOUNT); |
| 6061 | | − if (elem.priv == NULL) |
| 6106 | + if (IS_ERR(elem.priv)) { |
| 6107 | + err = PTR_ERR(elem.priv); |
| 6062 | 6108 | goto err_parse_data; |
| 6109 | + } |
| 6063 | 6110 | |
| 6064 | 6111 | ext = nft_set_elem_ext(set, elem.priv); |
| 6065 | 6112 | if (flags) |
| 6066 | 6113 | *nft_set_ext_flags(ext) = flags; |
| 6114 | + |
| 6067 | 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 | 6120 | udata = nft_set_ext_userdata(ext); |
| 6069 | 6121 | udata->len = ulen - 1; |
| 6070 | 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 | 6125 | *nft_set_ext_obj(ext) = obj; |
| 6074 | 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 | 6129 | if (err < 0) |
| 6078 | | − goto err_elem_expr; |
| 6130 | + goto err_elem_free; |
| 6079 | 6131 | |
| 6080 | 6132 | trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set); |
| 6081 | 6133 | if (trans == NULL) { |
| 6082 | 6134 | err = -ENOMEM; |
| 6083 | | − goto err_elem_expr; |
| 6135 | + goto err_elem_free; |
| 6084 | 6136 | } |
| 6085 | 6137 | |
| 6086 | 6138 | ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK; |
| @@ -6126,10 +6178,10 @@ err_set_full: · 39 unmodified lines |
| 6126 | 6178 | nft_setelem_remove(ctx->net, set, &elem); |
| 6127 | 6179 | err_element_clash: |
| 6128 | 6180 | kfree(trans); |
| 6129 | | −err_elem_expr: |
| 6181 | +err_elem_free: |
| 6130 | 6182 | if (obj) |
| 6131 | 6183 | obj->use--; |
| 6132 | | − |
| 6184 | +err_elem_userdata: |
| 6133 | 6185 | nf_tables_set_elem_destroy(ctx, set, elem.priv); |
| 6134 | 6186 | err_parse_data: |
| 6135 | 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 | 6363 | elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, |
| 6312 | 6364 | elem.key_end.val.data, NULL, 0, 0, |
| 6313 | 6365 | GFP_KERNEL_ACCOUNT); |
| 6314 | | − if (elem.priv == NULL) |
| 6366 | + if (IS_ERR(elem.priv)) { |
| 6367 | + err = PTR_ERR(elem.priv); |
| 6315 | 6368 | goto fail_elem_key_end; |
| 6369 | + } |
| 6316 | 6370 | |
| 6317 | 6371 | ext = nft_set_elem_ext(set, elem.priv); |
| 6318 | 6372 | if (flags) |