| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* xfrm_user.c: User interface to configure xfrm engine. |
|---|
| 2 | 3 | * |
|---|
| 3 | 4 | * Copyright (C) 2002 David S. Miller (davem@redhat.com) |
|---|
| .. | .. |
|---|
| 521 | 522 | struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; |
|---|
| 522 | 523 | struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; |
|---|
| 523 | 524 | |
|---|
| 524 | | - if (re) { |
|---|
| 525 | + if (re && x->replay_esn && x->preplay_esn) { |
|---|
| 525 | 526 | struct xfrm_replay_state_esn *replay_esn; |
|---|
| 526 | 527 | replay_esn = nla_data(re); |
|---|
| 527 | 528 | memcpy(x->replay_esn, replay_esn, |
|---|
| .. | .. |
|---|
| 620 | 621 | |
|---|
| 621 | 622 | xfrm_smark_init(attrs, &x->props.smark); |
|---|
| 622 | 623 | |
|---|
| 623 | | - if (attrs[XFRMA_IF_ID]) { |
|---|
| 624 | + if (attrs[XFRMA_IF_ID]) |
|---|
| 624 | 625 | x->if_id = nla_get_u32(attrs[XFRMA_IF_ID]); |
|---|
| 625 | | - if (!x->if_id) { |
|---|
| 626 | | - err = -EINVAL; |
|---|
| 627 | | - goto error; |
|---|
| 628 | | - } |
|---|
| 629 | | - } |
|---|
| 630 | 626 | |
|---|
| 631 | 627 | err = __xfrm_init_state(x, false, attrs[XFRMA_OFFLOAD_DEV]); |
|---|
| 632 | 628 | if (err) |
|---|
| .. | .. |
|---|
| 1043 | 1039 | u8 proto = 0; |
|---|
| 1044 | 1040 | int err; |
|---|
| 1045 | 1041 | |
|---|
| 1046 | | - err = nlmsg_parse(cb->nlh, 0, attrs, XFRMA_MAX, xfrma_policy, |
|---|
| 1047 | | - NULL); |
|---|
| 1042 | + err = nlmsg_parse_deprecated(cb->nlh, 0, attrs, XFRMA_MAX, |
|---|
| 1043 | + xfrma_policy, cb->extack); |
|---|
| 1048 | 1044 | if (err < 0) |
|---|
| 1049 | 1045 | return err; |
|---|
| 1050 | 1046 | |
|---|
| .. | .. |
|---|
| 1053 | 1049 | sizeof(*filter), GFP_KERNEL); |
|---|
| 1054 | 1050 | if (filter == NULL) |
|---|
| 1055 | 1051 | return -ENOMEM; |
|---|
| 1052 | + |
|---|
| 1053 | + /* see addr_match(), (prefix length >> 5) << 2 |
|---|
| 1054 | + * will be used to compare xfrm_address_t |
|---|
| 1055 | + */ |
|---|
| 1056 | + if (filter->splen > (sizeof(xfrm_address_t) << 3) || |
|---|
| 1057 | + filter->dplen > (sizeof(xfrm_address_t) << 3)) { |
|---|
| 1058 | + kfree(filter); |
|---|
| 1059 | + return -EINVAL; |
|---|
| 1060 | + } |
|---|
| 1056 | 1061 | } |
|---|
| 1057 | 1062 | |
|---|
| 1058 | 1063 | if (attrs[XFRMA_PROTO]) |
|---|
| .. | .. |
|---|
| 1357 | 1362 | |
|---|
| 1358 | 1363 | mark = xfrm_mark_get(attrs, &m); |
|---|
| 1359 | 1364 | |
|---|
| 1360 | | - if (attrs[XFRMA_IF_ID]) { |
|---|
| 1365 | + if (attrs[XFRMA_IF_ID]) |
|---|
| 1361 | 1366 | if_id = nla_get_u32(attrs[XFRMA_IF_ID]); |
|---|
| 1362 | | - if (!if_id) { |
|---|
| 1363 | | - err = -EINVAL; |
|---|
| 1364 | | - goto out_noput; |
|---|
| 1365 | | - } |
|---|
| 1366 | | - } |
|---|
| 1367 | 1367 | |
|---|
| 1368 | 1368 | if (p->info.seq) { |
|---|
| 1369 | 1369 | x = xfrm_find_acq_byseq(net, mark, p->info.seq); |
|---|
| .. | .. |
|---|
| 1676 | 1676 | |
|---|
| 1677 | 1677 | xfrm_mark_get(attrs, &xp->mark); |
|---|
| 1678 | 1678 | |
|---|
| 1679 | | - if (attrs[XFRMA_IF_ID]) { |
|---|
| 1679 | + if (attrs[XFRMA_IF_ID]) |
|---|
| 1680 | 1680 | xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]); |
|---|
| 1681 | | - if (!xp->if_id) { |
|---|
| 1682 | | - err = -EINVAL; |
|---|
| 1683 | | - goto error; |
|---|
| 1684 | | - } |
|---|
| 1685 | | - } |
|---|
| 1686 | 1681 | |
|---|
| 1687 | 1682 | return xp; |
|---|
| 1688 | 1683 | error: |
|---|
| .. | .. |
|---|
| 1926 | 1921 | struct km_event c; |
|---|
| 1927 | 1922 | int delete; |
|---|
| 1928 | 1923 | struct xfrm_mark m; |
|---|
| 1929 | | - u32 mark = xfrm_mark_get(attrs, &m); |
|---|
| 1930 | 1924 | u32 if_id = 0; |
|---|
| 1931 | 1925 | |
|---|
| 1932 | 1926 | p = nlmsg_data(nlh); |
|---|
| .. | .. |
|---|
| 1943 | 1937 | if (attrs[XFRMA_IF_ID]) |
|---|
| 1944 | 1938 | if_id = nla_get_u32(attrs[XFRMA_IF_ID]); |
|---|
| 1945 | 1939 | |
|---|
| 1940 | + xfrm_mark_get(attrs, &m); |
|---|
| 1941 | + |
|---|
| 1946 | 1942 | if (p->index) |
|---|
| 1947 | | - xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, delete, &err); |
|---|
| 1943 | + xp = xfrm_policy_byid(net, &m, if_id, type, p->dir, |
|---|
| 1944 | + p->index, delete, &err); |
|---|
| 1948 | 1945 | else { |
|---|
| 1949 | 1946 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
|---|
| 1950 | 1947 | struct xfrm_sec_ctx *ctx; |
|---|
| .. | .. |
|---|
| 1961 | 1958 | if (err) |
|---|
| 1962 | 1959 | return err; |
|---|
| 1963 | 1960 | } |
|---|
| 1964 | | - xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir, &p->sel, |
|---|
| 1965 | | - ctx, delete, &err); |
|---|
| 1961 | + xp = xfrm_policy_bysel_ctx(net, &m, if_id, type, p->dir, |
|---|
| 1962 | + &p->sel, ctx, delete, &err); |
|---|
| 1966 | 1963 | security_xfrm_policy_free(ctx); |
|---|
| 1967 | 1964 | } |
|---|
| 1968 | 1965 | if (xp == NULL) |
|---|
| .. | .. |
|---|
| 2229 | 2226 | u8 type = XFRM_POLICY_TYPE_MAIN; |
|---|
| 2230 | 2227 | int err = -ENOENT; |
|---|
| 2231 | 2228 | struct xfrm_mark m; |
|---|
| 2232 | | - u32 mark = xfrm_mark_get(attrs, &m); |
|---|
| 2233 | 2229 | u32 if_id = 0; |
|---|
| 2234 | 2230 | |
|---|
| 2235 | 2231 | err = copy_from_user_policy_type(&type, attrs); |
|---|
| .. | .. |
|---|
| 2243 | 2239 | if (attrs[XFRMA_IF_ID]) |
|---|
| 2244 | 2240 | if_id = nla_get_u32(attrs[XFRMA_IF_ID]); |
|---|
| 2245 | 2241 | |
|---|
| 2242 | + xfrm_mark_get(attrs, &m); |
|---|
| 2243 | + |
|---|
| 2246 | 2244 | if (p->index) |
|---|
| 2247 | | - xp = xfrm_policy_byid(net, mark, if_id, type, p->dir, p->index, 0, &err); |
|---|
| 2245 | + xp = xfrm_policy_byid(net, &m, if_id, type, p->dir, p->index, |
|---|
| 2246 | + 0, &err); |
|---|
| 2248 | 2247 | else { |
|---|
| 2249 | 2248 | struct nlattr *rt = attrs[XFRMA_SEC_CTX]; |
|---|
| 2250 | 2249 | struct xfrm_sec_ctx *ctx; |
|---|
| .. | .. |
|---|
| 2261 | 2260 | if (err) |
|---|
| 2262 | 2261 | return err; |
|---|
| 2263 | 2262 | } |
|---|
| 2264 | | - xp = xfrm_policy_bysel_ctx(net, mark, if_id, type, p->dir, |
|---|
| 2263 | + xp = xfrm_policy_bysel_ctx(net, &m, if_id, type, p->dir, |
|---|
| 2265 | 2264 | &p->sel, ctx, 0, &err); |
|---|
| 2266 | 2265 | security_xfrm_policy_free(ctx); |
|---|
| 2267 | 2266 | } |
|---|
| .. | .. |
|---|
| 2433 | 2432 | int n = 0; |
|---|
| 2434 | 2433 | struct net *net = sock_net(skb->sk); |
|---|
| 2435 | 2434 | struct xfrm_encap_tmpl *encap = NULL; |
|---|
| 2435 | + u32 if_id = 0; |
|---|
| 2436 | 2436 | |
|---|
| 2437 | 2437 | if (attrs[XFRMA_MIGRATE] == NULL) |
|---|
| 2438 | 2438 | return -EINVAL; |
|---|
| .. | .. |
|---|
| 2457 | 2457 | return 0; |
|---|
| 2458 | 2458 | } |
|---|
| 2459 | 2459 | |
|---|
| 2460 | | - err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap); |
|---|
| 2460 | + if (attrs[XFRMA_IF_ID]) |
|---|
| 2461 | + if_id = nla_get_u32(attrs[XFRMA_IF_ID]); |
|---|
| 2462 | + |
|---|
| 2463 | + err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap, if_id); |
|---|
| 2461 | 2464 | |
|---|
| 2462 | 2465 | kfree(encap); |
|---|
| 2463 | 2466 | |
|---|
| .. | .. |
|---|
| 2630 | 2633 | [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, |
|---|
| 2631 | 2634 | [XFRMA_ENCAP] = { .len = sizeof(struct xfrm_encap_tmpl) }, |
|---|
| 2632 | 2635 | [XFRMA_TMPL] = { .len = sizeof(struct xfrm_user_tmpl) }, |
|---|
| 2633 | | - [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_sec_ctx) }, |
|---|
| 2636 | + [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_user_sec_ctx) }, |
|---|
| 2634 | 2637 | [XFRMA_LTIME_VAL] = { .len = sizeof(struct xfrm_lifetime_cur) }, |
|---|
| 2635 | 2638 | [XFRMA_REPLAY_VAL] = { .len = sizeof(struct xfrm_replay_state) }, |
|---|
| 2636 | 2639 | [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 }, |
|---|
| .. | .. |
|---|
| 2751 | 2754 | goto err; |
|---|
| 2752 | 2755 | } |
|---|
| 2753 | 2756 | |
|---|
| 2754 | | - err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, |
|---|
| 2755 | | - link->nla_max ? : XFRMA_MAX, |
|---|
| 2756 | | - link->nla_pol ? : xfrma_policy, extack); |
|---|
| 2757 | + err = nlmsg_parse_deprecated(nlh, xfrm_msg_min[type], attrs, |
|---|
| 2758 | + link->nla_max ? : XFRMA_MAX, |
|---|
| 2759 | + link->nla_pol ? : xfrma_policy, extack); |
|---|
| 2757 | 2760 | if (err < 0) |
|---|
| 2758 | 2761 | goto err; |
|---|
| 2759 | 2762 | |
|---|
| .. | .. |
|---|
| 2764 | 2767 | |
|---|
| 2765 | 2768 | err = link->doit(skb, nlh, attrs); |
|---|
| 2766 | 2769 | |
|---|
| 2770 | + /* We need to free skb allocated in xfrm_alloc_compat() before |
|---|
| 2771 | + * returning from this function, because consume_skb() won't take |
|---|
| 2772 | + * care of frag_list since netlink destructor sets |
|---|
| 2773 | + * sbk->head to NULL. (see netlink_skb_destructor()) |
|---|
| 2774 | + */ |
|---|
| 2775 | + if (skb_has_frag_list(skb)) { |
|---|
| 2776 | + kfree_skb(skb_shinfo(skb)->frag_list); |
|---|
| 2777 | + skb_shinfo(skb)->frag_list = NULL; |
|---|
| 2778 | + } |
|---|
| 2779 | + |
|---|
| 2767 | 2780 | err: |
|---|
| 2768 | 2781 | kvfree(nlh64); |
|---|
| 2769 | 2782 | return err; |
|---|