2012-05-26 22:06:38 +04:00
# include <linux/kernel.h>
# include <linux/export.h>
# include <linux/uaccess.h>
# include <asm/word-at-a-time.h>
/* Set bits in the first 'n' bytes when loaded from memory */
# ifdef __LITTLE_ENDIAN
# define aligned_byte_mask(n) ((1ul << 8*(n))-1)
# else
2012-05-28 06:59:56 +04:00
# define aligned_byte_mask(n) (~0xfful << (BITS_PER_LONG - 8 - 8*(n)))
2012-05-26 22:06:38 +04:00
# endif
/*
* Do a strnlen , return length of string * with * final ' \0 ' .
* ' count ' is the user - supplied count , while ' max ' is the
* address space maximum .
*
* Return 0 for exceptions ( which includes hitting the address
* space maximum ) , or ' count + 1 ' if hitting the user - supplied
* maximum count .
*
* NOTE ! We can sometimes overshoot the user - supplied maximum
* if it fits in a aligned ' long ' . The caller needs to check
* the return value against " > max " .
*/
static inline long do_strnlen_user ( const char __user * src , unsigned long count , unsigned long max )
{
const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS ;
long align , res = 0 ;
unsigned long c ;
/*
* Truncate ' max ' to the user - specified limit , so that
* we only have one limit we need to check in the loop
*/
if ( max > count )
max = count ;
/*
* Do everything aligned . But that means that we
* need to also expand the maximum . .
*/
align = ( sizeof ( long ) - 1 ) & ( unsigned long ) src ;
src - = align ;
max + = align ;
2015-12-17 21:05:19 +03:00
if ( unlikely ( unsafe_get_user ( c , ( unsigned long __user * ) src ) ) )
2012-05-26 22:06:38 +04:00
return 0 ;
c | = aligned_byte_mask ( align ) ;
for ( ; ; ) {
unsigned long data ;
if ( has_zero ( c , & data , & constants ) ) {
data = prep_zero_mask ( c , data , & constants ) ;
data = create_zero_mask ( data ) ;
return res + find_zero ( data ) + 1 - align ;
}
res + = sizeof ( unsigned long ) ;
2015-06-02 18:10:28 +03:00
/* We already handled 'unsigned long' bytes. Did we do it all ? */
if ( unlikely ( max < = sizeof ( unsigned long ) ) )
2012-05-26 22:06:38 +04:00
break ;
max - = sizeof ( unsigned long ) ;
2015-12-17 21:05:19 +03:00
if ( unlikely ( unsafe_get_user ( c , ( unsigned long __user * ) ( src + res ) ) ) )
2012-05-26 22:06:38 +04:00
return 0 ;
}
res - = align ;
/*
* Uhhuh . We hit ' max ' . But was that the user - specified maximum
* too ? If so , return the marker for " too long " .
*/
if ( res > = count )
return count + 1 ;
/*
* Nope : we hit the address space limit , and we still had more
* characters the caller would have wanted . That ' s 0.
*/
return 0 ;
}
/**
* strnlen_user : - Get the size of a user string INCLUDING final NUL .
* @ str : The string to measure .
* @ count : Maximum count ( including NUL character )
*
2015-05-11 18:52:08 +03:00
* Context : User context only . This function may sleep if pagefaults are
* enabled .
2012-05-26 22:06:38 +04:00
*
* Get the size of a NUL - terminated string in user space .
*
* Returns the size of the string INCLUDING the terminating NUL .
2015-06-03 16:50:35 +03:00
* If the string is too long , returns a number larger than @ count . User
* has to check the return value against " > count " .
2012-05-26 22:06:38 +04:00
* On exception ( or invalid count ) , returns 0.
2015-06-03 16:50:35 +03:00
*
* NOTE ! You should basically never use this function . There is
* almost never any valid case for using the length of a user space
* string , since the string can be changed at any time by other
* threads . Use " strncpy_from_user() " instead to get a stable copy
* of the string .
2012-05-26 22:06:38 +04:00
*/
long strnlen_user ( const char __user * str , long count )
{
unsigned long max_addr , src_addr ;
if ( unlikely ( count < = 0 ) )
return 0 ;
max_addr = user_addr_max ( ) ;
src_addr = ( unsigned long ) str ;
if ( likely ( src_addr < max_addr ) ) {
unsigned long max = max_addr - src_addr ;
2015-12-17 21:05:19 +03:00
long retval ;
user_access_begin ( ) ;
retval = do_strnlen_user ( str , count , max ) ;
user_access_end ( ) ;
return retval ;
2012-05-26 22:06:38 +04:00
}
return 0 ;
}
EXPORT_SYMBOL ( strnlen_user ) ;
/**
* strlen_user : - Get the size of a user string INCLUDING final NUL .
* @ str : The string to measure .
*
2015-05-11 18:52:08 +03:00
* Context : User context only . This function may sleep if pagefaults are
* enabled .
2012-05-26 22:06:38 +04:00
*
* Get the size of a NUL - terminated string in user space .
*
* Returns the size of the string INCLUDING the terminating NUL .
* On exception , returns 0.
*
* If there is a limit on the length of a valid string , you may wish to
* consider using strnlen_user ( ) instead .
*/
long strlen_user ( const char __user * str )
{
unsigned long max_addr , src_addr ;
max_addr = user_addr_max ( ) ;
src_addr = ( unsigned long ) str ;
if ( likely ( src_addr < max_addr ) ) {
unsigned long max = max_addr - src_addr ;
2015-12-17 21:05:19 +03:00
long retval ;
user_access_begin ( ) ;
retval = do_strnlen_user ( str , ~ 0ul , max ) ;
user_access_end ( ) ;
return retval ;
2012-05-26 22:06:38 +04:00
}
return 0 ;
}
EXPORT_SYMBOL ( strlen_user ) ;