The kernel often needs to copy data from userspace to kernel space; for example, when lengthy data structures are passed indirectly in system calls by means of pointers. There is a similar need to write data in the reverse direction from kernel space to userspace.
This cannot be done simply by passing and de-referencing pointers for two reasons. First, userspace programs must not access kernel addresses; and second, there is no guarantee that a virtual page belonging to a pointer from userspace is really associated with a physical page. The kernel therefore provides several standard functions to cater for these special situations when data are exchanged between kernel space and userspace. They are shown in summary form in Table 4-2.
Table 4-2: Standard Functions for Exchanging Data between Userspace and Kernel Space
Table 4-2: Standard Functions for Exchanging Data between Userspace and Kernel Space
copy_from_user(to, from, n) _copy_from_user
Copies a string of n bytes from from (userspace) to to (kernel space).
get_user(type *to, type* ptr) _get_user
Reads a simple variable (char, long, . ) from ptr to to; depending on pointer type, the kernel decides automatically to transfer 1, 2, 4, or 8 bytes.
strncopy_from_user(to, from, n) _strncopy_from_user
Copies a null-terminated string with a maximum of n characters from from (userspace) to to (kernel space).
put_user(type *from, type *to) _put_user
Copies a simple value from from (kernel space) to to (userspace); the relevant value is determined automatically from the pointer type passed.
copy_to_user(to, from, n) _copy_to_user
Copies n bytes from from (kernel space) to to (userspace).
Table 4-3 lists additional helper functions for working with strings from userspace. These functions are subject to the same restrictions as the functions for copying data.
get_user and put_user function correctly only when applied to pointers to "simple" data types such as char, int, and so on. They do not function with compound data types or arrays because of the pointer arithmetic required (and owing to the necessary implementation optimizations). Before structs can be exchanged between userspace and kernel space, it is necessary to copy the data and then convert it to the correct type by means of typecasts.
Table 4-3: Standard Functions for Working with Strings in Userspace Data
clear_user(to, n) _clear_user Fills the next n bytes after to with zeros.
strlen_user(s) _strlen_user Gets the size of a null-terminated string in userspace (includ
ing the terminating character).
strnlen_user(s, n) _strnlen_user Gets the size of a null-terminated string but restricts the
search to a maximum of n characters.
As the tables show, there are two versions of most of the functions. In the versions without preceding underscores, access_user is also invoked to perform checks on the userspace address; the checks carried out differ from architecture to architecture. For example, one check ensures that a pointer really points to a position in the user segment; another invokes handle_mm_fault if pages are not found in memory to make sure that data are read in for processing. All functions also apply the fixup mechanism described above to detect and correct page faults.
The functions are implemented mainly in assembler language. They are extremely performance-critical because they are invoked so frequently. The exception code must also be integrated using complicated GNU C constructions to embed assembler and linker directives in the code. It is not my intention to discuss the implementation of the individual functions in detail.
A checker tool was added to the compilation process during the development of kernel 2.5. It analyzes the sources to check whether userspace pointers can be de-referenced directly without the need for the above
functions. The pointers originating from userspace must be labeled with the keyword_user so that the
tool knows which pointers to check. One particular example is the chroot system call, which expects a filename as argument. Many, many more places in the kernel contain similarly marked arguments from userspace.
Was this article helpful?