Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932854AbbGHUVh (ORCPT ); Wed, 8 Jul 2015 16:21:37 -0400 Received: from mail-db3on0087.outbound.protection.outlook.com ([157.55.234.87]:54816 "EHLO emea01-db3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1759024AbbGHUVR (ORCPT ); Wed, 8 Jul 2015 16:21:17 -0400 Authentication-Results: spf=fail (sender IP is 12.216.194.146) smtp.mailfrom=ezchip.com; vger.kernel.org; dkim=none (message not signed) header.d=none; From: Chris Metcalf To: Linus Torvalds CC: Chris Metcalf , Al Viro , Fabian Frederick , Randy Dunlap , Rickard Strandqvist , , Peter Zijlstra , "David S. Miller" , Frederic Weisbecker , Andrew Morton , Sam Ravnborg , Stephen Rothwell , "Theodore Ts'o" , Grant Likely , Dan Carpenter , Geert Uytterhoeven , Michael Ellerman , Linux Kernel Mailing List , Subject: [PATCH v2 2/3] string: provide strscpy() Date: Wed, 8 Jul 2015 16:20:44 -0400 Message-ID: <1436386845-11989-3-git-send-email-cmetcalf@ezchip.com> X-Mailer: git-send-email 2.1.2 In-Reply-To: <1436386845-11989-1-git-send-email-cmetcalf@ezchip.com> References: <1436386845-11989-1-git-send-email-cmetcalf@ezchip.com> X-EOPAttributedMessage: 0 X-Microsoft-Exchange-Diagnostics: 1;DB3FFO11FD042;1:1mzk8Zf06oKDaIPxK8s86vxZFyEP6ToK3kl10hl3/KXl4USQYYbHSxf/nsaAUUiertd7rqS89XL3ShTJDdwjjKCP8xxSSOnO1Q0cdE5OaS/6qSTJxyu1yG1gMjq8UNzZxg5q/tINaGi1OxFBxrfgTiIScBpkqNPXRZ8NY2bDHn4JIHvmeIyAEm7p12sltJ4p++LNJ65pp+RtWV5hR9BBcTwwXdM+FMJaC0EF1XvdzUk2REXnjMX2lQesS5BGRMOAk9oclQVv/uN1nfWK5trhQh8SgIxuPnlrC3lO3UbbQ7TfN1AZLn9utvmyCASOTWUMoILni9I8Sbe+URhgfh9NVbUkPAL1UFJIk1yOh5ZAC9yPM/Ah1tMX5glAa1cO/ylX3RwxEZ3LoKunvYUCltNZu5gfTNWbbOdkPLXJU1gxLGHjHhLUqnAuTFWf7ww3NrBR X-Forefront-Antispam-Report: CIP:12.216.194.146;CTRY:US;IPV:NLI;EFV:NLI;SFV:NSPM;SFS:(10009020)(6009001)(2980300002)(339900001)(199003)(189002)(36756003)(48376002)(87936001)(229853001)(50466002)(46102003)(104016003)(92566002)(33646002)(76176999)(575784001)(50986999)(189998001)(85426001)(42186005)(86362001)(106466001)(6806004)(47776003)(5003940100001)(62966003)(77156002)(50226001)(5001960100002)(110136002)(105606002)(19580395003)(2950100001)(19580405001);DIR:OUT;SFP:1101;SCL:1;SRVR:VI1PR02MB0784;H:ld-1.internal.tilera.com;FPR:;SPF:Fail;MLV:sfv;A:1;MX:1;LANG:en; MIME-Version: 1.0 Content-Type: text/plain X-Microsoft-Exchange-Diagnostics: 1;VI1PR02MB0784;2:g9UZSOuDnA+gdG2nQcG38IRy8Y77RDvWkBVZMEbUw7L3eSvusuv0EjqI1DGS8Gzl;3:IJd/NFeQZ+xIxnQK1qvNi+1Fw6EwL0zn70pGNiX9nHHvb3KfGPDTq13sSkK/+asIB3WF0SPps4Vea/0BFzse+U8h2yhZml7FnXgkRGUx0fBF5i0JbpyKuT2nqenZeynL5BwGS1yMkmznYdTsl76bUA2IIxFevQUGNEARwzNy1AxgGQuL++/1v/vbpXXvy+AT2rLQCvinkTJ2SMUgZ4ZfrnBUW59ILLnEzgI0Jc0UMGqg/r2HLmq6LbDb/bZ0MxTr;25:mPqRMHFENU5DV7wrkAzn317DS/fO6YpWRN6wLi7ALYLnkJAtjzHoKV52tOHov0XEL2DNNEc94KS4yI9iEURuvd9othRWVsa1hNdr6DnjgRMtm9dhIEs9i5eqYSvp0OnxySDi/3HKVGi1dSwN/wnNv0Fua/R8fsL3jPw0iyHGH7vztsh3k/e/ji3HWKQ4Mrilid20QcJCaLphY9MWRpbsQN5YH3IN/7DCkVhusMDjCqkHQDpNh/Ac+Pszi6TshXOtyU/K8LJUxXDZmHeiNCtpwg==;20:2/HQ6IRfcnsZUiwYttyhRrQKf/XiJgjwCaze6D3vgcGfe4TFAWNS9iZntQskA37OnMpUhSkBiWkb4Po5JGLyx4EREtUPd2KdWDzigKTf3whphfREGDXqu0MLyB/AbIZevDaOMI1zyUL4oestYY5quPvqIFP8bswVJKZ3JxfLbi0= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:VI1PR02MB0784; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(5005006)(3002001);SRVR:VI1PR02MB0784;BCL:0;PCL:0;RULEID:;SRVR:VI1PR02MB0784; X-Microsoft-Exchange-Diagnostics: 1;VI1PR02MB0784;4:FMDDq8FJ5x4t20ssSJtw9HZCGlq1kjAxR8PQvwNLxU9l1Dm0PIgw2UHNow9JsfGPweMM1f0598hfXFo5B6oWGGfDPQGwq7Lc83Vdr1Fggoe9ZMtamjguf3S5KOuuuU3DJYCH4552SITIxkWsuioWMDi7O6Ma2oflvG3TBuNfpl9cavYdL6IKgL4vnlRVI+4+5P1cGu41U14rIHPX4naiF7ojJqLUUm/nQNilF5j/aO480mXp5KcC++pC2sdl+RjY4zZ0ML+Zw0yjqi/qzJuXXafC7p1PMsJ2fxA+WmjgG20= X-Forefront-PRVS: 0631F0BC3D X-Microsoft-Exchange-Diagnostics: 1;VI1PR02MB0784;23:EfI1G3Oui+PtyV7o9/n5uwAJpCfskhnlBELe8Qu0hpxd8xjg8K7PGcIzahIyH4+1MexpJo1CJzy9s+8CFmgmXmFTN51AcnrlHrvi4Cuw8kU2BF3iopYofH6/5Dqb81LVWWMmsQzDPAgJic8qE6+vf9D1eEw2YP3DjR7YQYdfy2ofb88hB6HQICirGHpjianqWFeFZpPiz3BBuxBatgvwuH65Ky9patlWB9pP0dCOBWaqhTqdD6/2cW614uHDxFOi7CAuId+PW5+toDk3VCME8Vz6MlEhdE1FsMaUPsbqEIJK1rvoeEEXea4ad7LfK+tyVGwaFqto+1wq14QvaVuF+aHjHLkGx0kcuDoDENfGLWY+NewrOMIdAwsHrjhUKA+5dHSEW7DB0iuXJg8owtQk+HX5Mfaoo5G4TYhrfMIuN4K0qP5SuC1q17cOW6VPlO4XjSg2AIrAgaUK2eXR4VVtg0Ib2cL95hJTyPlaMXDr0AoIZ3L0Pod5nAmM6yqJbJCSD++h48MEGM6V4jail+HWx16nx/V6WbibEO7VM+tTerHAquS/Y9lf5YnCrqwZKXkO0R9wyHYJVzPHYmHbci89LzgqRIqDoKYskGULu/ZAu110FMhzpFSIwymoZnDOHppT6ySKWYVf3vmO1hPs4NKCa5Qy9c9R0dekiAe08cF3oRIMV8mv7OSbZyacPW6JDI8YGka9YP+nYHQ2XyLI0vHQUcdxEoCTgVHYNxz5LVrw7fPvIYNbxoKqCZrj+6JxU/7vg8g7h7FBR4SDCtozlb1pUTecIzbfoWM16YeBfUCN69TQGvXWpquuGHP2DriQ/lpgH+CFcp8FUNd1WAYuDcU+mGFAqoN4Jk1cq6+YFqksunpJWQ564rjgdsXLj+0aE6N0jqU61u1+RvIDFKR73VGjZUav7kjNe2eQ7MrYyE6d2DI= X-Microsoft-Exchange-Diagnostics: 1;VI1PR02MB0784;5:hnZBam50Sc+opdysodHIRgv+qeay4xyvlwp4mfFlO87QDDi1AYer3nd+p2IlGKKpllDknYhe5PIuNUhOztIj5HDRw302fj4QAQuhMTLv7Q5s5LcILifMv4GloR1u8dDhlKBpVOcu/2pd+RpKnHfbSw==;24:t5l+YN+2mUktqWdb0PL+w0wjk9r2USi1A9AaaBWv8DrpICkZyKTcQ4kIv2Ohru59MHFA8sEAWUoPvvUzggwVC+jvE9okrpwhIHoA7tKbLZY=;20:x+8kj+vbDNeFOFPVDeBBFWzh3U2Rb/0+YPER9qj2Jb7YBfIHsRaBHGIp2juPqMz/zR4jiu1qAoNgOiqXIwqC4A== SpamDiagnosticOutput: 1:23 SpamDiagnosticMetadata: NSPM X-OriginatorOrg: ezchip.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 08 Jul 2015 20:21:11.3253 (UTC) X-MS-Exchange-CrossTenant-Id: 0fc16e0a-3cd3-4092-8b2f-0a42cff122c3 X-MS-Exchange-CrossTenant-OriginalAttributedTenantConnectingIp: TenantId=0fc16e0a-3cd3-4092-8b2f-0a42cff122c3;Ip=[12.216.194.146];Helo=[ld-1.internal.tilera.com] X-MS-Exchange-CrossTenant-FromEntityHeader: HybridOnPrem X-MS-Exchange-Transport-CrossTenantHeadersStamped: VI1PR02MB0784 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5218 Lines: 159 The strscpy() API is intended to be used instead of strlcpy(), and instead of most uses of strncpy(). - Unlike strlcpy(), it doesn't read from memory beyond (src + size). - Unlike strlcpy() or strncpy(), the API provides an easy way to check for destination buffer overflow: an -E2BIG error return value. - The provided implementation is robust in the face of the source buffer being asynchronously changed during the copy, unlike the current implementation of strlcpy(). - Unlike strncpy(), the destination buffer will be NUL-terminated if the string in the source buffer is too long. - Also unlike strncpy(), the destination buffer will not be updated beyond the NUL termination, avoiding strncpy's behavior of zeroing the entire tail end of the destination buffer. (A memset() after the strscpy() can be used if this behavior is desired.) - The implementation should be reasonably performant on all platforms since it uses the asm/word-at-a-time.h API rather than simple byte copy. Kernel-to-kernel string copy is not considered to be performance critical in any case. Signed-off-by: Chris Metcalf --- include/linux/string.h | 3 ++ lib/string.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/linux/string.h b/include/linux/string.h index e40099e585c9..213274a0d356 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -25,6 +25,9 @@ extern char * strncpy(char *,const char *, __kernel_size_t); #ifndef __HAVE_ARCH_STRLCPY size_t strlcpy(char *, const char *, size_t); #endif +#ifndef __HAVE_ARCH_STRSCPY +ssize_t __must_check strscpy(char *, const char *, size_t); +#endif #ifndef __HAVE_ARCH_STRCAT extern char * strcat(char *, const char *); #endif diff --git a/lib/string.c b/lib/string.c index a5792019193c..0ff54eb78f52 100644 --- a/lib/string.c +++ b/lib/string.c @@ -27,6 +27,10 @@ #include #include +#include +#include +#include + #ifndef __HAVE_ARCH_STRNCASECMP /** * strncasecmp - Case insensitive, length-limited string comparison @@ -146,6 +150,90 @@ size_t strlcpy(char *dest, const char *src, size_t size) EXPORT_SYMBOL(strlcpy); #endif +#ifndef __HAVE_ARCH_STRSCPY +/** + * strscpy - 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 routine returns the number of characters copied (not including + * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough. + * The behavior is undefined if the string buffers overlap. + * If the destination buffer isn't big enough, it is NUL terminated. + * + * Preferred to strlcpy() since the API doesn't require reading memory + * from the src string beyond the specified "count" bytes, and since + * the return value is easier to error-check than strlcpy()'s. + * In addition, the implementation is robust to the string changing out + * from underneath it, unlike the current strlcpy() implementation. + * + * Preferred to strncpy() since it always returns a valid string, and + * doesn't unnecessarily force the tail of the destination buffer to be + * zeroed. If the zeroing is desired, it's likely cleaner to use strscpy() + * with an overflow test, then just memset() the tail of the dest buffer. + */ +ssize_t strscpy(char *dest, const char *src, size_t count) +{ + const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; + size_t max = count; + long res = 0; + + if (count == 0) + return -E2BIG; + +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + /* + * If src is unaligned, don't cross a page boundary, + * since we don't know if the next page is mapped. + */ + if ((long)src & (sizeof(long) - 1)) { + size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1)); + if (limit < max) + max = limit; + } +#else + /* If src or dest is unaligned, don't do word-at-a-time. */ + if (((long) dest | (long) src) & (sizeof(long) - 1)) + max = 0; +#endif + + while (max >= sizeof(unsigned long)) { + unsigned long c, data; + + c = *(unsigned long *)(src+res); + *(unsigned long *)(dest+res) = c; + if (has_zero(c, &data, &constants)) { + data = prep_zero_mask(c, data, &constants); + data = create_zero_mask(data); + return res + find_zero(data); + } + res += sizeof(unsigned long); + count -= sizeof(unsigned long); + max -= sizeof(unsigned long); + } + + while (count) { + char c; + + c = src[res]; + dest[res] = c; + if (!c) + return res; + res++; + count--; + } + + /* Hit buffer length without finding a NUL; force NUL-termination. */ + if (res) + dest[res-1] = '\0'; + + return -E2BIG; +} +EXPORT_SYMBOL(strscpy); +#endif + #ifndef __HAVE_ARCH_STRCAT /** * strcat - Append one %NUL-terminated string to another -- 2.1.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/