Index Home About Blog
From: torvalds@transmeta.com (Linus Torvalds)
Subject: Re: verify_area(...) possible problem.
Date: 	13 Apr 1999 17:00:10 GMT
Newsgroups: fa.linux.kernel

In article <4B857AEEE602D211A45900805FA7753C0407D1@TOTOMB02>,
Gilbert, Douglas <douglas.gilbert@rbcds.com> wrote:
>
>Linus Torvalds wrote:
>
>> ... you can do
>>
>>        error = access_ok(VERIFY_READ, p, 3*sizeof(*p));
>>        if (!error) {
>>                __put_user(a, p);
>>                __put_user(b, p+1);
>>                __put_user(c, p+2);
>>        }
>>
>> where the __xxx versions are faster but "unsafe" unless you have
>> verified the area by hand first.
>
>Can this be extended to:
>
>	error = access_ok(VERIFY_READ, p, 3*sizeof(*p));
>	if (! error) {
>		interruptible_sleep_on(&some_wait_queue);
>		...
>		__put_user(a, p);
>		__put_user(b, p+1);
>		__put_user(c, p+2);
>	}
>??

Yes.

"access_ok()" really only checks that the pointer is a _potentially_
valid user space pointer.  What that means is architecture-dependent, as
user-space pointers can have different representations on different
architectures, but on the x86, for example, it only checks that the
pointer is within the "TASK_SIZE" thing (ie in the region 0-0xbfffffff
on a default linux kernel). 

On other architectures "access_ok()" can actually be a no-op, because
the user address space can be completely separate from the kernel
address space and is accessed with special instructions rather than with
a normal load/store like on the x86. 

As such, "access_ok()" is not timing-related, and it doesn't matter
whether you do it immediately before the access or a year before. 
That's a requirement to actually be thread-safe, so this is very much a
fundamental design decision. 

The test whether a page is actually _mapped_ within the user address
space is then done when doing the actual access.  On any sane
architecture this is done by the hardware mmu, and the only thing the
get_user()/put_user() functions need to do is to set up everything so
that the kernel page fault handler can recover gracefully from any
faults. 

		Linus


Date: 	Mon, 12 Apr 1999 21:17:11 -0700 (PDT)
From: Linus Torvalds <torvalds@transmeta.com>
Subject: Re: verify_area(...) possible problem.
Newsgroups: fa.linux.kernel

On Mon, 12 Apr 1999, Richard B. Johnson wrote:
> 
> > 
> > The short and sweet of it is: you absolutely positively _have_ to use
> > get_user()/put_user()/copy_from_user()/copy_to_user() for user level
> > accesses. There are no if's and but's about it.
> 
> Yes, yes, I know that. However, this has another problem in the
> intended application. I would like to memmap a physical page from
> user-space, lock it down in memory, and have an ISR write directly
> to that.

You cannot.

This keeps coming up, and even sane people like Alan Cox want to do it,
even though it is fairly obvious that it should not be done that way.

>	 I didn't want a kernel-space buffer that I have to copy
> (for performance reasons). Therefore, I decided to use verify_area
> as a check for existance.
> 
> So, I guess I will have to do a dummy copy_to_user as an initial test?

No. That doesn't help in the least.

By the time your interrupt handler is called, the process is long long
gone and even if it was the current process it might have changed its
mapping.

Basically you should never EVER even consider writing to user space from
interrupts. EVER!

Basically, you should always use a kernel-space buffer. Just accept that
as a fundamental notion, and your life suddenly turns a lot easier.

Now, I know about zero-copy. I'm not a big believer in it, but I certainly
know about it. And having a kernel buffer does not imply that you can't do
zero-copy. It just means that you can' tdo the initial copy to user space.

Sounds contradictory? Think "mmap()". It works, it's there, and magically
all the problems go away. Don't make the mountain go to Mohammed. Instead,
think of your problem the other way around: instead of the kernel writing
to user space, think of it as user space asking to see a window of a
kernel buffer. You make a device driver that has a mmap() function, and
suddenly the device driver can write to kernel memory, and whatever it
writes magically shows up in user space too. 

		Linus



Index Home About Blog