lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4efbdd50-419f-f12c-2874-cfacabf5e052@infradead.org>
Date:   Wed, 25 Nov 2020 13:59:15 -0800
From:   Randy Dunlap <rdunlap@...radead.org>
To:     Michael Witten <mfwitten@...il.com>, sparclinux@...r.kernel.org,
        linux-kernel@...r.kernel.org
Subject: Re: [RFC] openprom: Fix 'opiocnextprop'; ensure integer conversions;
 use string size

On 9/4/20 12:40 PM, Michael Witten wrote:
> The following patch improves the quality and correctness of the openprom code.
> 
> I have neither a machine to test the result nor a toolchain to compile it, and
> that is why it is listed currently as an "RFC". Nonetheless, I believe those
> who do have these tools will find the proposed changes useful; I hope you will
> help me iterate this patch into something worthy of merging (or use it as the
> basis for your own changes).
> 
> Sincerely,
> Michael Witten
> 
> --8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<----8<--
> 
> This commit fixes or improves a conglomeration of related issues:
> 
>    * 'opiocnextprop()' was incorrectly implemented.
>    * Integer conversions were not checked.
>    * Faulty PROMs and users can leave out nul-termination
>    * The confusion of string lengths for string sizes.
> 
> OPIOCNEXTPROP
> =============
> 
> According to NetBSD's documentation, this ioctl is supposed to
> return a property's *name*. However, until this commit, it has
> returned a property's *value*; this commit implements the return
> of the name.
> 
> In addition, the 'op_buflen' field is now also updated, whereas
> before it was not.
> 
> Conversions
> ===========
> 
> There are a number of different integer types used throughout this
> code to represent the size of some buffer; this commit introduces
> some checks to help ensure that these conversions will succeed, or
> at least to help ensure that bad conversions will be handled in a
> meaningful way.
> 
> Nul-Termination
> ===============
> 
> Faulty PROMs
> ------------
> 
> The Sun/Oracle documentation says that when returning data via the
> user-supplied buffers, the data should be explicitly nul-terminated
> if the buffer size is larger than the size of the data, just in case
> a faulty PROM fails to include nul-termination properly.
> 
> In the "Sun" ioctls, this should already be handled, because the data
> structure in question is zeroed when allocated, but this commit also
> introduces some checks for this when the following kernel config is
> defined:
> 
>    CONFIG_DEBUG_KERNEL
> 
> One BSD ioctl was amended to include this automatic nul-termination:
> 
>    OPIOCGET
> 
> User Error
> ----------
> 
> It is perhaps worth noting that the following helper function
> was already being used to append a nul character to user data
> provided to the BSD ioctl implementations:
> 
>    copyin_string()
> 
> The BSD documentation for those ioctl functions does indeed
> refer to "counted" strings, which may mean that nul-termination
> is not required, so the behavior of copyin_string() is merely
> a defensive way to handle input that is not nul-terminated.
> Such defensive programming is maintained by this commit; in
> addition, where applicable, strlen() is used to determine a
> length, rather than relying on a user-supplied value.
> 
> String Size
> ===========
> 
> There is an important distinction to be made between the following:
> 
>    * A nul-terminated string's size
>    * A nul-terminated string's length
> 
> This commit tries to make this distinction as much as possible,
> and assumes that all strings are intended to be nul-terminated.
> The result is the following:
> 
>    * Sometimes a variable's name is simply changed (e.g., from
>      'len' to 'size').
> 
>    * Sometimes 'strlen()' is called rather than relying on
>      some buffer size.
> 
>    * Sometimes, there is the replacement of code that erroneously
>      uses string length rather than string size.
> 
> All together, these changes make the code more robust and correct.
> 
> Signed-off-by: Michael Witten <mfwitten@...il.com>
> ---
>   arch/sparc/include/asm/prom.h   |   2 +-
>   arch/sparc/kernel/prom_common.c |  14 +--
>   drivers/sbus/char/openprom.c    | 263 ++++++++++++++++++++++++++++------------
>   3 files changed, 194 insertions(+), 85 deletions(-)
> 
> diff --git a/arch/sparc/include/asm/prom.h b/arch/sparc/include/asm/prom.h
> index 587edb8b5a65..b523dab16877 100644
> --- a/arch/sparc/include/asm/prom.h
> +++ b/arch/sparc/include/asm/prom.h
> @@ -30,7 +30,7 @@ struct of_irq_controller {
>   };
>   
>   struct device_node *of_find_node_by_cpuid(int cpuid);
> -int of_set_property(struct device_node *node, const char *name, void *val, int len);
> +int of_set_property(struct device_node *node, const char *name, void *val, int size);
>   extern struct mutex of_set_property_mutex;
>   int of_getintprop_default(struct device_node *np,
>   			  const char *name,
> diff --git a/arch/sparc/kernel/prom_common.c b/arch/sparc/kernel/prom_common.c
> index c9ec70888a39..fbc96c6e554c 100644
> --- a/arch/sparc/kernel/prom_common.c
> +++ b/arch/sparc/kernel/prom_common.c
> @@ -34,10 +34,10 @@ EXPORT_SYMBOL(of_console_options);
>   int of_getintprop_default(struct device_node *np, const char *name, int def)
>   {
>   	struct property *prop;
> -	int len;
> +	int size;
>   
> -	prop = of_find_property(np, name, &len);
> -	if (!prop || len != 4)
> +	prop = of_find_property(np, name, &size);
> +	if (!prop || size != 4)
>   		return def;
>   
>   	return *(int *) prop->value;
> @@ -47,14 +47,14 @@ EXPORT_SYMBOL(of_getintprop_default);
>   DEFINE_MUTEX(of_set_property_mutex);
>   EXPORT_SYMBOL(of_set_property_mutex);
>   
> -int of_set_property(struct device_node *dp, const char *name, void *val, int len)
> +int of_set_property(struct device_node *dp, const char *name, void *val, int size)
>   {
>   	struct property **prevp;
>   	unsigned long flags;
>   	void *new_val;
>   	int err;
>   
> -	new_val = kmemdup(val, len, GFP_KERNEL);
> +	new_val = kmemdup(val, size, GFP_KERNEL);
>   	if (!new_val)
>   		return -ENOMEM;
>   
> @@ -70,12 +70,12 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
>   			void *old_val = prop->value;
>   			int ret;
>   
> -			ret = prom_setprop(dp->phandle, name, val, len);
> +			ret = prom_setprop(dp->phandle, name, val, size);
>   
>   			err = -EINVAL;
>   			if (ret >= 0) {
>   				prop->value = new_val;
> -				prop->length = len;
> +				prop->length = size;
>   
>   				if (OF_IS_DYNAMIC(prop))
>   					kfree(old_val);
> diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
> index 30b9751aad30..9bc2877aa09a 100644
> --- a/drivers/sbus/char/openprom.c
> +++ b/drivers/sbus/char/openprom.c
> @@ -16,6 +16,7 @@
>    */
>   
>   
> +#include <linux/limits.h>
>   #include <linux/module.h>
>   #include <linux/kernel.h>
>   #include <linux/errno.h>
> @@ -54,42 +55,76 @@ static struct device_node *options_node;
>    * Copy an openpromio structure into kernel space from user space.
>    * This routine does error checking to make sure that all memory
>    * accesses are within bounds. A pointer to the allocated openpromio
> - * structure will be placed in "*opp_p". Return value is the length
> - * of the user supplied buffer.
> + * structure will be placed in "*opp_p". The return value is the size
> + * of the user supplied buffer; the return value is negative on error.
>    */
> -static int copyin(struct openpromio __user *info, struct openpromio **opp_p)
> +static ssize_t copyin(struct openpromio __user *info, struct openpromio **opp_p)
>   {
> -	unsigned int bufsize;
> +	unsigned int oprom_size;
> +	size_t bufsize;
> +	ssize_t result;
>   
>   	if (!info || !opp_p)
>   		return -EFAULT;
>   
> -	if (get_user(bufsize, &info->oprom_size))
> +	if (get_user(oprom_size, &info->oprom_size))
>   		return -EFAULT;
>   
> -	if (bufsize == 0)
> +	if (oprom_size == 0)
>   		return -EINVAL;
>   
> +	static_assert(SIZE_MAX >= UINT_MAX);
> +
>   	/* If the bufsize is too large, just limit it.
>   	 * Fix from Jason Rappleye.
>   	 */
> -	if (bufsize > OPROMMAXPARAM)
> -		bufsize = OPROMMAXPARAM;
> +	#if UINT_MAX <= OPROMMAXPARAM
> +		bufsize = oprom_size;
> +	#else
> +		if (oprom_size <= OPROMMAXPARAM)
> +			bufsize =  oprom_size;
> +		else
> +			bufsize = OPROMMAXPARAM;
> +	#endif
> +
> +	#if CONFIG_DEBUG_KERNEL
> +		if (WARN_ON(bufsize > OPROMMAXPARAM))
> +			bufsize = OPROMMAXPARAM;
> +	#endif
> +
> +	#if OPROMMAXPARAM > SIZE_MAX/2
> +		if (bufsize > SIZE_MAX/2)
> +			return -EFAULT;
> +	#endif
> +
> +	result = (ssize_t)bufsize;
>   
> +	/* The buffer 'oprom_array' is often supposed to contain a
> +	 * nul-terminated string, but the user may have erroneously
> +	 * set 'oprom_size' to the length of that string rather than
> +	 * the size of that string; therefore, the '+ 1' essentially
> +	 * appends a nul character. Any code that expects a string
> +	 * to be nul-terminated must not trust the size returned by
> +	 * this function.
> +	 */
> +	static_assert(OPROMMAXPARAM <= SIZE_MAX - sizeof(int) - 1);
>   	if (!(*opp_p = kzalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
>   		return -ENOMEM;
>   
> +	static_assert(ULONG_MAX >= SIZE_MAX);
>   	if (copy_from_user(&(*opp_p)->oprom_array,
>   			   &info->oprom_array, bufsize)) {
>   		kfree(*opp_p);
>   		return -EFAULT;
>   	}
> -	return bufsize;
> +
> +	return result;
>   }
>   
> -static int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
> +static ssize_t getstrings(struct openpromio __user *info, struct openpromio **opp_p)
>   {
> -	int n, bufsize;
> +	int n;
> +	ssize_t bufsize;
>   	char c;
>   
>   	if (!info || !opp_p)
> @@ -98,9 +133,8 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
>   	if (!(*opp_p = kzalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL)))
>   		return -ENOMEM;
>   
> -	(*opp_p)->oprom_size = 0;
> -
> -	n = bufsize = 0;
> +	bufsize = n = 0;
> +	static_assert((SIZE_MAX/2) >= OPROMMAXPARAM);
>   	while ((n < 2) && (bufsize < OPROMMAXPARAM)) {
>   		if (get_user(c, &info->oprom_array[bufsize])) {
>   			kfree(*opp_p);
> @@ -120,69 +154,109 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
>   /*
>    * Copy an openpromio structure in kernel space back to user space.
>    */
> -static int copyout(void __user *info, struct openpromio *opp, int len)
> +static int copyout(void __user *info, struct openpromio *opp, const size_t size)
>   {
> -	if (copy_to_user(info, opp, len))
> +	static_assert(ULONG_MAX >= SIZE_MAX);
> +	if (copy_to_user(info, opp, size))
>   		return -EFAULT;
>   	return 0;
>   }
>   
> -static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
> +static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, const size_t bufsize)
>   {
>   	const void *pval;
> -	int len;
> +	int pval_size;
>   
>   	if (!dp ||
> -	    !(pval = of_get_property(dp, op->oprom_array, &len)) ||
> -	    len <= 0 || len > bufsize)
> +	    !(pval = of_get_property(dp, op->oprom_array, &pval_size)) ||
> +	    pval_size <= 0 || pval_size > bufsize) {
> +		#ifdef CONFIG_DEBUG_KERNEL
> +			if (WARN_ON(op->oprom_size))
> +				op->oprom_size = 0;
> +		#endif
>   		return copyout(argp, op, sizeof(int));
> +	}
> +
> +	op->oprom_size = pval_size;
> +	memcpy(op->oprom_array, pval, pval_size);
>   
> -	memcpy(op->oprom_array, pval, len);
> -	op->oprom_array[len] = '\0';
> -	op->oprom_size = len;
> +	#ifdef CONFIG_DEBUG_KERNEL
> +		// If the buffer is larger than needed, then
> +		// the contents should be nul-terminated in
> +		// case the PROM erroneously produces a string
> +		// that is not nul-terminated.
> +		if (pval_size < bufsize)
> +			char *const end = op->oprom_array + pval_size;
> +			if (WARN_ON(*end))
> +				*end = 0;
> +	#endif
>   
>   	return copyout(argp, op, sizeof(int) + bufsize);
>   }
>   
> -static int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
> +static int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, const size_t bufsize)
>   {
>   	struct property *prop;
> -	int len;
> +	size_t name_size;
> +	unsigned int uint_name_size;
>   
>   	if (!dp)
> -		return copyout(argp, op, sizeof(int));
> +		goto nothing;
> +
>   	if (op->oprom_array[0] == '\0') {
>   		prop = dp->properties;
> -		if (!prop)
> -			return copyout(argp, op, sizeof(int));
> -		len = strlen(prop->name);
>   	} else {
>   		prop = of_find_property(dp, op->oprom_array, NULL);
> +		if (prop)
> +			prop = prop->next;
> +	}
>   
> -		if (!prop ||
> -		    !prop->next ||
> -		    (len = strlen(prop->next->name)) + 1 > bufsize)
> -			return copyout(argp, op, sizeof(int));
> +	if (!prop)
> +		goto nothing;
>   
> -		prop = prop->next;
> -	}
> +	name_size = 1 + strlen(prop->name);
> +
> +	uint_name_size = name_size;
> +	if (unlikely(uint_name_size != name_size))
> +		goto nothing; // overflow
> +
> +	if (name_size > bufsize)
> +		goto nothing;
>   
> -	memcpy(op->oprom_array, prop->name, len);
> -	op->oprom_array[len] = '\0';
> -	op->oprom_size = ++len;
> +	memcpy(op->oprom_array, prop->name, name_size);
> +	op->oprom_size = uint_name_size;
>   
>   	return copyout(argp, op, sizeof(int) + bufsize);
> +
> +nothing:
> +	#ifdef CONFIG_DEBUG_KERNEL
> +		if (WARN_ON(op->oprom_size))
> +			op-oprom_size = 0;
> +	#endif
> +	return copyout(argp, op, sizeof(int));
>   }
>   
> -static int opromsetopt(struct device_node *dp, struct openpromio *op, int bufsize)
> +static int opromsetopt(struct device_node *dp, struct openpromio *op, const size_t name_value_size)
>   {
> -	char *buf = op->oprom_array + strlen(op->oprom_array) + 1;
> -	int len = op->oprom_array + bufsize - buf;
> +	const char *const name = op->oprom_array;
> +	const size_t name_size = 1 + strlen(name);
> +	char *const value = op->oprom_array + name_size;
> +	const size_t value_size = name_value_size - name_size;
> +	int int_value_size;
> +
> +	#if CONFIG_DEBUG_KERNEL
> +		if (WARN_ON(name_value_size <= name_size))
> +			return -EFAULT;
> +	#endif
>   
> -	return of_set_property(options_node, op->oprom_array, buf, len);
> +	if (unlikely(value_size > INT_MAX))
> +		return -EINVAL;
> +	int_value_size = (int)value_size;
> +
> +	return of_set_property(options_node, name, value, int_value_size);
>   }
>   
> -static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
> +static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, const size_t bufsize, DATA *data)
>   {
>   	phandle ph;
>   
> @@ -229,7 +303,7 @@ static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp
>   	return copyout(argp, op, bufsize + sizeof(int));
>   }
>   
> -static int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
> +static int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, const size_t bufsize, DATA *data)
>   {
>   	int err = -EINVAL;
>   
> @@ -255,7 +329,7 @@ static int oprompci2node(void __user *argp, struct device_node *dp, struct openp
>   	return err;
>   }
>   
> -static int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
> +static int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, const size_t bufsize, DATA *data)
>   {
>   	phandle ph = 0;
>   
> @@ -269,16 +343,24 @@ static int oprompath2node(void __user *argp, struct device_node *dp, struct open
>   	return copyout(argp, op, bufsize + sizeof(int));
>   }
>   
> -static int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsize)
> +static int opromgetbootargs(void __user *argp, struct openpromio *op, const size_t bufsize)
>   {
> -	char *buf = saved_command_line;
> -	int len = strlen(buf);
> +	const char *const buf = saved_command_line;
> +	const size_t size = 1 + strlen(buf);
> +	unsigned int uint_size;
> +
> +	if (unlikely(size == 0))
> +		return -EFAULT; // overflow
>   
> -	if (len > bufsize)
> +	if (size > bufsize)
>   		return -EINVAL;
>   
> -	strcpy(op->oprom_array, buf);
> -	op->oprom_size = len;
> +	if (unlikely(size > UINT_MAX))
> +		return -EFAULT;
> +	uint_size = (unsigned int)size;
> +
> +	memcpy(op->oprom_array, buf, size);
> +	op->oprom_size = uint_size;
>   
>   	return copyout(argp, op, bufsize + sizeof(int));
>   }
> @@ -292,7 +374,8 @@ static long openprom_sunos_ioctl(struct file * file,
>   {
>   	DATA *data = file->private_data;
>   	struct openpromio *opp = NULL;
> -	int bufsize, error = 0;
> +	ssize_t bufsize;
> +	int error = 0;
>   	static int cnt;
>   	void __user *argp = (void __user *)arg;
>   
> @@ -301,6 +384,12 @@ static long openprom_sunos_ioctl(struct file * file,
>   	else
>   		bufsize = copyin(argp, &opp);
>   
> +	#ifdef CONFIG_DEBUG_KERNEL
> +		if (WARN_ON(bufsize == 0))
> +			bufsize = -EFAULT;
> +	#enif
> +
> +	static_assert(LONG_MIN <= -(SIZE_MAX/2)-1);
>   	if (bufsize < 0)
>   		return bufsize;
>   
> @@ -373,7 +462,9 @@ static struct device_node *get_node(phandle n, DATA *data)
>   /* Copy in a whole string from userspace into kernelspace. */
>   static char * copyin_string(char __user *user, size_t len)
>   {
> -	if ((ssize_t)len < 0 || (ssize_t)(len + 1) < 0)
> +	// Is this test even necessary? Surely, memdup_user_nul()
> +	// will fail to allocate space in this condition.
> +	if (len == SIZE_MAX)
>   		return ERR_PTR(-EINVAL);
>   
>   	return memdup_user_nul(user, len);
> @@ -388,7 +479,7 @@ static int opiocget(void __user *argp, DATA *data)
>   	struct device_node *dp;
>   	char *str;
>   	const void *pval;
> -	int err, len;
> +	int err, size;
>   
>   	if (copy_from_user(&op, argp, sizeof(op)))
>   		return -EFAULT;
> @@ -399,15 +490,21 @@ static int opiocget(void __user *argp, DATA *data)
>   	if (IS_ERR(str))
>   		return PTR_ERR(str);
>   
> -	pval = of_get_property(dp, str, &len);
> +	pval = of_get_property(dp, str, &size);
>   	err = 0;
> -	if (!pval || len > op.op_buflen) {
> +	if (!pval || size > op.op_buflen) {
>   		err = -EINVAL;
>   	} else {
> -		op.op_buflen = len;
> +		const int buflen = op.op_buflen;
> +		op.op_buflen = size;
>   		if (copy_to_user(argp, &op, sizeof(op)) ||
> -		    copy_to_user(op.op_buf, pval, len))
> +		    copy_to_user(op.op_buf, pval, size))
>   			err = -EFAULT;
> +		if (size < buflen) {
> +			const char c = 0;
> +			if (copy_to_user(op.op_buf + size, &c, 1)) // To correct faulty PROMs
> +				err = -EFAULT;
> +		}
>   	}
>   	kfree(str);
>   
> @@ -420,7 +517,7 @@ static int opiocnextprop(void __user *argp, DATA *data)
>   	struct device_node *dp;
>   	struct property *prop;
>   	char *str;
> -	int len;
> +	size_t name_size;
>   
>   	if (copy_from_user(&op, argp, sizeof(op)))
>   		return -EFAULT;
> @@ -443,18 +540,28 @@ static int opiocnextprop(void __user *argp, DATA *data)
>   	kfree(str);
>   
>   	if (!prop)
> -		len = 0;
> -	else
> -		len = prop->length;
> +		name_size = 0;
> +	else {
> +		name_size = 1 + strlen(prop->name);
> +		if (unlikely(name_size == 0))
> +			return -EFAULT; // overflow
> +	}
> +
> +	if (op.op_buflen <= 0)
> +		op.op_buflen = 0;
> +
> +	if (name_size > op.op_buflen)
> +		name_size = op.op_buflen;
> +
> +	if (unlikely(name_size > INT_MAX))
> +		name_size = INT_MAX;
>   
> -	if (len > op.op_buflen)
> -		len = op.op_buflen;
> +	op.op_buflen = (int)name_size;
>   
>   	if (copy_to_user(argp, &op, sizeof(op)))
>   		return -EFAULT;
>   
> -	if (len &&
> -	    copy_to_user(op.op_buf, prop->value, len))
> +	if (name_size && copy_to_user(op.op_buf, prop->name, name_size))
>   		return -EFAULT;
>   
>   	return 0;
> @@ -464,7 +571,7 @@ static int opiocset(void __user *argp, DATA *data)
>   {
>   	struct opiocdesc op;
>   	struct device_node *dp;
> -	char *str, *tmp;
> +	char *name, *value;
>   	int err;
>   
>   	if (copy_from_user(&op, argp, sizeof(op)))
> @@ -474,20 +581,22 @@ static int opiocset(void __user *argp, DATA *data)
>   	if (!dp)
>   		return -EINVAL;
>   
> -	str = copyin_string(op.op_name, op.op_namelen);
> -	if (IS_ERR(str))
> -		return PTR_ERR(str);
> +	name = copyin_string(op.op_name, op.op_namelen);
> +	if (IS_ERR(name))
> +		return PTR_ERR(name);
>   
> -	tmp = copyin_string(op.op_buf, op.op_buflen);
> -	if (IS_ERR(tmp)) {
> -		kfree(str);
> -		return PTR_ERR(tmp);
> +	value = copyin_string(op.op_buf, op.op_buflen);
> +	if (IS_ERR(value)) {
> +		kfree(name);
> +		return PTR_ERR(value);
>   	}
>   
> -	err = of_set_property(dp, str, tmp, op.op_buflen);
> +	// Note that op.op_buflen is not trusted; strlen() is
> +	// used instead to calculate the proper size.
> +	err = of_set_property(dp, name, value, 1 + strlen(value));
>   
> -	kfree(str);
> -	kfree(tmp);
> +	kfree(name);
> +	kfree(value);
>   
>   	return err;
>   }
> 

Hi,
Below is the full set of changes to the offered patch that I had to fix
to make it build cleanly.
However, the changes that I made to <linux/limits.h> won't be acceptable;
some local SIZE_OPMAX macro could be used instead for those checks.

---
---
  drivers/sbus/char/openprom.c |   25 ++++++++++++++++---------
  include/linux/limits.h       |    9 ++++++++-
  2 files changed, 24 insertions(+), 10 deletions(-)

--- linux-next-20201124.orig/drivers/sbus/char/openprom.c
+++ linux-next-20201124/drivers/sbus/char/openprom.c
@@ -34,6 +34,12 @@
  #include <linux/pci.h>
  #endif

+	static_assert(SIZE_MAX >= UINT_MAX);
+	static_assert(OPROMMAXPARAM <= SIZE_MAX - sizeof(int) - 1);
+	static_assert(ULONG_MAX >= SIZE_MAX);
+	static_assert((SIZE_MAX/2) >= OPROMMAXPARAM);
+	static_assert(LONG_MIN <= -(SIZE_MAX/2)-1);
+
  MODULE_AUTHOR("Thomas K. Dyas (tdyas@....rutgers.edu) and Eddie C. Dost  (ecd@...net.be)");
  MODULE_DESCRIPTION("OPENPROM Configuration Driver");
  MODULE_LICENSE("GPL");
@@ -73,7 +79,7 @@ static ssize_t copyin(struct openpromio
  	if (oprom_size == 0)
  		return -EINVAL;

-	static_assert(SIZE_MAX >= UINT_MAX);
+	///static_assert(SIZE_MAX >= UINT_MAX);

  	/* If the bufsize is too large, just limit it.
  	 * Fix from Jason Rappleye.
@@ -107,11 +113,11 @@ static ssize_t copyin(struct openpromio
  	 * to be nul-terminated must not trust the size returned by
  	 * this function.
  	 */
-	static_assert(OPROMMAXPARAM <= SIZE_MAX - sizeof(int) - 1);
+	///static_assert(OPROMMAXPARAM <= SIZE_MAX - sizeof(int) - 1);
  	if (!(*opp_p = kzalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
  		return -ENOMEM;

-	static_assert(ULONG_MAX >= SIZE_MAX);
+	///static_assert(ULONG_MAX >= SIZE_MAX);
  	if (copy_from_user(&(*opp_p)->oprom_array,
  			   &info->oprom_array, bufsize)) {
  		kfree(*opp_p);
@@ -134,7 +140,7 @@ static ssize_t getstrings(struct openpro
  		return -ENOMEM;

  	bufsize = n = 0;
-	static_assert((SIZE_MAX/2) >= OPROMMAXPARAM);
+	///static_assert((SIZE_MAX/2) >= OPROMMAXPARAM);
  	while ((n < 2) && (bufsize < OPROMMAXPARAM)) {
  		if (get_user(c, &info->oprom_array[bufsize])) {
  			kfree(*opp_p);
@@ -156,7 +162,7 @@ static ssize_t getstrings(struct openpro
   */
  static int copyout(void __user *info, struct openpromio *opp, const size_t size)
  {
-	static_assert(ULONG_MAX >= SIZE_MAX);
+	///static_assert(ULONG_MAX >= SIZE_MAX);
  	if (copy_to_user(info, opp, size))
  		return -EFAULT;
  	return 0;
@@ -185,10 +191,11 @@ static int opromgetprop(void __user *arg
  		// the contents should be nul-terminated in
  		// case the PROM erroneously produces a string
  		// that is not nul-terminated.
-		if (pval_size < bufsize)
+		if (pval_size < bufsize) {
  			char *const end = op->oprom_array + pval_size;
  			if (WARN_ON(*end))
  				*end = 0;
+		}
  	#endif

  	return copyout(argp, op, sizeof(int) + bufsize);
@@ -231,7 +238,7 @@ static int opromnxtprop(void __user *arg
  nothing:
  	#ifdef CONFIG_DEBUG_KERNEL
  		if (WARN_ON(op->oprom_size))
-			op-oprom_size = 0;
+			op->oprom_size = 0;
  	#endif
  	return copyout(argp, op, sizeof(int));
  }
@@ -387,9 +394,9 @@ static long openprom_sunos_ioctl(struct
  	#ifdef CONFIG_DEBUG_KERNEL
  		if (WARN_ON(bufsize == 0))
  			bufsize = -EFAULT;
-	#enif
+	#endif

-	static_assert(LONG_MIN <= -(SIZE_MAX/2)-1);
+	///static_assert(LONG_MIN <= -(SIZE_MAX/2)-1);
  	if (bufsize < 0)
  		return bufsize;

--- linux-next-20201124.orig/include/linux/limits.h
+++ linux-next-20201124/include/linux/limits.h
@@ -5,8 +5,9 @@
  #include <uapi/linux/limits.h>
  #include <linux/types.h>
  #include <vdso/limits.h>
+#include <asm/bitsperlong.h>

-#define SIZE_MAX	(~(size_t)0)
+//#define SIZE_MAX	(~(size_t)0)
  #define PHYS_ADDR_MAX	(~(phys_addr_t)0)

  #define U8_MAX		((u8)~0U)
@@ -23,4 +24,10 @@
  #define S64_MAX		((s64)(U64_MAX >> 1))
  #define S64_MIN		((s64)(-S64_MAX - 1))

+#if BITS_PER_LONG == 64
+#define SIZE_MAX	(~0UL & 0xffffffffffffffffUL)
+#else
+#define SIZE_MAX	(~0UL & 0xffffffffUL)
+#endif
+
  #endif /* _LINUX_LIMITS_H */

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