diff mbox series

[1/6] property: add fwnode_property_read_string_index()

Message ID 20220318160059.328208-2-clement.leger@bootlin.com (mailing list archive)
State Not Applicable
Delegated to: Netdev Maintainers
Headers show
Series introduce fwnode in the I2C subsystem | expand

Checks

Context Check Description
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8235 this patch: 8235
netdev/cc_maintainers success CCed 7 of 7 maintainers
netdev/build_clang success Errors and warnings before: 1489 this patch: 1489
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 7767 this patch: 7767
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 63 lines checked
netdev/kdoc success Errors and warnings before: 5 this patch: 5
netdev/source_inline success Was 0 now: 0
netdev/tree_selection success Guessing tree name failed - patch did not apply

Commit Message

Clément Léger March 18, 2022, 4 p.m. UTC
Add fwnode_property_read_string_index() function which allows to
retrieve a string from an array by its index. This function is the
equivalent of of_property_read_string_index() but for fwnode support.

Signed-off-by: Clément Léger <clement.leger@bootlin.com>
---
 drivers/base/property.c  | 48 ++++++++++++++++++++++++++++++++++++++++
 include/linux/property.h |  3 +++
 2 files changed, 51 insertions(+)

Comments

Andy Shevchenko March 18, 2022, 4:26 p.m. UTC | #1
On Fri, Mar 18, 2022 at 05:00:47PM +0100, Clément Léger wrote:
> Add fwnode_property_read_string_index() function which allows to
> retrieve a string from an array by its index. This function is the
> equivalent of of_property_read_string_index() but for fwnode support.

...

> +	values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
> +	if (!values)
> +		return -ENOMEM;
> +
> +	ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
> +	if (ret < 0)
> +		goto out;
> +
> +	*string = values[index];
> +out:
> +	kfree(values);

Here is UAF (use after free). How is it supposed to work?
Clément Léger March 18, 2022, 4:49 p.m. UTC | #2
Le Fri, 18 Mar 2022 18:26:00 +0200,
Andy Shevchenko <andriy.shevchenko@linux.intel.com> a écrit :

> On Fri, Mar 18, 2022 at 05:00:47PM +0100, Clément Léger wrote:
> > Add fwnode_property_read_string_index() function which allows to
> > retrieve a string from an array by its index. This function is the
> > equivalent of of_property_read_string_index() but for fwnode support.  
> 
> ...
> 
> > +	values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
> > +	if (!values)
> > +		return -ENOMEM;
> > +
> > +	ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
> > +	if (ret < 0)
> > +		goto out;
> > +
> > +	*string = values[index];
> > +out:
> > +	kfree(values);  
> 
> Here is UAF (use after free). How is it supposed to work?
> 

values is an array of pointers. I'm only retrieving a pointer out of
it.
Andy Shevchenko March 18, 2022, 6:09 p.m. UTC | #3
On Fri, Mar 18, 2022 at 05:49:12PM +0100, Clément Léger wrote:
> Le Fri, 18 Mar 2022 18:26:00 +0200,
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> a écrit :
> > On Fri, Mar 18, 2022 at 05:00:47PM +0100, Clément Léger wrote:
> > > Add fwnode_property_read_string_index() function which allows to
> > > retrieve a string from an array by its index. This function is the
> > > equivalent of of_property_read_string_index() but for fwnode support.  

...

> > > +	values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
> > > +	if (!values)
> > > +		return -ENOMEM;
> > > +
> > > +	ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
> > > +	if (ret < 0)
> > > +		goto out;
> > > +
> > > +	*string = values[index];
> > > +out:
> > > +	kfree(values);  
> > 
> > Here is UAF (use after free). How is it supposed to work?
> 
> values is an array of pointers. I'm only retrieving a pointer out of
> it.

I see, thanks for pointing out.

Nevertheless, I don't like the idea of allocating memory in this case.
Can we rather add a new callback that will provide us the necessary
property directly?
Clément Léger March 21, 2022, 7:49 a.m. UTC | #4
Le Fri, 18 Mar 2022 20:09:37 +0200,
Andy Shevchenko <andriy.shevchenko@linux.intel.com> a écrit :

> On Fri, Mar 18, 2022 at 05:49:12PM +0100, Clément Léger wrote:
> > Le Fri, 18 Mar 2022 18:26:00 +0200,
> > Andy Shevchenko <andriy.shevchenko@linux.intel.com> a écrit :  
> > > On Fri, Mar 18, 2022 at 05:00:47PM +0100, Clément Léger wrote:  
> > > > Add fwnode_property_read_string_index() function which allows to
> > > > retrieve a string from an array by its index. This function is the
> > > > equivalent of of_property_read_string_index() but for fwnode support.    
> 
> ...
> 
> > > > +	values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
> > > > +	if (!values)
> > > > +		return -ENOMEM;
> > > > +
> > > > +	ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
> > > > +	if (ret < 0)
> > > > +		goto out;
> > > > +
> > > > +	*string = values[index];
> > > > +out:
> > > > +	kfree(values);    
> > > 
> > > Here is UAF (use after free). How is it supposed to work?  
> > 
> > values is an array of pointers. I'm only retrieving a pointer out of
> > it.  
> 
> I see, thanks for pointing out.
> 
> Nevertheless, I don't like the idea of allocating memory in this case.
> Can we rather add a new callback that will provide us the necessary
> property directly?
> 

