Re: [PATCH net] ipvs: prevent integer overflow in do_ip_vs_get_ctl()

Julian Anastasov <[email protected]>
Newsgroups org.kernel.vger.lvs-devel,org.kernel.vger.kernel-janitors,org.kernel.vger.linux-kernel,org.kernel.vger.netdev,org.kernel.vger.netfilter-devel
Message-ID <[email protected]>
	Hello,

On Fri, 7 Mar 2025, Dan Carpenter wrote:

> The get->num_services variable is an unsigned int which is controlled by
> the user.  The struct_size() function ensures that the size calculation
> does not overflow an unsigned long, however, we are saving the result to
> an int so the calculation can overflow.
> 
> Save the result from struct_size() type size_t to fix this integer
> overflow bug.
> 
> Cc: [email protected]
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Signed-off-by: Dan Carpenter <[email protected]>
> ---
>  net/netfilter/ipvs/ip_vs_ctl.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
> index 7d13110ce188..801d65fd8a81 100644
> --- a/net/netfilter/ipvs/ip_vs_ctl.c
> +++ b/net/netfilter/ipvs/ip_vs_ctl.c
> @@ -3091,12 +3091,12 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
>  	case IP_VS_SO_GET_SERVICES:
>  	{
>  		struct ip_vs_get_services *get;
> -		int size;
> +		size_t size;
>  
>  		get = (struct ip_vs_get_services *)arg;
>  		size = struct_size(get, entrytable, get->num_services);

	Both are GET operations. The problem that can happen only
on 64-bit platforms is that user will attempt copy_to_user() with
shorter buffer and will get EFAULT if there are so many entries to
return. On 32-bit size will be -1 and will not match *len (EINVAL).
So, I assume the issue is not critical, right?

>  		if (*len != size) {
> -			pr_err("length: %u != %u\n", *len, size);
> +			pr_err("length: %u != %lu\n", *len, size);

	%zu, %lu fails on 32-bit platforms. Please, send v2
fixing the format.

>  			ret = -EINVAL;
>  			goto out;
>  		}
> @@ -3132,12 +3132,12 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
>  	case IP_VS_SO_GET_DESTS:
>  	{
>  		struct ip_vs_get_dests *get;
> -		int size;
> +		size_t size;
>  
>  		get = (struct ip_vs_get_dests *)arg;
>  		size = struct_size(get, entrytable, get->num_dests);
>  		if (*len != size) {
> -			pr_err("length: %u != %u\n", *len, size);
> +			pr_err("length: %u != %lu\n", *len, size);
>  			ret = -EINVAL;
>  			goto out;
>  		}
> -- 
> 2.47.2

Regards

--
Julian Anastasov <[email protected]>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.