What are the implications of the linux __user macr

2019-01-08 10:37发布

问题:

I was hoping someone could explain the nuances of the __user macro used in the linux kernel source.

First of all, the macro:

# define __user         __attribute__((noderef, address_space(1)))

Now, after some googling I read that this macro allows one to designate a pointer as belonging to the user address space, and that it should not be dereferenced.

I may be missing some obvious facts, but could someone please explain the implications of such a macro? For instance, what is a good example of where this macro would be of use? Again, forgive me if I am missing something obvious.

To put this in some context, I came accross the macro while examining some USB code (linux/usbdevice_fs.h). I am only looking for a general understanding of this macros( or others like it) use within the kernel.

Thanks for looking!

回答1:

It allows tools like sparse to tell kernel developers that they're possibly using an untrusted pointer (or a pointer that may be invalid in the current virtual address mapping) improperly.



回答2:

I think __user marks user space pointers and tells the developer/system not to trust it. If user gives you "invalid" pointer, then kernel tries to reference it (note that kernel can reference everywhere) and it can corrupt it's own space.

For example in "read"(in you usbdevice_fs.h) should provide you a (__user) buffer to write the result to. So you have to use copy_to_user, but not memcopy, strcpy or anything like this.

Note: This is not formal definition/description, but the only part I'm aware of.



回答3:

The __user macro is defined with some other macros like __force/__kernel etc in the compiler.h header file. They are actually not of any use to traditional compilers, including GCC/ICC etc. But it's useful for kernel static analysis tools like sparse (more information here: Sparse - Linux Kernel Newbies). When you mention the macros like __user/__kernel/__force etc, it keeps special meaning for sparse. In the Linux kernel mailing list, Linus Torvalds explains the use of it like this:

This is important to remember: for gcc, the sparse annotations are meaningless. They can still be useful just to tell the programmer that "hey, that pointer you got wasn't a normal pointer" in a fairly readable manner, but in the end, unless you use sparse, they don't actually do anything.

HOWEVER. When you do use parse, it is another matter entirely. For "sparse", that "__iomem" has lots of meaning:

# define __iomem __attribute__((noderef, address_space(2)))

ie "iomem" means two separate things: it means that sparse should complain

if the pointer is ever dereferenced (it's a "noderef" pointer) directly, and it's in "address space 2" as opposed to the normal address space (0).

Now, that means that sparse will complain if such a pointer is ever passed into a function that wants a regular pointer (because it is not a normal pointer, and you obviously shouldn't do things like "strcmp()" etc on it), and sparse will also complain if you try to cast it to another pointer in another address space.