diff options
Diffstat (limited to 'include/linux/fortify-string.h')
| -rw-r--r-- | include/linux/fortify-string.h | 161 | 
1 files changed, 112 insertions, 49 deletions
diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index c9de1f59ee80..da51a83b2829 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -20,7 +20,7 @@ void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning("  ({								\  	char *__p = (char *)(p);				\  	size_t __ret = SIZE_MAX;				\ -	size_t __p_size = __member_size(p);			\ +	const size_t __p_size = __member_size(p);		\  	if (__p_size != SIZE_MAX &&				\  	    __builtin_constant_p(*__p)) {			\  		size_t __p_len = __p_size - 1;			\ @@ -142,7 +142,7 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size)  __FORTIFY_INLINE __diagnose_as(__builtin_strncpy, 1, 2, 3)  char *strncpy(char * const POS p, const char *q, __kernel_size_t size)  { -	size_t p_size = __member_size(p); +	const size_t p_size = __member_size(p);  	if (__compiletime_lessthan(p_size, size))  		__write_overflow(); @@ -151,33 +151,6 @@ char *strncpy(char * const POS p, const char *q, __kernel_size_t size)  	return __underlying_strncpy(p, q, size);  } -/** - * strcat - Append a string to an existing string - * - * @p: pointer to NUL-terminated string to append to - * @q: pointer to NUL-terminated source string to append from - * - * Do not use this function. While FORTIFY_SOURCE tries to avoid - * read and write overflows, this is only possible when the - * destination buffer size is known to the compiler. Prefer - * building the string with formatting, via scnprintf() or similar. - * At the very least, use strncat(). - * - * Returns @p. - * - */ -__FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2) -char *strcat(char * const POS p, const char *q) -{ -	size_t p_size = __member_size(p); - -	if (p_size == SIZE_MAX) -		return __underlying_strcat(p, q); -	if (strlcat(p, q, p_size) >= p_size) -		fortify_panic(__func__); -	return p; -} -  extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen);  /**   * strnlen - Return bounded count of characters in a NUL-terminated string @@ -191,8 +164,8 @@ extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(st   */  __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size_t maxlen)  { -	size_t p_size = __member_size(p); -	size_t p_len = __compiletime_strlen(p); +	const size_t p_size = __member_size(p); +	const size_t p_len = __compiletime_strlen(p);  	size_t ret;  	/* We can take compile-time actions when maxlen is const. */ @@ -233,8 +206,8 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char * const POS p, __kernel_size  __FORTIFY_INLINE __diagnose_as(__builtin_strlen, 1)  __kernel_size_t __fortify_strlen(const char * const POS p)  { +	const size_t p_size = __member_size(p);  	__kernel_size_t ret; -	size_t p_size = __member_size(p);  	/* Give up if we don't know how large p is. */  	if (p_size == SIZE_MAX) @@ -267,8 +240,8 @@ extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy);   */  __FORTIFY_INLINE size_t strlcpy(char * const POS p, const char * const POS q, size_t size)  { -	size_t p_size = __member_size(p); -	size_t q_size = __member_size(q); +	const size_t p_size = __member_size(p); +	const size_t q_size = __member_size(q);  	size_t q_len;	/* Full count of source string length. */  	size_t len;	/* Count of characters going into destination. */ @@ -299,8 +272,8 @@ extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy);   * @q: Where to copy the string from   * @size: Size of destination buffer   * - * Copy the source string @p, or as much of it as fits, into the destination - * @q buffer. The behavior is undefined if the string buffers overlap. The + * Copy the source string @q, or as much of it as fits, into the destination + * @p buffer. The behavior is undefined if the string buffers overlap. The   * destination @p buffer is always NUL terminated, unless it's zero-sized.   *   * Preferred to strlcpy() since the API doesn't require reading memory @@ -318,10 +291,10 @@ extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy);   */  __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, size_t size)  { -	size_t len;  	/* Use string size rather than possible enclosing struct size. */ -	size_t p_size = __member_size(p); -	size_t q_size = __member_size(q); +	const size_t p_size = __member_size(p); +	const size_t q_size = __member_size(q); +	size_t len;  	/* If we cannot get size of p and q default to call strscpy. */  	if (p_size == SIZE_MAX && q_size == SIZE_MAX) @@ -371,6 +344,96 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s  	return __real_strscpy(p, q, len);  } +/* Defined after fortified strlen() to reuse it. */ +extern size_t __real_strlcat(char *p, const char *q, size_t avail) __RENAME(strlcat); +/** + * strlcat - Append a string to an existing string + * + * @p: pointer to %NUL-terminated string to append to + * @q: pointer to %NUL-terminated string to append from + * @avail: Maximum bytes available in @p + * + * Appends %NUL-terminated string @q after the %NUL-terminated + * string at @p, but will not write beyond @avail bytes total, + * potentially truncating the copy from @q. @p will stay + * %NUL-terminated only if a %NUL already existed within + * the @avail bytes of @p. If so, the resulting number of + * bytes copied from @q will be at most "@avail - strlen(@p) - 1". + * + * Do not use this function. While FORTIFY_SOURCE tries to avoid + * read and write overflows, this is only possible when the sizes + * of @p and @q are known to the compiler. Prefer building the + * string with formatting, via scnprintf(), seq_buf, or similar. + * + * Returns total bytes that _would_ have been contained by @p + * regardless of truncation, similar to snprintf(). If return + * value is >= @avail, the string has been truncated. + * + */ +__FORTIFY_INLINE +size_t strlcat(char * const POS p, const char * const POS q, size_t avail) +{ +	const size_t p_size = __member_size(p); +	const size_t q_size = __member_size(q); +	size_t p_len, copy_len; +	size_t actual, wanted; + +	/* Give up immediately if both buffer sizes are unknown. */ +	if (p_size == SIZE_MAX && q_size == SIZE_MAX) +		return __real_strlcat(p, q, avail); + +	p_len = strnlen(p, avail); +	copy_len = strlen(q); +	wanted = actual = p_len + copy_len; + +	/* Cannot append any more: report truncation. */ +	if (avail <= p_len) +		return wanted; + +	/* Give up if string is already overflowed. */ +	if (p_size <= p_len) +		fortify_panic(__func__); + +	if (actual >= avail) { +		copy_len = avail - p_len - 1; +		actual = p_len + copy_len; +	} + +	/* Give up if copy will overflow. */ +	if (p_size <= actual) +		fortify_panic(__func__); +	__underlying_memcpy(p + p_len, q, copy_len); +	p[actual] = '\0'; + +	return wanted; +} + +/* Defined after fortified strlcat() to reuse it. */ +/** + * strcat - Append a string to an existing string + * + * @p: pointer to NUL-terminated string to append to + * @q: pointer to NUL-terminated source string to append from + * + * Do not use this function. While FORTIFY_SOURCE tries to avoid + * read and write overflows, this is only possible when the + * destination buffer size is known to the compiler. Prefer + * building the string with formatting, via scnprintf() or similar. + * At the very least, use strncat(). + * + * Returns @p. + * + */ +__FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2) +char *strcat(char * const POS p, const char *q) +{ +	const size_t p_size = __member_size(p); + +	if (strlcat(p, q, p_size) >= p_size) +		fortify_panic(__func__); +	return p; +} +  /**   * strncat - Append a string to an existing string   * @@ -394,9 +457,9 @@ __FORTIFY_INLINE ssize_t strscpy(char * const POS p, const char * const POS q, s  __FORTIFY_INLINE __diagnose_as(__builtin_strncat, 1, 2, 3)  char *strncat(char * const POS p, const char * const POS q, __kernel_size_t count)  { +	const size_t p_size = __member_size(p); +	const size_t q_size = __member_size(q);  	size_t p_len, copy_len; -	size_t p_size = __member_size(p); -	size_t q_size = __member_size(q);  	if (p_size == SIZE_MAX && q_size == SIZE_MAX)  		return __underlying_strncat(p, q, count); @@ -639,7 +702,7 @@ __FORTIFY_INLINE bool fortify_memcpy_chk(__kernel_size_t size,  extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan);  __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size)  { -	size_t p_size = __struct_size(p); +	const size_t p_size = __struct_size(p);  	if (__compiletime_lessthan(p_size, size))  		__read_overflow(); @@ -651,8 +714,8 @@ __FORTIFY_INLINE void *memscan(void * const POS0 p, int c, __kernel_size_t size)  __FORTIFY_INLINE __diagnose_as(__builtin_memcmp, 1, 2, 3)  int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t size)  { -	size_t p_size = __struct_size(p); -	size_t q_size = __struct_size(q); +	const size_t p_size = __struct_size(p); +	const size_t q_size = __struct_size(q);  	if (__builtin_constant_p(size)) {  		if (__compiletime_lessthan(p_size, size)) @@ -668,7 +731,7 @@ int memcmp(const void * const POS0 p, const void * const POS0 q, __kernel_size_t  __FORTIFY_INLINE __diagnose_as(__builtin_memchr, 1, 2, 3)  void *memchr(const void * const POS0 p, int c, __kernel_size_t size)  { -	size_t p_size = __struct_size(p); +	const size_t p_size = __struct_size(p);  	if (__compiletime_lessthan(p_size, size))  		__read_overflow(); @@ -680,7 +743,7 @@ void *memchr(const void * const POS0 p, int c, __kernel_size_t size)  void *__real_memchr_inv(const void *s, int c, size_t n) __RENAME(memchr_inv);  __FORTIFY_INLINE void *memchr_inv(const void * const POS0 p, int c, size_t size)  { -	size_t p_size = __struct_size(p); +	const size_t p_size = __struct_size(p);  	if (__compiletime_lessthan(p_size, size))  		__read_overflow(); @@ -693,7 +756,7 @@ extern void *__real_kmemdup(const void *src, size_t len, gfp_t gfp) __RENAME(kme  								    __realloc_size(2);  __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp)  { -	size_t p_size = __struct_size(p); +	const size_t p_size = __struct_size(p);  	if (__compiletime_lessthan(p_size, size))  		__read_overflow(); @@ -720,8 +783,8 @@ __FORTIFY_INLINE void *kmemdup(const void * const POS0 p, size_t size, gfp_t gfp  __FORTIFY_INLINE __diagnose_as(__builtin_strcpy, 1, 2)  char *strcpy(char * const POS p, const char * const POS q)  { -	size_t p_size = __member_size(p); -	size_t q_size = __member_size(q); +	const size_t p_size = __member_size(p); +	const size_t q_size = __member_size(q);  	size_t size;  	/* If neither buffer size is known, immediately give up. */  | 
