Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit a0436b5e authored by Dmitry Safonov's avatar Dmitry Safonov Committed by derfelot
Browse files

BACKPORT: xfrm/compat: Translate 32-bit user_policy from sockptr



Provide compat_xfrm_userpolicy_info translation for xfrm setsocketopt().
Reallocate buffer and put the missing padding for 64-bit message.

Signed-off-by: default avatarDmitry Safonov <dima@arista.com>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
(cherry picked from commit 96392ee5a13b992563cfe07d23ee30d333b89126)
[adelva: Edited around removed compat check in Android kernels]
Bug: 163141236
Signed-off-by: default avatarAlistair Delva <adelva@google.com>
Change-Id: I32a6495cd92fa13c956fca88aa5d80716155b8ae
parent 874ba013
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1837,6 +1837,9 @@ struct xfrm_translator {
	struct nlmsghdr *(*rcv_msg_compat)(const struct nlmsghdr *nlh,
			int maxtype, const struct nla_policy *policy);

	/* Translate 32-bit user_policy from sockptr */
	int (*xlate_user_policy_sockptr)(u8 **pdata32, int optlen);

	struct module *owner;
};

+26 −0
Original line number Diff line number Diff line
@@ -636,10 +636,36 @@ static struct nlmsghdr *xfrm_user_rcv_msg_compat(const struct nlmsghdr *h32,
	return h64;
}

static int xfrm_user_policy_compat(u8 **pdata32, int optlen)
{
	struct compat_xfrm_userpolicy_info *p = (void *)*pdata32;
	u8 *src_templates, *dst_templates;
	u8 *data64;

	if (optlen < sizeof(*p))
		return -EINVAL;

	data64 = kmalloc_track_caller(optlen + 4, GFP_USER | __GFP_NOWARN);
	if (!data64)
		return -ENOMEM;

	memcpy(data64, *pdata32, sizeof(*p));
	memset(data64 + sizeof(*p), 0, 4);

	src_templates = *pdata32 + sizeof(*p);
	dst_templates = data64 + sizeof(*p) + 4;
	memcpy(dst_templates, src_templates, optlen - sizeof(*p));

	kfree(*pdata32);
	*pdata32 = data64;
	return 0;
}

static struct xfrm_translator xfrm_translator = {
	.owner				= THIS_MODULE,
	.alloc_compat			= xfrm_alloc_compat,
	.rcv_msg_compat			= xfrm_user_rcv_msg_compat,
	.xlate_user_policy_sockptr	= xfrm_user_policy_compat,
};

static int __init xfrm_compat_init(void)
+14 −0
Original line number Diff line number Diff line
@@ -1939,6 +1939,20 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
	if (copy_from_user(data, optval, optlen))
		goto out;

	if (is_compat_task()) {
		struct xfrm_translator *xtr = xfrm_get_translator();

		if (!xtr)
			return -EOPNOTSUPP;

		err = xtr->xlate_user_policy_sockptr(&data, optlen);
		xfrm_put_translator(xtr);
		if (err) {
			kfree(data);
			return err;
		}
	}

	err = -EINVAL;
	rcu_read_lock();
	list_for_each_entry_rcu(km, &xfrm_km_list, list) {