• Kees Cook's avatar
    string.h: Introduce memtostr() and memtostr_pad() · 0efc5990
    Kees Cook authored
    Another ambiguous use of strncpy() is to copy from strings that may not
    be NUL-terminated. These cases depend on having the destination buffer
    be explicitly larger than the source buffer's maximum size, having
    the size of the copy exactly match the source buffer's maximum size,
    and for the destination buffer to get explicitly NUL terminated.
    
    This usually happens when parsing protocols or hardware character arrays
    that are not guaranteed to be NUL-terminated. The code pattern is
    effectively this:
    
    	char dest[sizeof(src) + 1];
    
    	strncpy(dest, src, sizeof(src));
    	dest[sizeof(dest) - 1] = '\0';
    
    In practice it usually looks like:
    
    struct from_hardware {
    	...
    	char name[HW_NAME_SIZE] __nonstring;
    	...
    };
    
    	struct from_hardware *p = ...;
    	char name[HW_NAME_SIZE + 1];
    
    	strncpy(name, p->name, HW_NAME_SIZE);
    	name[NW_NAME_SIZE] = '\0';
    
    This cannot be replaced with:
    
    	strscpy(name, p->name, sizeof(name));
    
    because p->name is smaller and not NUL-terminated, so FORTIFY will
    trigger when strnlen(p->name, sizeof(name)) is used. And it cannot be
    replaced with:
    
    	strscpy(name, p->name, sizeof(p->name));
    
    because then "name" may contain a 1 character early truncation of
    p->name.
    
    Provide an unambiguous interface for converting a maybe not-NUL-terminated
    string to a NUL-terminated string, with compile-time buffer size checking
    so that it can never fail at runtime: memtostr() and memtostr_pad(). Also
    add KUnit tests for both.
    
    Link: https://lore.kernel.org/r/20240410023155.2100422-1-keescook@chromium.orgSigned-off-by: default avatarKees Cook <keescook@chromium.org>
    0efc5990
string_kunit.c 19.3 KB