2019-05-19 15:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2008-04-17 22:05:36 +04:00
/*
* Access kernel memory without faulting .
*/
2011-10-16 10:01:52 +04:00
# include <linux/export.h>
2008-04-17 22:05:36 +04:00
# include <linux/mm.h>
2010-10-27 20:29:01 +04:00
# include <linux/uaccess.h>
2008-04-17 22:05:36 +04:00
2019-05-15 08:38:18 +03:00
static __always_inline long
probe_read_common ( void * dst , const void __user * src , size_t size )
{
long ret ;
pagefault_disable ( ) ;
ret = __copy_from_user_inatomic ( dst , src , size ) ;
pagefault_enable ( ) ;
return ret ? - EFAULT : 0 ;
}
2019-11-02 02:17:56 +03:00
static __always_inline long
probe_write_common ( void __user * dst , const void * src , size_t size )
{
long ret ;
pagefault_disable ( ) ;
ret = __copy_to_user_inatomic ( dst , src , size ) ;
pagefault_enable ( ) ;
return ret ? - EFAULT : 0 ;
}
2008-04-17 22:05:36 +04:00
/**
2020-06-09 07:34:07 +03:00
* probe_kernel_read ( ) : safely attempt to read from any location
2008-04-17 22:05:36 +04:00
* @ dst : pointer to the buffer that shall take the data
* @ src : address to read from
* @ size : size of the data chunk
*
2020-06-09 07:34:07 +03:00
* Same as probe_kernel_read_strict ( ) except that for architectures with
* not fully separated user and kernel address spaces this function also works
* for user address tanges .
*
* DO NOT USE THIS FUNCTION - it is broken on architectures with entirely
* separate kernel and user address spaces , and also a bad idea otherwise .
*/
long __weak probe_kernel_read ( void * dst , const void * src , size_t size )
__attribute__ ( ( alias ( " __probe_kernel_read " ) ) ) ;
/**
* probe_kernel_read_strict ( ) : safely attempt to read from kernel - space
* @ dst : pointer to the buffer that shall take the data
* @ src : address to read from
* @ size : size of the data chunk
*
* Safely read from kernel address @ src to the buffer at @ dst . If a kernel
* fault happens , handle that and return - EFAULT .
2015-11-06 05:46:03 +03:00
*
* We ensure that the copy_from_user is executed in atomic context so that
2020-06-09 07:33:54 +03:00
* do_page_fault ( ) doesn ' t attempt to take mmap_lock . This makes
2015-11-06 05:46:03 +03:00
* probe_kernel_read ( ) suitable for use within regions where the caller
2020-06-09 07:33:54 +03:00
* already holds mmap_lock , or other locks which nest inside mmap_lock .
2008-04-17 22:05:36 +04:00
*/
2010-01-07 20:58:36 +03:00
2019-11-02 02:17:57 +03:00
long __weak probe_kernel_read_strict ( void * dst , const void * src , size_t size )
__attribute__ ( ( alias ( " __probe_kernel_read " ) ) ) ;
2011-05-19 22:35:33 +04:00
long __probe_kernel_read ( void * dst , const void * src , size_t size )
2008-04-17 22:05:36 +04:00
{
long ret ;
2008-02-20 22:33:38 +03:00
mm_segment_t old_fs = get_fs ( ) ;
2008-04-17 22:05:36 +04:00
2008-02-20 22:33:38 +03:00
set_fs ( KERNEL_DS ) ;
2019-05-15 08:38:18 +03:00
ret = probe_read_common ( dst , ( __force const void __user * ) src , size ) ;
2008-02-20 22:33:38 +03:00
set_fs ( old_fs ) ;
2008-04-17 22:05:36 +04:00
2019-05-15 08:38:18 +03:00
return ret ;
2008-04-17 22:05:36 +04:00
}
EXPORT_SYMBOL_GPL ( probe_kernel_read ) ;
2019-05-15 08:38:18 +03:00
/**
* probe_user_read ( ) : safely attempt to read from a user - space location
* @ dst : pointer to the buffer that shall take the data
* @ src : address to read from . This must be a user address .
* @ size : size of the data chunk
*
* Safely read from user address @ src to the buffer at @ dst . If a kernel fault
* happens , handle that and return - EFAULT .
*/
2020-06-09 07:34:01 +03:00
long probe_user_read ( void * dst , const void __user * src , size_t size )
2019-05-15 08:38:18 +03:00
{
long ret = - EFAULT ;
mm_segment_t old_fs = get_fs ( ) ;
set_fs ( USER_DS ) ;
if ( access_ok ( src , size ) )
ret = probe_read_common ( dst , src , size ) ;
set_fs ( old_fs ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( probe_user_read ) ;
2008-04-17 22:05:36 +04:00
/**
* probe_kernel_write ( ) : safely attempt to write to a location
* @ dst : address to write to
* @ src : pointer to the data that shall be written
* @ size : size of the data chunk
*
* Safely write to address @ dst from the buffer at @ src . If a kernel fault
* happens , handle that and return - EFAULT .
*/
2020-06-09 07:34:01 +03:00
long probe_kernel_write ( void * dst , const void * src , size_t size )
2008-04-17 22:05:36 +04:00
{
long ret ;
2008-02-20 22:33:38 +03:00
mm_segment_t old_fs = get_fs ( ) ;
2008-04-17 22:05:36 +04:00
2008-02-20 22:33:38 +03:00
set_fs ( KERNEL_DS ) ;
2019-11-02 02:17:56 +03:00
ret = probe_write_common ( ( __force void __user * ) dst , src , size ) ;
2008-02-20 22:33:38 +03:00
set_fs ( old_fs ) ;
2008-04-17 22:05:36 +04:00
2019-11-02 02:17:56 +03:00
return ret ;
2008-04-17 22:05:36 +04:00
}
2015-08-31 18:57:10 +03:00
2019-11-02 02:17:56 +03:00
/**
* probe_user_write ( ) : safely attempt to write to a user - space location
* @ dst : address to write to
* @ src : pointer to the data that shall be written
* @ size : size of the data chunk
*
* Safely write to address @ dst from the buffer at @ src . If a kernel fault
* happens , handle that and return - EFAULT .
*/
2020-06-09 07:34:01 +03:00
long probe_user_write ( void __user * dst , const void * src , size_t size )
2019-11-02 02:17:56 +03:00
{
long ret = - EFAULT ;
mm_segment_t old_fs = get_fs ( ) ;
set_fs ( USER_DS ) ;
if ( access_ok ( dst , size ) )
ret = probe_write_common ( dst , src , size ) ;
set_fs ( old_fs ) ;
return ret ;
}
EXPORT_SYMBOL_GPL ( probe_user_write ) ;
2019-05-15 08:38:18 +03:00
2015-08-31 18:57:10 +03:00
/**
* 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 .
2018-02-07 02:42:16 +03:00
* @ unsafe_addr : Unsafe address .
2015-08-31 18:57:10 +03:00
* @ 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 .
2019-11-02 02:17:57 +03:00
*
2020-06-09 07:34:07 +03:00
* Same as strncpy_from_unsafe_strict ( ) except that for architectures with
* not fully separated user and kernel address spaces this function also works
* for user address tanges .
*
* DO NOT USE THIS FUNCTION - it is broken on architectures with entirely
* separate kernel and user address spaces , and also a bad idea otherwise .
2015-08-31 18:57:10 +03:00
*/
2019-11-02 02:17:57 +03:00
long __weak strncpy_from_unsafe ( char * dst , const void * unsafe_addr , long count )
__attribute__ ( ( alias ( " __strncpy_from_unsafe " ) ) ) ;
2020-06-09 07:34:07 +03:00
/**
* strncpy_from_unsafe_strict : - Copy a NUL terminated string from unsafe
* address .
* @ dst : Destination address , in kernel space . This buffer must be at
* least @ count bytes long .
* @ unsafe_addr : 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 .
*/
2019-11-02 02:17:57 +03:00
long __weak strncpy_from_unsafe_strict ( char * dst , const void * unsafe_addr ,
long count )
__attribute__ ( ( alias ( " __strncpy_from_unsafe " ) ) ) ;
long __strncpy_from_unsafe ( char * dst , const void * unsafe_addr , long count )
2015-08-31 18:57:10 +03:00
{
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 {
2016-05-23 03:21:27 +03:00
ret = __get_user ( * dst + + , ( const char __user __force * ) src + + ) ;
2015-08-31 18:57:10 +03:00
} while ( dst [ - 1 ] & & ret = = 0 & & src - unsafe_addr < count ) ;
dst [ - 1 ] = ' \0 ' ;
pagefault_enable ( ) ;
set_fs ( old_fs ) ;
2015-11-06 05:50:11 +03:00
return ret ? - EFAULT : src - unsafe_addr ;
2015-08-31 18:57:10 +03:00
}
2019-05-15 08:38:18 +03:00
/**
* strncpy_from_unsafe_user : - Copy a NUL terminated string from unsafe user
* address .
* @ dst : Destination address , in kernel space . This buffer must be at
* least @ count bytes long .
* @ unsafe_addr : Unsafe user address .
* @ count : Maximum number of bytes to copy , including the trailing NUL .
*
* Copies a NUL - terminated string from unsafe user 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_user ( char * dst , const void __user * unsafe_addr ,
long count )
{
mm_segment_t old_fs = get_fs ( ) ;
long ret ;
if ( unlikely ( count < = 0 ) )
return 0 ;
set_fs ( USER_DS ) ;
pagefault_disable ( ) ;
ret = strncpy_from_user ( dst , unsafe_addr , count ) ;
pagefault_enable ( ) ;
set_fs ( old_fs ) ;
if ( ret > = count ) {
ret = count ;
dst [ ret - 1 ] = ' \0 ' ;
} else if ( ret > 0 ) {
ret + + ;
}
return ret ;
}
/**
* strnlen_unsafe_user : - Get the size of a user string INCLUDING final NUL .
* @ unsafe_addr : The string to measure .
* @ count : Maximum count ( including NUL )
*
* Get the size of a NUL - terminated string in user space without pagefault .
*
* Returns the size of the string INCLUDING the terminating NUL .
*
* If the string is too long , returns a number larger than @ count . User
* has to check the return value against " > count " .
* On exception ( or invalid count ) , returns 0.
*
* Unlike strnlen_user , this can be used from IRQ handler etc . because
* it disables pagefaults .
*/
long strnlen_unsafe_user ( const void __user * unsafe_addr , long count )
{
mm_segment_t old_fs = get_fs ( ) ;
int ret ;
set_fs ( USER_DS ) ;
pagefault_disable ( ) ;
ret = strnlen_user ( unsafe_addr , count ) ;
pagefault_enable ( ) ;
set_fs ( old_fs ) ;
return ret ;
}