Hi! > >> If userspace doesn't end the input with a newline (which can easily > >> happen if the write happens from a C program that does write(fd, > >> iface, strlen(iface))), we may end up including garbage from a > >> previous, longer value in the device_name. For example > >> > >> # cat device_name > >> > >> # printf 'eth12' > device_name > >> # cat device_name > >> eth12 > >> # printf 'eth3' > device_name > >> # cat device_name > >> eth32 > >> > >> I highly doubt anybody is relying on this behaviour, so switch to > >> simply copying the bytes (we've already checked that size is < > >> IFNAMSIZ) and unconditionally zero-terminate it; of course, we also > >> still have to strip a trailing newline. > > > > char device_name[IFNAMSIZ]; > > > > Ok, good catch reporting the bug, but are you sure the fix is right? > > > > AFAICT the design is that device_name does _not_ have to be zero > > terminated, and your fix incorrectly limits the size of device_name. > > Yes, I'm sure. > > /** > * dev_valid_name - check if name is okay for network device > * @name: name string > * > * Network device names need to be valid file names to > * to allow sysfs to work. We also disallow any kind of > * whitespace. > */ > bool dev_valid_name(const char *name) > { > if (*name == '\0') > return false; > if (strnlen(name, IFNAMSIZ) == IFNAMSIZ) > return false; > > so no netdevice name has a string length > 15 (IOW, there must be a nul > byte within the first 16 bytes of name). Also note all the places a > net_device->name is printed with a simple %s, so they are definitely > always 0-terminated. > > Moreover, I'm actually not limiting anything more than was already done; > we already reject any input from userspace >= 16 bytes. I'm simply > ensuring that we're never confused by leftover garbage. Ok. Sorry for the noise. > >> --- a/drivers/leds/trigger/ledtrig-netdev.c > >> +++ b/drivers/leds/trigger/ledtrig-netdev.c > >> @@ -122,7 +122,8 @@ static ssize_t device_name_store(struct device *dev, > >> trigger_data->net_dev = NULL; > >> } > >> > >> - strncpy(trigger_data->device_name, buf, size); > >> + memcpy(trigger_data->device_name, buf, size); > >> + trigger_data->device_name[size] = '\0'; > > > > I'd do = 0 for consistency with code below. > > I'd rather the other way around :) but yeah, let's just be consistent. > I'll fix in next version. Or just use your version and fix both places :-). Your option, as long as it is consistent. > > I believe the strncpy() is right to use here, but code should be > > modified so that zero-termination is not required. > > So, I believe the above should convince you that strncpy is wrong. Or > rather, strncpy is really just a convoluted memcpy: the userspace input > doesn't contain a nul among the size bytes [1], so the "copy all the > bytes, but don't nul-terminate" semantics of strncpy kick in - which is > often a security bug, but the code is such that the zero at > device_name[15] (because it was originally kzalloc'ed) is never > overwritten. So in theory, we could keep strncpy and just add the > nul-termination, but the str* prefix is very misleading (which is > probably why the bug happened in the first place). > > [1] And if it did, the "zero the rest of the output buffer" semantics > kick in. That's functionally equivalent to my memcpy() + write one nul > byte, since nothing after that first nul byte in device_name would ever > be inspected. Actually "zero the rest" semantics kind of makes sense here. No, I'm sorry, I don't understand. How are you getting stale data there? > >> # printf 'eth12' > device_name > >> # cat device_name > >> eth12 > >> # printf 'eth3' > device_name > >> # cat device_name > >> eth32 strncpy() should zero the rest, and you should get "eth3"...?! Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
Attachment:
signature.asc
Description: Digital signature