162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/kernel.h> 362306a36Sopenharmony_ci#include <linux/export.h> 462306a36Sopenharmony_ci#include <linux/uaccess.h> 562306a36Sopenharmony_ci#include <linux/mm.h> 662306a36Sopenharmony_ci#include <linux/bitops.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <asm/word-at-a-time.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* 1162306a36Sopenharmony_ci * Do a strnlen, return length of string *with* final '\0'. 1262306a36Sopenharmony_ci * 'count' is the user-supplied count, while 'max' is the 1362306a36Sopenharmony_ci * address space maximum. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Return 0 for exceptions (which includes hitting the address 1662306a36Sopenharmony_ci * space maximum), or 'count+1' if hitting the user-supplied 1762306a36Sopenharmony_ci * maximum count. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * NOTE! We can sometimes overshoot the user-supplied maximum 2062306a36Sopenharmony_ci * if it fits in a aligned 'long'. The caller needs to check 2162306a36Sopenharmony_ci * the return value against "> max". 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cistatic __always_inline long do_strnlen_user(const char __user *src, unsigned long count, unsigned long max) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; 2662306a36Sopenharmony_ci unsigned long align, res = 0; 2762306a36Sopenharmony_ci unsigned long c; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci /* 3062306a36Sopenharmony_ci * Do everything aligned. But that means that we 3162306a36Sopenharmony_ci * need to also expand the maximum.. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ci align = (sizeof(unsigned long) - 1) & (unsigned long)src; 3462306a36Sopenharmony_ci src -= align; 3562306a36Sopenharmony_ci max += align; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci unsafe_get_user(c, (unsigned long __user *)src, efault); 3862306a36Sopenharmony_ci c |= aligned_byte_mask(align); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci for (;;) { 4162306a36Sopenharmony_ci unsigned long data; 4262306a36Sopenharmony_ci if (has_zero(c, &data, &constants)) { 4362306a36Sopenharmony_ci data = prep_zero_mask(c, data, &constants); 4462306a36Sopenharmony_ci data = create_zero_mask(data); 4562306a36Sopenharmony_ci return res + find_zero(data) + 1 - align; 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci res += sizeof(unsigned long); 4862306a36Sopenharmony_ci /* We already handled 'unsigned long' bytes. Did we do it all ? */ 4962306a36Sopenharmony_ci if (unlikely(max <= sizeof(unsigned long))) 5062306a36Sopenharmony_ci break; 5162306a36Sopenharmony_ci max -= sizeof(unsigned long); 5262306a36Sopenharmony_ci unsafe_get_user(c, (unsigned long __user *)(src+res), efault); 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci res -= align; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci /* 5762306a36Sopenharmony_ci * Uhhuh. We hit 'max'. But was that the user-specified maximum 5862306a36Sopenharmony_ci * too? If so, return the marker for "too long". 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci if (res >= count) 6162306a36Sopenharmony_ci return count+1; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* 6462306a36Sopenharmony_ci * Nope: we hit the address space limit, and we still had more 6562306a36Sopenharmony_ci * characters the caller would have wanted. That's 0. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ciefault: 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/** 7262306a36Sopenharmony_ci * strnlen_user: - Get the size of a user string INCLUDING final NUL. 7362306a36Sopenharmony_ci * @str: The string to measure. 7462306a36Sopenharmony_ci * @count: Maximum count (including NUL character) 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * Context: User context only. This function may sleep if pagefaults are 7762306a36Sopenharmony_ci * enabled. 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * Get the size of a NUL-terminated string in user space. 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * Returns the size of the string INCLUDING the terminating NUL. 8262306a36Sopenharmony_ci * If the string is too long, returns a number larger than @count. User 8362306a36Sopenharmony_ci * has to check the return value against "> count". 8462306a36Sopenharmony_ci * On exception (or invalid count), returns 0. 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * NOTE! You should basically never use this function. There is 8762306a36Sopenharmony_ci * almost never any valid case for using the length of a user space 8862306a36Sopenharmony_ci * string, since the string can be changed at any time by other 8962306a36Sopenharmony_ci * threads. Use "strncpy_from_user()" instead to get a stable copy 9062306a36Sopenharmony_ci * of the string. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cilong strnlen_user(const char __user *str, long count) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci unsigned long max_addr, src_addr; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (unlikely(count <= 0)) 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci max_addr = TASK_SIZE_MAX; 10062306a36Sopenharmony_ci src_addr = (unsigned long)untagged_addr(str); 10162306a36Sopenharmony_ci if (likely(src_addr < max_addr)) { 10262306a36Sopenharmony_ci unsigned long max = max_addr - src_addr; 10362306a36Sopenharmony_ci long retval; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* 10662306a36Sopenharmony_ci * Truncate 'max' to the user-specified limit, so that 10762306a36Sopenharmony_ci * we only have one limit we need to check in the loop 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci if (max > count) 11062306a36Sopenharmony_ci max = count; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (user_read_access_begin(str, max)) { 11362306a36Sopenharmony_ci retval = do_strnlen_user(str, count, max); 11462306a36Sopenharmony_ci user_read_access_end(); 11562306a36Sopenharmony_ci return retval; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ciEXPORT_SYMBOL(strnlen_user); 121