Received: by 2002:a05:6a10:1d13:0:0:0:0 with SMTP id pp19csp54833pxb; Wed, 25 Aug 2021 19:49:24 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxwIsxWdijrnwPxgTUgaim3yUdXgoJ3+H31ax5qyr3jNwT66X9zr1UJmW5WECFGvNqG8RVP X-Received: by 2002:a17:906:1454:: with SMTP id q20mr1879297ejc.446.1629946164677; Wed, 25 Aug 2021 19:49:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1629946164; cv=none; d=google.com; s=arc-20160816; b=zHo5+hwXARUos4nKpLB7hgQc3XVtEf0yTznXHDbWtB26U6+uHHb8ivMbrtiJ2QtX4o /NGAzfD8cv+gksy4xk1F4sCoCgidbbiv23dLg6lZzyagaiby9tJl8ZyNhnOA6coSHVi0 ZEVV5fBkOwZyghH8JVsPJDiuIcV139RP/7r+VvTOCaTqONidTrmFkgGC6+rJJBgJt+OA /Xhf0FHfo748bx+Dly+C1n/xQv4Xo0V/6A3JVB1IdGPiqHJiXqURsv784s74/4q72v5A CbzdBfR/8koLoBITaFRQo1YSDZBm/jCGPkKHsjjkUvjP3yrCfZH+AEiZBtGj6mM8ZPPN pdPw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:in-reply-to:content-disposition:mime-version :references:message-id:subject:cc:to:from:date:dkim-signature; bh=2NTnR4tKqkUMwtt7VmZitcD8mv+aAAdUIksgDSJe0RM=; b=IuILKi+HOqtRSIuTvSMAZT7qSDsFpTjcOhr1Nt5ZdviZCxHDTJQcstRaKyvK09LsWq RRoK9jOMceMgPkozCn7hui2BeFG2Qip/DMuUUI0ElK9NQWeFTyPZ0LrvTDS0Hh9NmlSf qnVgcnlKlASUpZKKy9FkxnMAL2CXwR6XrpLqvyPHiQKlXQ/RjkopyzYlX6RBRhOQIvqg LakJKXAZSzsWtnUFYe06fVVEJLS+6QIF78lMGHa5P/ElWyUYIkW6uUYaIVjHwDcdc3xG JofTl9egF+uz65Rkn6YNaC0jnsR494hgvTK+Lt84HiBdTMy7JIgrA+QPwOhfSCjukW8y XIdw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=PpXBh4KI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id d15si1864428edt.431.2021.08.25.19.48.59; Wed, 25 Aug 2021 19:49:24 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=PpXBh4KI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232441AbhHZCsF (ORCPT + 99 others); Wed, 25 Aug 2021 22:48:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40556 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237527AbhHZCsE (ORCPT ); Wed, 25 Aug 2021 22:48:04 -0400 Received: from mail-pj1-x1032.google.com (mail-pj1-x1032.google.com [IPv6:2607:f8b0:4864:20::1032]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E37DFC0613C1 for ; Wed, 25 Aug 2021 19:47:17 -0700 (PDT) Received: by mail-pj1-x1032.google.com with SMTP id h1so1191743pjs.2 for ; Wed, 25 Aug 2021 19:47:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to; bh=2NTnR4tKqkUMwtt7VmZitcD8mv+aAAdUIksgDSJe0RM=; b=PpXBh4KIrPHyeYV5WYxZcDrXhrw16aCmd+jC9qMjezCHeIFay6RQlH4s+vNY6snhep psjbOhxJt7dcxQXhBBbVHyhnI3u8FiFHYpxevGQCacXI4QJSy9i83KNxVKqZeecH4yKT UCBJmr+1l9I27q+TBGsZRPaTAn/xDYak3SZAs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to; bh=2NTnR4tKqkUMwtt7VmZitcD8mv+aAAdUIksgDSJe0RM=; b=rsdlpGs1XctfOYeNvJ/D5X5Ue+q7KmrIn+h6jZTdBDzbhfClY1Cg36eXDmV4jkB+K7 GakUPzuAH8D3ZxzVnsx94iK4VyonMNQVsixK77CejejAlYiu9m2rGwbCr55PAaRfsT89 yUWE5UHLvRSAtCTl31iVPeMA7a0x666bkxnU2+XKblHW3SLh39aX7LMhiG5ikVd2GXmY Q2ugzmxdS8xYDXebzpPr8PIkLv1fOKTuTJAA7m4SQm2GKTpTkmgGvtt4k7ZjRu2oNqpN gPcOpMh2mP3TJlD3Y2OaYy2pkrycMlV+Zy+x1bTD1Ydry6QA2MseiCD0qiM0e3K5HLMb lW/Q== X-Gm-Message-State: AOAM533A6TkioVISbz33V/lmgQU0vzxuIL4MTFjVwviYySM8Oad1NLME kF8s7H0WLwggHk08ThGxp6lXEQ== X-Received: by 2002:a17:90a:9314:: with SMTP id p20mr14161631pjo.87.1629946037190; Wed, 25 Aug 2021 19:47:17 -0700 (PDT) Received: from www.outflux.net (smtp.outflux.net. [198.145.64.163]) by smtp.gmail.com with ESMTPSA id 141sm1355928pgf.46.2021.08.25.19.47.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 25 Aug 2021 19:47:16 -0700 (PDT) Date: Wed, 25 Aug 2021 19:47:15 -0700 From: Kees Cook To: Nick Desaulniers Cc: linux-kernel@vger.kernel.org, Andy Shevchenko , Rasmus Villemoes , Daniel Micay , Francis Laniel , Bart Van Assche , David Gow , linux-mm@kvack.org, clang-built-linux@googlegroups.com, linux-hardening@vger.kernel.org Subject: Re: [PATCH for-next 14/25] lib/string: Move helper functions out of string.c Message-ID: <202108251942.26FC1B8E7@keescook> References: <20210822075122.864511-1-keescook@chromium.org> <20210822075122.864511-15-keescook@chromium.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Aug 25, 2021 at 02:48:30PM -0700, Nick Desaulniers wrote: > On Sun, Aug 22, 2021 at 12:51 AM Kees Cook wrote: > > > > The core functions of string.c are those that may be implemented by > > per-architecture functions, or overloaded by FORTIFY_SOURCE. As a > > result, it needs to be built with __NO_FORTIFY. Without this, macros > > Sorry, is there more info on what exactly __NO_FORTIFY is (and why we > "need" it)? include/linux/string.h has: #if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE) #include #endif It's needed in cases where fortification won't actually operate (i.e. early boot without the full kernel running), or in similar situations (code meant to be executed under different "runtimes" (hypervisors), or for the fortified string implementations themselves (i.e. what these couple of patches are reorganizing to correctly do here). > > > will collide with function declarations. This was accidentally working > > due to -ffreestanding (on some architectures). Make this deterministic > > by explicitly setting __NO_FORTIFY and move all the helper functions > > into string_helpers.c so that they gain the fortification coverage they > > had been missing. > > > > Acked-by: Andy Shevchenko > > Signed-off-by: Kees Cook > > --- > > arch/arm/boot/compressed/string.c | 1 + > > arch/s390/lib/string.c | 3 + > > arch/x86/boot/compressed/misc.h | 2 + > > arch/x86/boot/compressed/pgtable_64.c | 2 + > > arch/x86/lib/string_32.c | 1 + > > lib/string.c | 210 +------------------------- > > lib/string_helpers.c | 193 +++++++++++++++++++++++ > > 7 files changed, 208 insertions(+), 204 deletions(-) > > > > diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c > > index 8c0fa276d994..fcc678fce045 100644 > > --- a/arch/arm/boot/compressed/string.c > > +++ b/arch/arm/boot/compressed/string.c > > @@ -5,6 +5,7 @@ > > * Small subset of simple string routines > > */ > > > > +#define __NO_FORTIFY > > #include > > > > /* > > diff --git a/arch/s390/lib/string.c b/arch/s390/lib/string.c > > index cfcdf76d6a95..392fb9f4f4db 100644 > > --- a/arch/s390/lib/string.c > > +++ b/arch/s390/lib/string.c > > @@ -8,6 +8,9 @@ > > */ > > > > #define IN_ARCH_STRING_C 1 > > +#ifndef __NO_FORTIFY > > +# define __NO_FORTIFY > > +#endif > > > > #include > > #include > > diff --git a/arch/x86/boot/compressed/misc.h b/arch/x86/boot/compressed/misc.h > > index 31139256859f..49bde196da9b 100644 > > --- a/arch/x86/boot/compressed/misc.h > > +++ b/arch/x86/boot/compressed/misc.h > > @@ -14,6 +14,8 @@ > > #undef CONFIG_KASAN > > #undef CONFIG_KASAN_GENERIC > > > > +#define __NO_FORTIFY > > + > > /* cpu_feature_enabled() cannot be used this early */ > > #define USE_EARLY_PGTABLE_L5 > > > > diff --git a/arch/x86/boot/compressed/pgtable_64.c b/arch/x86/boot/compressed/pgtable_64.c > > index 2a78746f5a4c..a1733319a22a 100644 > > --- a/arch/x86/boot/compressed/pgtable_64.c > > +++ b/arch/x86/boot/compressed/pgtable_64.c > > @@ -1,3 +1,5 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +#include "misc.h" > > ^ should we just `#define __NO_FORTIFY` here in pgtable_64.c rather > than set that for a whole header? No -- anything using the string functions in x86 early boot needs to use misc.h, since it correctly handles to various dances of includes and defines to get the right combinations. > > > #include > > #include > > #include > > diff --git a/arch/x86/lib/string_32.c b/arch/x86/lib/string_32.c > > index d15fdae9656e..53b3f202267c 100644 > > --- a/arch/x86/lib/string_32.c > > +++ b/arch/x86/lib/string_32.c > > @@ -11,6 +11,7 @@ > > * strings. > > */ > > > > +#define __NO_FORTIFY > > #include > > #include > > > > diff --git a/lib/string.c b/lib/string.c > > index 77bd0b1d3296..1e6259f263b8 100644 > > --- a/lib/string.c > > +++ b/lib/string.c > > @@ -6,20 +6,15 @@ > > */ > > > > /* > > - * stupid library routines.. The optimized versions should generally be found > > - * as inline code in > > + * This file should be used only for "library" routines that may have > > + * alternative implementations on specific architectures (generally > > + * found in ), or get overloaded by FORTIFY_SOURCE. > > + * (Specifically, this file is built with __NO_FORTIFY.) > > * > > - * These are buggy as well.. > > - * > > - * * Fri Jun 25 1999, Ingo Oeser > > - * - Added strsep() which will replace strtok() soon (because strsep() is > > - * reentrant and should be faster). Use only strsep() in new code, please. > > - * > > - * * Sat Feb 09 2002, Jason Thomas , > > - * Matthew Hawkins > > - * - Kissed strtok() goodbye > > + * Other helper functions should live in string_helpers.c. > > */ > > > > +#define __NO_FORTIFY > > #include > > #include > > #include > > @@ -237,40 +232,6 @@ ssize_t strscpy(char *dest, const char *src, size_t count) > > EXPORT_SYMBOL(strscpy); > > #endif > > > > -/** > > - * strscpy_pad() - Copy a C-string into a sized buffer > > - * @dest: Where to copy the string to > > - * @src: Where to copy the string from > > - * @count: Size of destination buffer > > - * > > - * Copy the string, or as much of it as fits, into the dest buffer. The > > - * behavior is undefined if the string buffers overlap. The destination > > - * buffer is always %NUL terminated, unless it's zero-sized. > > - * > > - * If the source string is shorter than the destination buffer, zeros > > - * the tail of the destination buffer. > > - * > > - * For full explanation of why you may want to consider using the > > - * 'strscpy' functions please see the function docstring for strscpy(). > > - * > > - * Returns: > > - * * The number of characters copied (not including the trailing %NUL) > > - * * -E2BIG if count is 0 or @src was truncated. > > - */ > > -ssize_t strscpy_pad(char *dest, const char *src, size_t count) > > -{ > > - ssize_t written; > > - > > - written = strscpy(dest, src, count); > > - if (written < 0 || written == count - 1) > > - return written; > > - > > - memset(dest + written + 1, 0, count - written - 1); > > - > > - return written; > > -} > > -EXPORT_SYMBOL(strscpy_pad); > > - > > /** > > * stpcpy - copy a string from src to dest returning a pointer to the new end > > * of dest, including src's %NUL-terminator. May overrun dest. > > @@ -513,46 +474,6 @@ char *strnchr(const char *s, size_t count, int c) > > EXPORT_SYMBOL(strnchr); > > #endif > > > > -/** > > - * skip_spaces - Removes leading whitespace from @str. > > - * @str: The string to be stripped. > > - * > > - * Returns a pointer to the first non-whitespace character in @str. > > - */ > > -char *skip_spaces(const char *str) > > -{ > > - while (isspace(*str)) > > - ++str; > > - return (char *)str; > > -} > > -EXPORT_SYMBOL(skip_spaces); > > - > > -/** > > - * strim - Removes leading and trailing whitespace from @s. > > - * @s: The string to be stripped. > > - * > > - * Note that the first trailing whitespace is replaced with a %NUL-terminator > > - * in the given string @s. Returns a pointer to the first non-whitespace > > - * character in @s. > > - */ > > -char *strim(char *s) > > -{ > > - size_t size; > > - char *end; > > - > > - size = strlen(s); > > - if (!size) > > - return s; > > - > > - end = s + size - 1; > > - while (end >= s && isspace(*end)) > > - end--; > > - *(end + 1) = '\0'; > > - > > - return skip_spaces(s); > > -} > > -EXPORT_SYMBOL(strim); > > - > > #ifndef __HAVE_ARCH_STRLEN > > /** > > * strlen - Find the length of a string > > @@ -687,101 +608,6 @@ char *strsep(char **s, const char *ct) > > EXPORT_SYMBOL(strsep); > > #endif > > > > -/** > > - * sysfs_streq - return true if strings are equal, modulo trailing newline > > - * @s1: one string > > - * @s2: another string > > - * > > - * This routine returns true iff two strings are equal, treating both > > - * NUL and newline-then-NUL as equivalent string terminations. It's > > - * geared for use with sysfs input strings, which generally terminate > > - * with newlines but are compared against values without newlines. > > - */ > > -bool sysfs_streq(const char *s1, const char *s2) > > -{ > > - while (*s1 && *s1 == *s2) { > > - s1++; > > - s2++; > > - } > > - > > - if (*s1 == *s2) > > - return true; > > - if (!*s1 && *s2 == '\n' && !s2[1]) > > - return true; > > - if (*s1 == '\n' && !s1[1] && !*s2) > > - return true; > > - return false; > > -} > > -EXPORT_SYMBOL(sysfs_streq); > > - > > -/** > > - * match_string - matches given string in an array > > - * @array: array of strings > > - * @n: number of strings in the array or -1 for NULL terminated arrays > > - * @string: string to match with > > - * > > - * This routine will look for a string in an array of strings up to the > > - * n-th element in the array or until the first NULL element. > > - * > > - * Historically the value of -1 for @n, was used to search in arrays that > > - * are NULL terminated. However, the function does not make a distinction > > - * when finishing the search: either @n elements have been compared OR > > - * the first NULL element was found. > > - * > > - * Return: > > - * index of a @string in the @array if matches, or %-EINVAL otherwise. > > - */ > > -int match_string(const char * const *array, size_t n, const char *string) > > -{ > > - int index; > > - const char *item; > > - > > - for (index = 0; index < n; index++) { > > - item = array[index]; > > - if (!item) > > - break; > > - if (!strcmp(item, string)) > > - return index; > > - } > > - > > - return -EINVAL; > > -} > > -EXPORT_SYMBOL(match_string); > > - > > -/** > > - * __sysfs_match_string - matches given string in an array > > - * @array: array of strings > > - * @n: number of strings in the array or -1 for NULL terminated arrays > > - * @str: string to match with > > - * > > - * Returns index of @str in the @array or -EINVAL, just like match_string(). > > - * Uses sysfs_streq instead of strcmp for matching. > > - * > > - * This routine will look for a string in an array of strings up to the > > - * n-th element in the array or until the first NULL element. > > - * > > - * Historically the value of -1 for @n, was used to search in arrays that > > - * are NULL terminated. However, the function does not make a distinction > > - * when finishing the search: either @n elements have been compared OR > > - * the first NULL element was found. > > - */ > > -int __sysfs_match_string(const char * const *array, size_t n, const char *str) > > -{ > > - const char *item; > > - int index; > > - > > - for (index = 0; index < n; index++) { > > - item = array[index]; > > - if (!item) > > - break; > > - if (sysfs_streq(item, str)) > > - return index; > > - }? > > - > > - return -EINVAL; > > -} > > -EXPORT_SYMBOL(__sysfs_match_string); > > - > > are memset16, memset32, and memset64 worth moving as well? Also, > memscan(), check_bytes(), memchr_inv()? All of these are implementations, so they should stay put. > > > #ifndef __HAVE_ARCH_MEMSET > > /** > > * memset - Fill a region of memory with the given value > > @@ -1125,27 +951,3 @@ void *memchr_inv(const void *start, int c, size_t bytes) > > return check_bytes8(start, value, bytes % 8); > > } > > EXPORT_SYMBOL(memchr_inv); > > - > > -/** > > - * strreplace - Replace all occurrences of character in string. > > - * @s: The string to operate on. > > - * @old: The character being replaced. > > - * @new: The character @old is replaced with. > > - * > > - * Returns pointer to the nul byte at the end of @s. > > - */ > > -char *strreplace(char *s, char old, char new) > > -{ > > - for (; *s; ++s) > > - if (*s == old) > > - *s = new; > > - return s; > > -} > > -EXPORT_SYMBOL(strreplace); > > - > > -void fortify_panic(const char *name) > > -{ > > - pr_emerg("detected buffer overflow in %s\n", name); > > - BUG(); > > -} > > -EXPORT_SYMBOL(fortify_panic); > > diff --git a/lib/string_helpers.c b/lib/string_helpers.c > > index 5a35c7e16e96..e9433caab217 100644 > > --- a/lib/string_helpers.c > > +++ b/lib/string_helpers.c > > @@ -692,3 +692,196 @@ void kfree_strarray(char **array, size_t n) > > kfree(array); > > } > > EXPORT_SYMBOL_GPL(kfree_strarray); > > + > > +/** > > + * strscpy_pad() - Copy a C-string into a sized buffer > > + * @dest: Where to copy the string to > > + * @src: Where to copy the string from > > + * @count: Size of destination buffer > > + * > > + * Copy the string, or as much of it as fits, into the dest buffer. The > > + * behavior is undefined if the string buffers overlap. The destination > > + * buffer is always %NUL terminated, unless it's zero-sized. > > + * > > + * If the source string is shorter than the destination buffer, zeros > > + * the tail of the destination buffer. > > + * > > + * For full explanation of why you may want to consider using the > > + * 'strscpy' functions please see the function docstring for strscpy(). > > + * > > + * Returns: > > + * * The number of characters copied (not including the trailing %NUL) > > + * * -E2BIG if count is 0 or @src was truncated. > > + */ > > +ssize_t strscpy_pad(char *dest, const char *src, size_t count) > > +{ > > + ssize_t written; > > + > > + written = strscpy(dest, src, count); > > + if (written < 0 || written == count - 1) > > + return written; > > + > > + memset(dest + written + 1, 0, count - written - 1); > > + > > + return written; > > +} > > +EXPORT_SYMBOL(strscpy_pad); > > + > > +/** > > + * skip_spaces - Removes leading whitespace from @str. > > + * @str: The string to be stripped. > > + * > > + * Returns a pointer to the first non-whitespace character in @str. > > + */ > > +char *skip_spaces(const char *str) > > +{ > > + while (isspace(*str)) > > + ++str; > > + return (char *)str; > > +} > > +EXPORT_SYMBOL(skip_spaces); > > + > > +/** > > + * strim - Removes leading and trailing whitespace from @s. > > + * @s: The string to be stripped. > > + * > > + * Note that the first trailing whitespace is replaced with a %NUL-terminator > > + * in the given string @s. Returns a pointer to the first non-whitespace > > + * character in @s. > > + */ > > +char *strim(char *s) > > +{ > > + size_t size; > > + char *end; > > + > > + size = strlen(s); > > + if (!size) > > + return s; > > + > > + end = s + size - 1; > > + while (end >= s && isspace(*end)) > > + end--; > > + *(end + 1) = '\0'; > > + > > + return skip_spaces(s); > > +} > > +EXPORT_SYMBOL(strim); > > + > > +/** > > + * sysfs_streq - return true if strings are equal, modulo trailing newline > > + * @s1: one string > > + * @s2: another string > > + * > > + * This routine returns true iff two strings are equal, treating both > > + * NUL and newline-then-NUL as equivalent string terminations. It's > > + * geared for use with sysfs input strings, which generally terminate > > + * with newlines but are compared against values without newlines. > > + */ > > +bool sysfs_streq(const char *s1, const char *s2) > > +{ > > + while (*s1 && *s1 == *s2) { > > + s1++; > > + s2++; > > + } > > + > > + if (*s1 == *s2) > > + return true; > > + if (!*s1 && *s2 == '\n' && !s2[1]) > > + return true; > > + if (*s1 == '\n' && !s1[1] && !*s2) > > + return true; > > + return false; > > +} > > +EXPORT_SYMBOL(sysfs_streq); > > + > > +/** > > + * match_string - matches given string in an array > > + * @array: array of strings > > + * @n: number of strings in the array or -1 for NULL terminated arrays > > + * @string: string to match with > > + * > > + * This routine will look for a string in an array of strings up to the > > + * n-th element in the array or until the first NULL element. > > + * > > + * Historically the value of -1 for @n, was used to search in arrays that > > + * are NULL terminated. However, the function does not make a distinction > > + * when finishing the search: either @n elements have been compared OR > > + * the first NULL element was found. > > + * > > + * Return: > > + * index of a @string in the @array if matches, or %-EINVAL otherwise. > > + */ > > +int match_string(const char * const *array, size_t n, const char *string) > > +{ > > + int index; > > + const char *item; > > + > > + for (index = 0; index < n; index++) { > > + item = array[index]; > > + if (!item) > > + break; > > + if (!strcmp(item, string)) > > + return index; > > + } > > + > > + return -EINVAL; > > +} > > +EXPORT_SYMBOL(match_string); > > + > > +/** > > + * __sysfs_match_string - matches given string in an array > > + * @array: array of strings > > + * @n: number of strings in the array or -1 for NULL terminated arrays > > + * @str: string to match with > > + * > > + * Returns index of @str in the @array or -EINVAL, just like match_string(). > > + * Uses sysfs_streq instead of strcmp for matching. > > + * > > + * This routine will look for a string in an array of strings up to the > > + * n-th element in the array or until the first NULL element. > > + * > > + * Historically the value of -1 for @n, was used to search in arrays that > > + * are NULL terminated. However, the function does not make a distinction > > + * when finishing the search: either @n elements have been compared OR > > + * the first NULL element was found. > > + */ > > +int __sysfs_match_string(const char * const *array, size_t n, const char *str) > > +{ > > + const char *item; > > + int index; > > + > > + for (index = 0; index < n; index++) { > > + item = array[index]; > > + if (!item) > > + break; > > + if (sysfs_streq(item, str)) > > + return index; > > + } > > + > > + return -EINVAL; > > +} > > +EXPORT_SYMBOL(__sysfs_match_string); > > + > > +/** > > + * strreplace - Replace all occurrences of character in string. > > + * @s: The string to operate on. > > + * @old: The character being replaced. > > + * @new: The character @old is replaced with. > > + * > > + * Returns pointer to the nul byte at the end of @s. > > + */ > > +char *strreplace(char *s, char old, char new) > > +{ > > + for (; *s; ++s) > > + if (*s == old) > > + *s = new; > > + return s; > > +} > > +EXPORT_SYMBOL(strreplace); > > + > > +void fortify_panic(const char *name) > > +{ > > + pr_emerg("detected buffer overflow in %s\n", name); > > + BUG(); > > +} > > +EXPORT_SYMBOL(fortify_panic); > > -- > > > -- > Thanks, > ~Nick Desaulniers -- Kees Cook