Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dmitry Safonov and committed by
Steffen Klassert
96392ee5 5106f4a8

+43 -3
+3
include/net/xfrm.h
··· 2012 2012 int maxtype, const struct nla_policy *policy, 2013 2013 struct netlink_ext_ack *extack); 2014 2014 2015 + /* Translate 32-bit user_policy from sockptr */ 2016 + int (*xlate_user_policy_sockptr)(u8 **pdata32, int optlen); 2017 + 2015 2018 struct module *owner; 2016 2019 }; 2017 2020
+26
net/xfrm/xfrm_compat.c
··· 576 576 return h64; 577 577 } 578 578 579 + static int xfrm_user_policy_compat(u8 **pdata32, int optlen) 580 + { 581 + struct compat_xfrm_userpolicy_info *p = (void *)*pdata32; 582 + u8 *src_templates, *dst_templates; 583 + u8 *data64; 584 + 585 + if (optlen < sizeof(*p)) 586 + return -EINVAL; 587 + 588 + data64 = kmalloc_track_caller(optlen + 4, GFP_USER | __GFP_NOWARN); 589 + if (!data64) 590 + return -ENOMEM; 591 + 592 + memcpy(data64, *pdata32, sizeof(*p)); 593 + memset(data64 + sizeof(*p), 0, 4); 594 + 595 + src_templates = *pdata32 + sizeof(*p); 596 + dst_templates = data64 + sizeof(*p) + 4; 597 + memcpy(dst_templates, src_templates, optlen - sizeof(*p)); 598 + 599 + kfree(*pdata32); 600 + *pdata32 = data64; 601 + return 0; 602 + } 603 + 579 604 static struct xfrm_translator xfrm_translator = { 580 605 .owner = THIS_MODULE, 581 606 .alloc_compat = xfrm_alloc_compat, 582 607 .rcv_msg_compat = xfrm_user_rcv_msg_compat, 608 + .xlate_user_policy_sockptr = xfrm_user_policy_compat, 583 609 }; 584 610 585 611 static int __init xfrm_compat_init(void)
+14 -3
net/xfrm/xfrm_state.c
··· 2331 2331 struct xfrm_mgr *km; 2332 2332 struct xfrm_policy *pol = NULL; 2333 2333 2334 - if (in_compat_syscall()) 2335 - return -EOPNOTSUPP; 2336 - 2337 2334 if (sockptr_is_null(optval) && !optlen) { 2338 2335 xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); 2339 2336 xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); ··· 2344 2347 data = memdup_sockptr(optval, optlen); 2345 2348 if (IS_ERR(data)) 2346 2349 return PTR_ERR(data); 2350 + 2351 + if (in_compat_syscall()) { 2352 + struct xfrm_translator *xtr = xfrm_get_translator(); 2353 + 2354 + if (!xtr) 2355 + return -EOPNOTSUPP; 2356 + 2357 + err = xtr->xlate_user_policy_sockptr(&data, optlen); 2358 + xfrm_put_translator(xtr); 2359 + if (err) { 2360 + kfree(data); 2361 + return err; 2362 + } 2363 + } 2347 2364 2348 2365 err = -EINVAL; 2349 2366 rcu_read_lock();