diff options
| author | Dmitry Safonov <dima@arista.com> | 2020-09-21 15:36:56 +0100 |
|---|---|---|
| committer | Alistair Delva <adelva@google.com> | 2020-11-02 16:37:31 +0000 |
| commit | 05de67ed2af314b5d1c5083b66c8b077628aaf52 (patch) | |
| tree | f9b16f770aa63efad5bf02bbfd7bb85d3a1076b2 /net | |
| parent | f0fee529f3b89d49e01e883c7c78e112ac8943b1 (diff) | |
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: Dmitry Safonov <dima@arista.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
(cherry picked from commit 96392ee5a13b992563cfe07d23ee30d333b89126)
[adelva: Edited around removed compat check in Android kernels]
Bug: 163141236
Signed-off-by: Alistair Delva <adelva@google.com>
Change-Id: I32a6495cd92fa13c956fca88aa5d80716155b8ae
Diffstat (limited to 'net')
| -rw-r--r-- | net/xfrm/xfrm_compat.c | 26 | ||||
| -rw-r--r-- | net/xfrm/xfrm_state.c | 14 |
2 files changed, 40 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_compat.c b/net/xfrm/xfrm_compat.c index fa168821c805..7158078a71f1 100644 --- a/net/xfrm/xfrm_compat.c +++ b/net/xfrm/xfrm_compat.c @@ -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) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 7558ed17dc65..4cbeee279840 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -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) { |
