80

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!

2
  • 3
    See do_execve() source for good example. See how argv is used in count(). If you'd simply dereference (*argv[0]) or something, sparse(1) will warn about it. address_space says not all pointers are equal, requiring different (dereference) rules and should not be mixed.
    – adobriyan
    Dec 24, 2010 at 17:12
  • @adobriyan in what header or source file can I find this function? I do not want to grep while filesystem in order to find it. A path will suffice
    – Herdsman
    May 9, 2020 at 21:04

3 Answers 3

53

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
  • So __attribute__() can use any arbitrary text as an "attribute"? It's not limited to a fixed set which are meaningful to GCC itself?
    – Alex D
    Mar 23, 2015 at 20:10
  • 1
    @AlexD From the GCC Attribute Syntax Manual: An attribute specifier is of the form __attribute__ ((attribute-list)). An attribute list is a possibly empty comma-separated sequence of attributes, where each attribute is one of the following: 1. Empty. Empty attributes are ignored. **2. An attribute name (which may be an identifier such as unused, or a reserved word such as const).** (...). It seems like it could be any identifier you want (using identifier naming conventions). Dec 30, 2015 at 18:45
42

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.

1
  • yeah, that let the copy_to_user make sense
    – hukeping
    Jul 9, 2014 at 4:12
15

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.