Accessing the Process Address Space

System call service routines often need to read or write data contained in the process's address space. Linux includes a set of macros that make this access easier. We'll describe two of them, called get_user( ) and put_user( ). The first can be used to read 1, 2, or

4 consecutive bytes from an address, while the second can be used to write data of those sizes into an address.

Each function accepts two arguments, a value x to transfer and a variable ptr. The second variable also determines how many bytes to transfer. Thus, in get_user(x,ptr), the size of the variable pointed to by ptr causes the function to expand into a__get_user_l( ),

_get_user_2( ), or__get_user_4( ) assembly language function. Let's consider one of them,__get_user_2( ):

get_user_2: addl $1, %eax jc bad_get_user movl %esp, %edx andl $0xffffe000, %edx cmpl 12(%edx), %eax jae bad_get_user 2: movzwl -1(%eax), %edx xorl %eax, %eax ret bad_get_user:

The eax register contains the address ptr of the first byte to be read. The first six instructions essentially perform the same checks as the verify_area( ) functions: they ensure that the 2 bytes to be read have addresses less than 4 GB as well as less than the addr_limit.seg field of the current process. (This field is stored at offset 12 in the process descriptor, which appears in the first operand of the cmpl instruction.)

If the addresses are valid, the function executes the movzwl instruction to store the data to be read in the two least significant bytes of edx register while setting the high-order bytes of edx to 0; then it sets a 0 return code in eax and terminates. If the addresses are not valid, the function clears edx, sets the -efault value into eax, and terminates.

The put_user(x,ptr) macro is similar to the one discussed before, except it writes the value x into the process address space starting from address ptr. Depending on the size of x, it invokes either the__put_user_asm( ) macro (size of 1, 2, or 4 bytes) or the _

_put_user_u64( ) macro (size of 8 bytes). Both macros return the value 0 in the eax register if they succeed in writing the value, and -efault otherwise.

Several other functions and macros are available to access the process address space in Kernel Mode; they are listed in Table 9-1. Notice that many of them also have a variant prefixed by two underscores (__). The ones without initial underscores take extra time to check the validity of the linear address interval requested, while the ones with the underscores bypass that check. Whenever the kernel must repeatedly access the same memory area in the process address space, it is more efficient to check the address once at the start and then access the process area without making any further checks.

Table 9-1. Functions and macros that access the process address space

Function

Action

get user get user

Reads an integer value from user space (1, 2, or 4 bytes)

put user put user

Writes an integer value to user space (1, 2, or 4 bytes)

copy from user copy from user

Copies a block of arbitrary size from user space

copy to user copy to user

Copies a block of arbitrary size to user space

strncpy from user strncpy from user

Copies a null-terminated string from user space

strlen_user strnlen user

Returns the length of a null-terminated string in user space

clear user clear user

Fills a memory area in user space with zeros

Was this article helpful?

0 0

Post a comment