The first 2.1 versions of the kernel introduced a new (and better) way to access user space from kernel code. The change is meant to fix a long-standing misbehavior and to enhance system performance.
When you compile code for version 2.1 of the kernel and need to
access user space, you need to include <asm/uaccess.h>
instead
of <asm/segment.h>
. You must also use a different set of
functions from those in 2.0. Needless to say, the header sysdep-2.1.h
takes care of these differences as much as possible and allows you to use
the 2.1 semantics when compiling with 2.0.
The most noticeable difference in user access is that verify_area is gone, as most of the verification is performed by the CPU instead. See Section 17.10 later in this chapter for more details on this subject.
The new set of functions that can be used to access user space is:
int access_ok (int type, unsigned long addr,
,
unsigned long size);
This function returns true (1) if the current process is
allowed to access memory at address addr
, false
(0) otherwise. This function is a replacement for
verify_area, although it does less checking. It
receives the same arguments as the old
verify_area, but is much faster. The function
should be called to check a user-space address before you
dereference it; if you fail to check, the user might be able
to access and modify kernel memory. The section Section 17.9, later in the chapter, explains the
issue in more detail. Fortunately, most of the functions
described below take care of such checking for you, so you
won’t need to actually call access_ok, unless you
choose to.
int get_user (lvalue, address);
The get_user macro used by 2.1 kernels is
different from the one we used in 2.0. The return value is 0
in case of success or a negative error code (always
-EFAULT
). The net effect of the function is to
assign to lvalue
data retrieved using the
address
pointer. The first argument of the macro
must be an lvalue in the usual C-language
meaning.[43] Similar to the 2.0 version of the function, the
actual size of the data item depends on the type of the
address
argument. The function calls
access_ok internally.
int __get_user (lvalue, address);
This function is exactly like get_user, but it doesn’t call access_ok internally. You should call __get_user when you access a user address that has already been checked from within the same kernel function.
get_user_ret (lvalue, address, retval);
This macro is a shortcut that calls get_user and
returns retval
if the function fails.
int put_user (expression, address);
,
int __put_user (expression, address);
,
put_user_ret (expression, address, retval);
These functions behave exactly like the
get_ equivalents, but they write to user space instead
of reading from it. In case of success, the value expression
is written to address address
.
unsigned long copy_from_user (unsigned long to,
,
unsigned long from,
,
unsigned long len);
This function copies data bytes from user space to kernel
space. It replaces the old memcpy_fromfs call. The
function calls access_ok internally. The return value is
always the number of bytes not transferred. Thus, if an
error occurs, the return value is greater than 0; in that case,
the driver usually returns -EFAULT
, because the
error is caused by a faulty memory access.
unsigned long __copy_from_user (unsigned long to,
,
unsigned long from,
,
unsigned long len);
This function is identical to copy_from_user, but it doesn’t call access_ok internally.
copy_from_user_ret (to, from, len, retval);
This macro is a shortcut that calls copy_from_user and returns from the current function if it fails.
unsigned long copy_to_user (unsigned long to,
,
unsigned long from,
,
unsigned long len);
,
unsigned long __copy_to_user (unsigned long to,
,
unsigned long from,
,
unsigned long len);
,
copy_to_user_ret (to, from, len, retval);
These functions are used to copy data to user space, and they behave exactly like their copy_from counterparts.
Version 2.1 of the kernel defines other functions for accessing user
space: clear_user, strncpy_from_user, and strlen_user.
I won’t comment on them because they are not available in Linux 2.0, and
because they are rarely needed by driver code. The interested reader
is urged to browse <asm/uaccess.h>
.
The new set of functions to access user space may look
disappointing at first, but they are meant to ultimately make life
easier for the programmer. With Linux 2.1, there’s no longer a need
to explicitly check user space; access_ok won’t usually
need to be called. The code using the new interface can just go ahead
and transfer
its data. The _ret functions, then, turn out to be
very useful when implementing system calls, because a failure in user-space
access usually results in a failure in the system call with
-EFAULT
.
The typical read implementation, therefore, will look like this:
long new_read(struct inode *inode, struct file *filp, char *buf, unsigned long count); { /* identify your data (device-specific code) */ if (__copy_to_user(buf, new_data, count)) return -EFAULT; return count; }
Note that the non-checking __copy_to_user function is used because the caller already checked the user address before dispatching data transfer to the file operations. This is just like 2.0, where read and write didn’t need to call verify_area.
Similarly, the typical ioctl implementation will look like the following:
int new_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); { /* device-specific checks, if needed */ switch(cmd) { case NEW_GETVALUE: put_user_ret(new_value,(int *)arg,-EFAULT); break; case NEW_SETVALUE: get_user_ret(new_value,(int *)arg,-EFAULT); break; default return -EINVAL; } return 0; }
Unlike the version 2.0 equivalent, this function doesn’t need
to check its arguments before the switch
statement, because
each get_user or put_user does the checking. An
alternative implementation is the following one:
int another_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); { int retval = -EINVAL, size = _IOC_SIZE(cmd); if (_IOC_DIR(cmd) & _IOC_READ) { if (!access_ok(VERIFY_WRITE, (void *)arg, size)) retturn -EFAULT; } else if (_IOC_DIR(cmd) & _IOC_WRITE) { if (!access_ok(VERIFY_READ, (void *)arg, size)) return -EFAULT switch(cmd) { case NEW_GETVALUE: retval = __put_user(another_value,arg); break; case NEW_SETVALUE: retval = __get_user(another_value,arg); break; } return retval; }
When you want to write code that compiles with both 2.0 and 2.1, on
the other hand, things become slightly more complicated, as you can’t
use the C preprocessor to fake the new behavior with older kernels.
You can’t just #define
a get_user macro that receives two
arguments, because the actual get_user implementation in version
2.0 is already a macro.
My own choice for writing code that is both portable and efficient is
to set up sysdep-2.1.h
to provide source code with the
following functions. Only the functions that read data are listed;
functions that write data behave in exactly the same way.
int access_ok(type, address, size);
This function is implemented in terms of verify_area when compiling against 2.0.
int verify_area_20(type, address, size);
Usually, when writing code for Linux 2.1, you won’t call access_ok. On the other hand, verify_area is compulsory when compiling for Linux 2.0. This function tries to bridge the gap: it expands to nothing when compiling for Linux 2.1 and is the original verify_area when compiling against 2.0. The function can’t just be called verify_area, because 2.1 still has a macro with the same name as the 2.0 function. The verify_area macro as defined in 2.1 implements the old semantics in terms of access_ok and exists to ease transition of source code from 2.0 to 2.1. (You could, in theory, leave any verify_area in your modules and just rename your functions; the downside of this simple porting technique is that the new version wouldn’t compile with 2.0.)
int GET_USER(var, add);
,
int __GET_USER(var, add);
,
GET_USER_RET(var, add, ret);
When compiling with 2.1, these macros expand to the real get_user functions, the ones explained above. When they are compiled with 2.0, the 2.0 implementation of get_user is used to implement the same functionality as 2.1.
int copy_from_user(to, from, size);
,
int __copy_from_user(to, from, size);
,
copy_from_user_ret(to, from, size);
When compiled with 2.0, these expand to memcpy_fromfs; with 2.1, the native functions are used instead. The _ret flavor won’t ever return with 2.0, because the copying functions can’t fail.
This way of implementing compatibility is my personal preference, but it’s not the only way to do it. In my sample code, verify_area_20 must be called before any user-space access (excluding the buffer for read and write, which is already checked in advance). An alternative would be to be more faithful to 2.1 semantics and automatically generate a verify_area at each get_user or copy_from_user when 2.0 is used. This choice would be cleaner at the source level, but rather inefficient when compiled with version 2.0, both in code size and execution time.
Sample code that compiles with both 2.0 and 2.1 is, for example, the
scull module, as found in the directory v2.1/scull
. I
don’t feel the code is interesting enough to show it here.
[43] An lvalue is an
expression that can be the left operand of an assignment. For
example, count
, v[34+check()]
, and
*((ptr+offset)->field)
are lvalues;
i++
, 32
, and cli()
are
not.
18.116.51.117