Commit 5f3eea6b authored by Dmitry Safonov's avatar Dmitry Safonov Committed by Steffen Klassert
Browse files

xfrm/compat: Attach xfrm dumps to 64=>32 bit translator



Currently nlmsg_unicast() is used by functions that dump structures that
can be different in size for compat tasks, see dump_one_state() and
dump_one_policy().

The following nlmsg_unicast() users exist today in xfrm:

         Function                          |    Message can be different
                                           |       in size on compat
-------------------------------------------|------------------------------
    xfrm_get_spdinfo()                     |               N
    xfrm_get_sadinfo()                     |               N
    xfrm_get_sa()                          |               Y
    xfrm_alloc_userspi()                   |               Y
    xfrm_get_policy()                      |               Y
    xfrm_get_ae()                          |               N

Besides, dump_one_state() and dump_one_policy() can be used by filtered
netlink dump for XFRM_MSG_GETSA, XFRM_MSG_GETPOLICY.

Just as for xfrm multicast, allocate frag_list for compat skb journey
down to recvmsg() which will give user the desired skb according to
syscall bitness.

Signed-off-by: default avatarDmitry Safonov <dima@arista.com>

Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 5461fc0c
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -975,6 +975,7 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
	struct xfrm_dump_info *sp = ptr;
	struct sk_buff *in_skb = sp->in_skb;
	struct sk_buff *skb = sp->out_skb;
	struct xfrm_translator *xtr;
	struct xfrm_usersa_info *p;
	struct nlmsghdr *nlh;
	int err;
@@ -992,6 +993,18 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
		return err;
	}
	nlmsg_end(skb, nlh);

	xtr = xfrm_get_translator();
	if (xtr) {
		err = xtr->alloc_compat(skb, nlh);

		xfrm_put_translator(xtr);
		if (err) {
			nlmsg_cancel(skb, nlh);
			return err;
		}
	}

	return 0;
}

@@ -1320,6 +1333,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
	struct net *net = sock_net(skb->sk);
	struct xfrm_state *x;
	struct xfrm_userspi_info *p;
	struct xfrm_translator *xtr;
	struct sk_buff *resp_skb;
	xfrm_address_t *daddr;
	int family;
@@ -1370,6 +1384,17 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,
		goto out;
	}

	xtr = xfrm_get_translator();
	if (xtr) {
		err = xtr->alloc_compat(skb, nlmsg_hdr(skb));

		xfrm_put_translator(xtr);
		if (err) {
			kfree_skb(resp_skb);
			goto out;
		}
	}

	err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).portid);

out:
@@ -1776,6 +1801,7 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
	struct xfrm_userpolicy_info *p;
	struct sk_buff *in_skb = sp->in_skb;
	struct sk_buff *skb = sp->out_skb;
	struct xfrm_translator *xtr;
	struct nlmsghdr *nlh;
	int err;

@@ -1800,6 +1826,18 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr
		return err;
	}
	nlmsg_end(skb, nlh);

	xtr = xfrm_get_translator();
	if (xtr) {
		err = xtr->alloc_compat(skb, nlh);

		xfrm_put_translator(xtr);
		if (err) {
			nlmsg_cancel(skb, nlh);
			return err;
		}
	}

	return 0;
}