IMHO, it would indeed be better. However,
fwnode_property_match_string() also allocates memory to do the same
kind of operation. Would you also like a callback for this one ?

Thanks,
Andy Shevchenko March 21, 2022, 10:31 a.m. UTC | #5
On Mon, Mar 21, 2022 at 08:49:21AM +0100, Clément Léger wrote:
> Le Fri, 18 Mar 2022 20:09:37 +0200,
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> a écrit :
> > On Fri, Mar 18, 2022 at 05:49:12PM +0100, Clément Léger wrote:
> > > Le Fri, 18 Mar 2022 18:26:00 +0200,
> > > Andy Shevchenko <andriy.shevchenko@linux.intel.com> a écrit :  
> > > > On Fri, Mar 18, 2022 at 05:00:47PM +0100, Clément Léger wrote:  

...

> > > > > +	values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
> > > > > +	if (!values)
> > > > > +		return -ENOMEM;
> > > > > +
> > > > > +	ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
> > > > > +	if (ret < 0)
> > > > > +		goto out;
> > > > > +
> > > > > +	*string = values[index];
> > > > > +out:
> > > > > +	kfree(values);    
> > > > 
> > > > Here is UAF (use after free). How is it supposed to work?  
> > > 
> > > values is an array of pointers. I'm only retrieving a pointer out of
> > > it.  
> > 
> > I see, thanks for pointing out.
> > 
> > Nevertheless, I don't like the idea of allocating memory in this case.
> > Can we rather add a new callback that will provide us the necessary
> > property directly?
> > 
> 
> IMHO, it would indeed be better. However,
> fwnode_property_match_string() also allocates memory to do the same
> kind of operation. Would you also like a callback for this one ?

But matching string will need all of them to cover all possible cases.
So, it doesn't rely on the certain index and needs allocation anyway.
Clément Léger March 21, 2022, 10:33 a.m. UTC | #6
Le Mon, 21 Mar 2022 12:31:58 +0200,
Andy Shevchenko <andriy.shevchenko@linux.intel.com> a écrit :

> > 
> > IMHO, it would indeed be better. However,
> > fwnode_property_match_string() also allocates memory to do the same
> > kind of operation. Would you also like a callback for this one ?  
> 
> But matching string will need all of them to cover all possible cases.
> So, it doesn't rely on the certain index and needs allocation anyway.

Acked, it makes sense to keep it that way.
diff mbox series

Patch

diff --git a/drivers/base/property.c b/drivers/base/property.c
index e6497f6877ee..67c33c11f00c 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -451,6 +451,54 @@  int fwnode_property_match_string(const struct fwnode_handle *fwnode,
 }
 EXPORT_SYMBOL_GPL(fwnode_property_match_string);
 
+/**
+ * fwnode_property_read_string_index - read a string in an array using an index
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property holding the array
+ * @index: Index of the string to look for
+ * @string: Pointer to the string if found
+ *
+ * Find a string by a given index in a string array and if it is found return
+ * the string value in @string.
+ *
+ * Return: %0 if the property was found (success),
+ *	   %-EINVAL if given arguments are not valid,
+ *	   %-ENODATA if the property does not have a value,
+ *	   %-EPROTO if the property is not an array of strings,
+ *	   %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string_index(const struct fwnode_handle *fwnode,
+				      const char *propname, int index,
+				      const char **string)
+{
+	const char **values;
+	int nval, ret;
+
+	nval = fwnode_property_read_string_array(fwnode, propname, NULL, 0);
+	if (nval < 0)
+		return nval;
+
+	if (index >= nval)
+		return -EINVAL;
+
+	if (nval == 0)
+		return -ENODATA;
+
+	values = kcalloc(nval, sizeof(*values), GFP_KERNEL);
+	if (!values)
+		return -ENOMEM;
+
+	ret = fwnode_property_read_string_array(fwnode, propname, values, nval);
+	if (ret < 0)
+		goto out;
+
+	*string = values[index];
+out:
+	kfree(values);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string_index);
+
 /**
  * fwnode_property_get_reference_args() - Find a reference with arguments
  * @fwnode:	Firmware node where to look for the reference
diff --git a/include/linux/property.h b/include/linux/property.h
index 7399a0b45f98..a033920eb10a 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -70,6 +70,9 @@  int fwnode_property_read_string_array(const struct fwnode_handle *fwnode,
 				      size_t nval);
 int fwnode_property_read_string(const struct fwnode_handle *fwnode,
 				const char *propname, const char **val);
+int fwnode_property_read_string_index(const struct fwnode_handle *fwnode,
+				      const char *propname, int index,
+				      const char **string);
 int fwnode_property_match_string(const struct fwnode_handle *fwnode,
 				 const char *propname, const char *string);
 int fwnode_property_get_reference_args(const struct fwnode_handle *fwnode,