[PATCH] powerpc: Add of_register_i2c_devices()

Guennadi Liakhovetski g.liakhovetski at gmx.de
Thu Aug 2 06:36:04 EST 2007


On Wed, 1 Aug 2007, Segher Boessenkool wrote:

> > > > > > +		strncpy(info->driver_name, i2c_devices[i].i2c_driver,
> > > > > > KOBJ_NAME_LEN);
> > > > > > +		strncpy(info->type, i2c_devices[i].i2c_type,
> > > > > > I2C_NAME_SIZE);
> > > > > 
> > > > > Why not just strcpy(), btw?
> > > > 
> > > > Because target strings are finite length, and sources are just pointers
> > > > to
> > > > some constant strings, which one might make arbitrarily long.
> > > 
> > > So it's no problem if the name or type string gets cut short?
> > > Just checking :-)
> > 
> > Then it just won't match.
> 
> strncpy() won't put a terminating zero on there, is everything
> that uses the resulting string okay with that?

Ok, this might be a problem, I guess. E.g., in 
drivers/i2c/i2c-core.c::i2c_device_uevent():

	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
			"MODALIAS=%s", client->driver_name))

and in a couple more places.

> Also, if the
> name gets cut short, it might match some _other_ expected name.

Don't think this could happen. At least the generic strcmp compares the 
'\0' too.

Now, the bad news (for me at least, as well as for some on #mklinux). To 
fix the bug I wrote the patch below. Yes, it is lacking a "Signed-..." - 
on purpose. Here's why. Having written it, I verified, that

	c[4] = "01234";

causes a nice compiler warning like:

warning: initializer-string for array of chars is too long

Then I asked myself what happens if you do

	c[4] = "0123";

? To my surprise, there was no warning. So, for example, declaring a 
struct like

struct t {
	char c[4];
	int i;
} z;

and doing

	strcpy(z.c, c);

silently corrupts z.i. Verified with gcc 3.3.x, 3.4.5, 4.1.2. 4.2 Does 
emit a warning... Now, am I right that there are lots of places in 
the kernel where we just initialize arrays of chars like above and then 
use ctrcpy to copy it to another equally-long string? Which means, if the 
initialization string is exactly the array length - without the '\0' - we 
get random memory corruption... And the only safe way is 

	strncpy(z.c, c, 3);
	z.c[3] = '\0';

with compilers < 4.2?...

Thanks
Guennadi
---

Fix a bug introduced by my earlier patch, whereby strncpy of too long a 
line could leave the result unterminated. Instead, just use fixed-size 
arrays and let the compiler verify the length for us. No need to try to 
save a few bytes of __initdata anyway. Thanks to Segher Boessenkool for 
pointing out.

diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 727453d..1e567d5 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -309,8 +309,8 @@ arch_initcall(gfar_of_init);
 #include <linux/i2c.h>
 struct i2c_driver_device {
 	char	*of_device;
-	char	*i2c_driver;
-	char	*i2c_type;
+	char	i2c_driver[KOBJ_NAME_LEN];
+	char	i2c_type[I2C_NAME_SIZE];
 };
 
 static struct i2c_driver_device i2c_devices[] __initdata = {
@@ -327,8 +327,8 @@ static int __init of_find_i2c_driver(struct device_node *node, struct i2c_board_
 	for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
 		if (!of_device_is_compatible(node, i2c_devices[i].of_device))
 			continue;
-		strncpy(info->driver_name, i2c_devices[i].i2c_driver, KOBJ_NAME_LEN);
-		strncpy(info->type, i2c_devices[i].i2c_type, I2C_NAME_SIZE);
+		strcpy(info->driver_name, i2c_devices[i].i2c_driver);
+		strcpy(info->type, i2c_devices[i].i2c_type);
 		return 0;
 	}
 	return -ENODEV;



More information about the Linuxppc-dev mailing list