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: Dmitry Safonov <dima@arista.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
parent
5106f4a8ac
commit
96392ee5a1
3 changed files with 43 additions and 3 deletions
|
@ -2012,6 +2012,9 @@ struct xfrm_translator {
|
||||||
int maxtype, const struct nla_policy *policy,
|
int maxtype, const struct nla_policy *policy,
|
||||||
struct netlink_ext_ack *extack);
|
struct netlink_ext_ack *extack);
|
||||||
|
|
||||||
|
/* Translate 32-bit user_policy from sockptr */
|
||||||
|
int (*xlate_user_policy_sockptr)(u8 **pdata32, int optlen);
|
||||||
|
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -576,10 +576,36 @@ static struct nlmsghdr *xfrm_user_rcv_msg_compat(const struct nlmsghdr *h32,
|
||||||
return h64;
|
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 = {
|
static struct xfrm_translator xfrm_translator = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.alloc_compat = xfrm_alloc_compat,
|
.alloc_compat = xfrm_alloc_compat,
|
||||||
.rcv_msg_compat = xfrm_user_rcv_msg_compat,
|
.rcv_msg_compat = xfrm_user_rcv_msg_compat,
|
||||||
|
.xlate_user_policy_sockptr = xfrm_user_policy_compat,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init xfrm_compat_init(void)
|
static int __init xfrm_compat_init(void)
|
||||||
|
|
|
@ -2331,9 +2331,6 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
|
||||||
struct xfrm_mgr *km;
|
struct xfrm_mgr *km;
|
||||||
struct xfrm_policy *pol = NULL;
|
struct xfrm_policy *pol = NULL;
|
||||||
|
|
||||||
if (in_compat_syscall())
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
|
|
||||||
if (sockptr_is_null(optval) && !optlen) {
|
if (sockptr_is_null(optval) && !optlen) {
|
||||||
xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
|
xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
|
||||||
xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
|
xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
|
||||||
|
@ -2348,6 +2345,20 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen)
|
||||||
if (IS_ERR(data))
|
if (IS_ERR(data))
|
||||||
return PTR_ERR(data);
|
return PTR_ERR(data);
|
||||||
|
|
||||||
|
if (in_compat_syscall()) {
|
||||||
|
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;
|
err = -EINVAL;
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
list_for_each_entry_rcu(km, &xfrm_km_list, list) {
|
list_for_each_entry_rcu(km, &xfrm_km_list, list) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue