mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	lib: introduce strncpy_from_unsafe()
generalize FETCH_FUNC_NAME(memory, string) into strncpy_from_unsafe() and fix sparse warnings that were present in original implementation. Signed-off-by: Alexei Starovoitov <ast@plumgrid.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									c9fd56b34e
								
							
						
					
					
						commit
						1a6877b9c0
					
				
					 3 changed files with 47 additions and 16 deletions
				
			
		| 
						 | 
					@ -129,4 +129,6 @@ extern long __probe_kernel_read(void *dst, const void *src, size_t size);
 | 
				
			||||||
extern long notrace probe_kernel_write(void *dst, const void *src, size_t size);
 | 
					extern long notrace probe_kernel_write(void *dst, const void *src, size_t size);
 | 
				
			||||||
extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size);
 | 
					extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif		/* __LINUX_UACCESS_H__ */
 | 
					#endif		/* __LINUX_UACCESS_H__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,11 +165,9 @@ DEFINE_BASIC_FETCH_FUNCS(memory)
 | 
				
			||||||
static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
 | 
					static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
 | 
				
			||||||
					    void *addr, void *dest)
 | 
										    void *addr, void *dest)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	long ret;
 | 
					 | 
				
			||||||
	int maxlen = get_rloc_len(*(u32 *)dest);
 | 
						int maxlen = get_rloc_len(*(u32 *)dest);
 | 
				
			||||||
	u8 *dst = get_rloc_data(dest);
 | 
						u8 *dst = get_rloc_data(dest);
 | 
				
			||||||
	u8 *src = addr;
 | 
						long ret;
 | 
				
			||||||
	mm_segment_t old_fs = get_fs();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!maxlen)
 | 
						if (!maxlen)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
| 
						 | 
					@ -178,23 +176,13 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
 | 
				
			||||||
	 * Try to get string again, since the string can be changed while
 | 
						 * Try to get string again, since the string can be changed while
 | 
				
			||||||
	 * probing.
 | 
						 * probing.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	set_fs(KERNEL_DS);
 | 
						ret = strncpy_from_unsafe(dst, addr, maxlen);
 | 
				
			||||||
	pagefault_disable();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	do
 | 
					 | 
				
			||||||
		ret = __copy_from_user_inatomic(dst++, src++, 1);
 | 
					 | 
				
			||||||
	while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	dst[-1] = '\0';
 | 
					 | 
				
			||||||
	pagefault_enable();
 | 
					 | 
				
			||||||
	set_fs(old_fs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ret < 0) {	/* Failed to fetch string */
 | 
						if (ret < 0) {	/* Failed to fetch string */
 | 
				
			||||||
		((u8 *)get_rloc_data(dest))[0] = '\0';
 | 
							dst[0] = '\0';
 | 
				
			||||||
		*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
 | 
							*(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		*(u32 *)dest = make_data_rloc(src - (u8 *)addr,
 | 
							*(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest));
 | 
				
			||||||
					      get_rloc_offs(*(u32 *)dest));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string));
 | 
					NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,3 +112,44 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
 | 
				
			||||||
	return -EFAULT;
 | 
						return -EFAULT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(strncpy_from_user);
 | 
					EXPORT_SYMBOL(strncpy_from_user);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address.
 | 
				
			||||||
 | 
					 * @dst:   Destination address, in kernel space.  This buffer must be at
 | 
				
			||||||
 | 
					 *         least @count bytes long.
 | 
				
			||||||
 | 
					 * @src:   Unsafe address.
 | 
				
			||||||
 | 
					 * @count: Maximum number of bytes to copy, including the trailing NUL.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copies a NUL-terminated string from unsafe address to kernel buffer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * On success, returns the length of the string INCLUDING the trailing NUL.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If access fails, returns -EFAULT (some data may have been copied
 | 
				
			||||||
 | 
					 * and the trailing NUL added).
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If @count is smaller than the length of the string, copies @count-1 bytes,
 | 
				
			||||||
 | 
					 * sets the last byte of @dst buffer to NUL and returns @count.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mm_segment_t old_fs = get_fs();
 | 
				
			||||||
 | 
						const void *src = unsafe_addr;
 | 
				
			||||||
 | 
						long ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(count <= 0))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						set_fs(KERNEL_DS);
 | 
				
			||||||
 | 
						pagefault_disable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						do {
 | 
				
			||||||
 | 
							ret = __copy_from_user_inatomic(dst++,
 | 
				
			||||||
 | 
											(const void __user __force *)src++, 1);
 | 
				
			||||||
 | 
						} while (dst[-1] && ret == 0 && src - unsafe_addr < count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dst[-1] = '\0';
 | 
				
			||||||
 | 
						pagefault_enable();
 | 
				
			||||||
 | 
						set_fs(old_fs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret < 0 ? ret : src - unsafe_addr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue