Commit da7a59ff authored by Dave Jones's avatar Dave Jones Committed by Linus Torvalds

[PATCH] documentation for userspace access.

From: Jon Foster <jon@jon-foster.co.uk>

This patch against 2.5.63 adds kerneldoc comments to the public API in these files:
- include/asm-i386/uaccess.h
- arch/i386/lib/usercopy.c

This patch only changes comments and one of the templates used by "make htmldocs",
it does not change any code.
parent 470aab84
...@@ -89,7 +89,11 @@ KAO --> ...@@ -89,7 +89,11 @@ KAO -->
<title>Memory Management in Linux</title> <title>Memory Management in Linux</title>
<sect1><title>The Slab Cache</title> <sect1><title>The Slab Cache</title>
!Emm/slab.c !Emm/slab.c
</sect1> </sect1>
<sect1><title>User Space Memory Access</title>
!Iinclude/asm-i386/uaccess.h
!Iarch/i386/lib/usercopy.c
</sect1>
</chapter> </chapter>
<chapter id="proc"> <chapter id="proc">
......
...@@ -50,6 +50,26 @@ do { \ ...@@ -50,6 +50,26 @@ do { \
: "memory"); \ : "memory"); \
} while (0) } while (0)
/**
* __strncpy_from_user: - Copy a NULL terminated string from userspace, with less checking.
* @dst: Destination address, in kernel space. This buffer must be at
* least @count bytes long.
* @src: Source address, in user space.
* @count: Maximum number of bytes to copy, including the trailing NULL.
*
* Copies a NULL-terminated string from userspace to kernel space.
* Caller must check the specified block with access_ok() before calling
* this function.
*
* On success, returns the length of the string (not including the trailing
* NULL).
*
* If access to userspace fails, returns -EFAULT (some data may have been
* copied).
*
* If @count is smaller than the length of the string, copies @count bytes
* and returns @count.
*/
long long
__strncpy_from_user(char *dst, const char *src, long count) __strncpy_from_user(char *dst, const char *src, long count)
{ {
...@@ -58,6 +78,24 @@ __strncpy_from_user(char *dst, const char *src, long count) ...@@ -58,6 +78,24 @@ __strncpy_from_user(char *dst, const char *src, long count)
return res; return res;
} }
/**
* strncpy_from_user: - Copy a NULL terminated string from userspace.
* @dst: Destination address, in kernel space. This buffer must be at
* least @count bytes long.
* @src: Source address, in user space.
* @count: Maximum number of bytes to copy, including the trailing NULL.
*
* Copies a NULL-terminated string from userspace to kernel space.
*
* On success, returns the length of the string (not including the trailing
* NULL).
*
* If access to userspace fails, returns -EFAULT (some data may have been
* copied).
*
* If @count is smaller than the length of the string, copies @count bytes
* and returns @count.
*/
long long
strncpy_from_user(char *dst, const char *src, long count) strncpy_from_user(char *dst, const char *src, long count)
{ {
...@@ -93,6 +131,16 @@ do { \ ...@@ -93,6 +131,16 @@ do { \
: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \ : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \
} while (0) } while (0)
/**
* clear_user: - Zero a block of memory in user space.
* @to: Destination address, in user space.
* @n: Number of bytes to zero.
*
* Zero a block of memory in user space.
*
* Returns number of bytes that could not be cleared.
* On success, this will be zero.
*/
unsigned long unsigned long
clear_user(void *to, unsigned long n) clear_user(void *to, unsigned long n)
{ {
...@@ -101,6 +149,17 @@ clear_user(void *to, unsigned long n) ...@@ -101,6 +149,17 @@ clear_user(void *to, unsigned long n)
return n; return n;
} }
/**
* __clear_user: - Zero a block of memory in user space, with less checking.
* @to: Destination address, in user space.
* @n: Number of bytes to zero.
*
* Zero a block of memory in user space. Caller must check
* the specified block with access_ok() before calling this function.
*
* Returns number of bytes that could not be cleared.
* On success, this will be zero.
*/
unsigned long unsigned long
__clear_user(void *to, unsigned long n) __clear_user(void *to, unsigned long n)
{ {
...@@ -108,12 +167,17 @@ __clear_user(void *to, unsigned long n) ...@@ -108,12 +167,17 @@ __clear_user(void *to, unsigned long n)
return n; return n;
} }
/* /**
* Return the size of a string (including the ending 0) * strlen_user: - Get the size of a string in user space.
* @s: The string to measure.
* @n: The maximum valid length
* *
* Return 0 on exception, a value greater than N if too long * Get the size of a NULL-terminated string in user space.
*
* Returns the size of the string INCLUDING the terminating NULL.
* On exception, returns 0.
* If the string is too long, returns a value greater than @n.
*/ */
long strnlen_user(const char *s, long n) long strnlen_user(const char *s, long n)
{ {
unsigned long mask = -__addr_ok(s); unsigned long mask = -__addr_ok(s);
......
...@@ -47,7 +47,13 @@ int __verify_write(const void *, unsigned long); ...@@ -47,7 +47,13 @@ int __verify_write(const void *, unsigned long);
#define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg)) #define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
/* /*
* Uhhuh, this needs 33-bit arithmetic. We have a carry.. * Test whether a block of memory is a valid user space address.
* Returns 0 if the range is valid, nonzero otherwise.
*
* This is equivalent to the following test:
* (u33)addr + (u33)size >= (u33)current->addr_limit.seg
*
* This needs 33-bit arithmetic. We have a carry...
*/ */
#define __range_ok(addr,size) ({ \ #define __range_ok(addr,size) ({ \
unsigned long flag,sum; \ unsigned long flag,sum; \
...@@ -58,6 +64,25 @@ int __verify_write(const void *, unsigned long); ...@@ -58,6 +64,25 @@ int __verify_write(const void *, unsigned long);
#ifdef CONFIG_X86_WP_WORKS_OK #ifdef CONFIG_X86_WP_WORKS_OK
/**
* access_ok: - Checks if a user space pointer is valid
* @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that
* %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
* to write to a block, it is always safe to read from it.
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
* Context: User context only. This function may sleep.
*
* Checks if a pointer to a block of memory in user space is valid.
*
* Returns true (nonzero) if the memory block may be valid, false (zero)
* if it is definitely invalid.
*
* Note that, depending on architecture, this function probably just
* checks that the pointer is in the user space range - after calling
* this function, memory access functions may still return -EFAULT.
*/
#define access_ok(type,addr,size) (__range_ok(addr,size) == 0) #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
#else #else
...@@ -68,6 +93,23 @@ int __verify_write(const void *, unsigned long); ...@@ -68,6 +93,23 @@ int __verify_write(const void *, unsigned long);
#endif #endif
/**
* verify_area: - Obsolete, use access_ok()
* @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
* @addr: User space pointer to start of block to check
* @size: Size of block to check
*
* Context: User context only. This function may sleep.
*
* This function has been replaced by access_ok().
*
* Checks if a pointer to a block of memory in user space is valid.
*
* Returns zero if the memory block may be valid, -EFAULT
* if it is definitely invalid.
*
* See access_ok() for more details.
*/
static inline int verify_area(int type, const void * addr, unsigned long size) static inline int verify_area(int type, const void * addr, unsigned long size)
{ {
return access_ok(type,addr,size) ? 0 : -EFAULT; return access_ok(type,addr,size) ? 0 : -EFAULT;
...@@ -118,7 +160,25 @@ extern void __get_user_4(void); ...@@ -118,7 +160,25 @@ extern void __get_user_4(void);
:"=a" (ret),"=d" (x) \ :"=a" (ret),"=d" (x) \
:"0" (ptr)) :"0" (ptr))
/* Careful: we have to cast the result to the type of the pointer for sign reasons */ /* Careful: we have to cast the result to the type of the pointer for sign reasons */
/**
* get_user: - Get a simple variable from user space.
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
* Context: User context only. This function may sleep.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
* data types like structures or arrays.
*
* @ptr must have pointer-to-simple-variable type, and the result of
* dereferencing @ptr must be assignable to @x without a cast.
*
* Returns zero on success, or -EFAULT on error.
* On error, the variable @x is set to zero.
*/
#define get_user(x,ptr) \ #define get_user(x,ptr) \
({ int __ret_gu,__val_gu; \ ({ int __ret_gu,__val_gu; \
switch(sizeof (*(ptr))) { \ switch(sizeof (*(ptr))) { \
...@@ -138,11 +198,70 @@ extern void __put_user_8(void); ...@@ -138,11 +198,70 @@ extern void __put_user_8(void);
extern void __put_user_bad(void); extern void __put_user_bad(void);
/**
* put_user: - Write a simple value into user space.
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
* Context: User context only. This function may sleep.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
* data types like structures or arrays.
*
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
* to the result of dereferencing @ptr.
*
* Returns zero on success, or -EFAULT on error.
*/
#define put_user(x,ptr) \ #define put_user(x,ptr) \
__put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
/**
* __get_user: - Get a simple variable from user space, with less checking.
* @x: Variable to store result.
* @ptr: Source address, in user space.
*
* Context: User context only. This function may sleep.
*
* This macro copies a single simple variable from user space to kernel
* space. It supports simple types like char and int, but not larger
* data types like structures or arrays.
*
* @ptr must have pointer-to-simple-variable type, and the result of
* dereferencing @ptr must be assignable to @x without a cast.
*
* Caller must check the pointer with access_ok() before calling this
* function.
*
* Returns zero on success, or -EFAULT on error.
* On error, the variable @x is set to zero.
*/
#define __get_user(x,ptr) \ #define __get_user(x,ptr) \
__get_user_nocheck((x),(ptr),sizeof(*(ptr))) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
/**
* __put_user: - Write a simple value into user space, with less checking.
* @x: Value to copy to user space.
* @ptr: Destination address, in user space.
*
* Context: User context only. This function may sleep.
*
* This macro copies a single simple value from kernel space to user
* space. It supports simple types like char and int, but not larger
* data types like structures or arrays.
*
* @ptr must have pointer-to-simple-variable type, and @x must be assignable
* to the result of dereferencing @ptr.
*
* Caller must check the pointer with access_ok() before calling this
* function.
*
* Returns zero on success, or -EFAULT on error.
*/
#define __put_user(x,ptr) \ #define __put_user(x,ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
...@@ -263,6 +382,21 @@ unsigned long __copy_from_user_ll(void *to, const void *from, unsigned long n); ...@@ -263,6 +382,21 @@ unsigned long __copy_from_user_ll(void *to, const void *from, unsigned long n);
* If a store crosses a page boundary and gets a fault, the x86 will not write * If a store crosses a page boundary and gets a fault, the x86 will not write
* anything, so this is accurate. * anything, so this is accurate.
*/ */
/**
* __copy_to_user: - Copy a block of data into user space, with less checking.
* @to: Destination address, in user space.
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from kernel space to user space. Caller must check
* the specified block with access_ok() before calling this function.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*/
static inline unsigned long static inline unsigned long
__copy_to_user(void *to, const void *from, unsigned long n) __copy_to_user(void *to, const void *from, unsigned long n)
{ {
...@@ -284,6 +418,23 @@ __copy_to_user(void *to, const void *from, unsigned long n) ...@@ -284,6 +418,23 @@ __copy_to_user(void *to, const void *from, unsigned long n)
return __copy_to_user_ll(to, from, n); return __copy_to_user_ll(to, from, n);
} }
/**
* __copy_from_user: - Copy a block of data from user space, with less checking.
* @to: Destination address, in kernel space.
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from user space to kernel space. Caller must check
* the specified block with access_ok() before calling this function.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*
* If some data could not be copied, this function will pad the copied
* data to the requested size using zero bytes.
*/
static inline unsigned long static inline unsigned long
__copy_from_user(void *to, const void *from, unsigned long n) __copy_from_user(void *to, const void *from, unsigned long n)
{ {
...@@ -305,6 +456,19 @@ __copy_from_user(void *to, const void *from, unsigned long n) ...@@ -305,6 +456,19 @@ __copy_from_user(void *to, const void *from, unsigned long n)
return __copy_from_user_ll(to, from, n); return __copy_from_user_ll(to, from, n);
} }
/**
* copy_to_user: - Copy a block of data into user space.
* @to: Destination address, in user space.
* @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from kernel space to user space.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*/
static inline unsigned long static inline unsigned long
copy_to_user(void *to, const void *from, unsigned long n) copy_to_user(void *to, const void *from, unsigned long n)
{ {
...@@ -313,6 +477,22 @@ copy_to_user(void *to, const void *from, unsigned long n) ...@@ -313,6 +477,22 @@ copy_to_user(void *to, const void *from, unsigned long n)
return n; return n;
} }
/**
* copy_from_user: - Copy a block of data from user space.
* @to: Destination address, in kernel space.
* @from: Source address, in user space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
* Copy data from user space to kernel space.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
*
* If some data could not be copied, this function will pad the copied
* data to the requested size using zero bytes.
*/
static inline unsigned long static inline unsigned long
copy_from_user(void *to, const void *from, unsigned long n) copy_from_user(void *to, const void *from, unsigned long n)
{ {
...@@ -323,7 +503,23 @@ copy_from_user(void *to, const void *from, unsigned long n) ...@@ -323,7 +503,23 @@ copy_from_user(void *to, const void *from, unsigned long n)
long strncpy_from_user(char *dst, const char *src, long count); long strncpy_from_user(char *dst, const char *src, long count);
long __strncpy_from_user(char *dst, const char *src, long count); long __strncpy_from_user(char *dst, const char *src, long count);
/**
* strlen_user: - Get the size of a string in user space.
* @str: The string to measure.
*
* Context: User context only. This function may sleep.
*
* Get the size of a NULL-terminated string in user space.
*
* Returns the size of the string INCLUDING the terminating NULL.
* 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.
*/
#define strlen_user(str) strnlen_user(str, ~0UL >> 1) #define strlen_user(str) strnlen_user(str, ~0UL >> 1)
long strnlen_user(const char *str, long n); long strnlen_user(const char *str, long n);
unsigned long clear_user(void *mem, unsigned long len); unsigned long clear_user(void *mem, unsigned long len);
unsigned long __clear_user(void *mem, unsigned long len); unsigned long __clear_user(void *mem, unsigned long len);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment