As Bartosz reported, str_has_prefix() has a bug: it can't differentiate between an empty prefix matching an empty string from a non-matching prefix. This is a fundamental design flaw in this API, and not something that can be fixed. As always, this is a consequence of choosing sizes instead of pointers. Sizes are often the wrong choice. In this specific case, pointers are more capable of differentiating these cases, as NULL is a special sentinel value that doesn't need to overload a valid value. Let's implement strprefix(), a function that returns a pointer right after the prefix if found, and a null pointer if not found. We'll slowly migrate existing code from str_has_prefix() to strprefix(). Reported-by: Bartosz Golaszewski Cc: Andreas Schwab Cc: Andy Shevchenko Cc: Andy Shevchenko Cc: Bartosz Golaszewski Cc: Daniel Scally Cc: Danilo Krummrich Cc: Greg Kroah-Hartman Cc: Hans Verkuil Cc: Heikki Krogerus Cc: Joe Perches Cc: Johan Hovold Cc: Kees Cook Cc: Laurent Pinchart Cc: Len Brown Cc: Linus Torvalds Cc: Linus Walleij Cc: Namhyung Kim Cc: "Rafael J. Wysocki" Cc: Rob Herring Cc: Sakari Ailus Cc: Saravana Kannan Cc: Steven Rostedt Cc: Tom Zanussi --- include/linux/string.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/include/linux/string.h b/include/linux/string.h index 6cb5cdd01158..0397e630bdc8 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -545,16 +545,33 @@ void memcpy_and_pad(void *dest, size_t dest_len, const void *src, size_t count, sizeof(*(obj)) - offsetof(typeof(*(obj)), member)); \ }) +/** + * strprefix - string prefix + * @s: The string to be tested + * @prefix: The string to see if @s starts with + * + * Returns: + * * @s+strlen(@prefix) if @s starts with @prefix + * * NULL if @s does not start with @prefix + */ +static __always_inline char *strprefix(const char *s, const char *prefix) +{ + size_t len = strlen(prefix); + return strncmp(s, prefix, len) == 0 ? (char *) s + len : NULL; +} + /** * str_has_prefix - Test if a string has a given prefix * @str: The string to test * @prefix: The string to see if @str starts with * + * DEPRECATED: Use strprefix() + * * A common way to test a prefix of a string is to do: * strncmp(str, prefix, sizeof(prefix) - 1) * * But this can lead to bugs due to typos, or if prefix is a pointer - * and not a constant. Instead use str_has_prefix(). + * and not a constant. Instead use strprefix(). * * Returns: * * strlen(@prefix) if @str starts with @prefix -- 2.55.0