Accessing userspace memory?

zirias@

Developer
When porting a driver from Linux to FreeBSD, I came across this code:
C:
        /* verify if it's ok to write into the buffer */
        if (access_ok(VERIFY_WRITE, kernel_val.buffer, 0x2000) == 0)
            return -EFAULT;
where kernel_val.buffer is a pointer to userspace. The code then continues writing directly there. As I couldn't find an equivalent to access_ok() in FreeBSD, I just removed the whole check for testing and it worked.

Now, AFAIK, this won't work on all architectures? Is it ever safe to directly access userspace memory? Is there some means to check whether such an access is ok, or should you always use a buffer in kernel space and the copy(9) functions?

edit: just to be sure, I changed the driver code to consistently use copyin() / copyout() on all data, this works fine, but I'm still curious ;)
 
It doesn't privide a real answer to your question, but this may shed some light.
access_ok() is rather fuzzy:
«access_ok() ... returns true (nonzero) if the memory block may be valid, false (zero) if it is definitely invalid»
Also, in some architectures it always return 1.
 
There exist two malloc() functions: malloc(3) and malloc(9) for the user space and the kernel space correspondingly.
So, if one creates a pointer using malloc(3) why it can be invalid? The only thing is I'm not sure whether both mallocs()'s can be used in a driver code at the same time.

Uhm, I don't (specifically) care about dynamically allocated memory, could be statically allocated buffers as well... it's more about virtual memory handling. It seems on x86_64, the mapped userspace pages keep mapped at the same virtual addresses when entering the kernel, otherwise the original (Linux) code wouldn't have worked?

Yes, you want to use copyin()/copyout(), otherwise SMAP comes after you.
Thanks, that's what I did. Now, what is SMAP? Could you explain a bit more or point me to something to read?
 
That's interesting, I will inform upstream because it's then probably broken on recent Linux versions as well.

In case of this driver, it's an 8kb buffer that needs to be copied, I guess this isn't much of a problem performance-wise. So *if* you wanted to avoid copying, you'd go for mmap(), correct?
 
That's interesting, I will inform upstream because it's then probably broken on recent Linux versions as well.

In case of this driver, it's an 8kb buffer that needs to be copied, I guess this isn't much of a problem performance-wise. So *if* you wanted to avoid copying, you'd go for mmap(), correct?

Did you ever figure this out? is there a way to lock down the user buffer for the copy?
 
No, I just used the copy functions for the whole 8k buffer and it works fine.

Uhm, not sure what you mean ... like making sure the userspace process doesn't modify it? How would it, as long as I'm running in a syscall context?
Are you running 12.x? I found that copyout generates a page fault when copying to a large user buffer. Not sure what it is; the code is too cryptic to figure out easily and there's more than one way to skin a cat so I did it another way. I have buffers that can be 25k or more and on the larger ones it was page faulting. Using copyout_nofault() it didn't do the copy.
 
Back
Top