forked from mirrors/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>
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…
	
		Reference in a new issue