# Accessing userspace memory?



## zirias@ (Nov 5, 2018)

When porting a driver from Linux to FreeBSD, I came across this code:

```
/* 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


----------



## aragats (Nov 5, 2018)

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.


----------



## zirias@ (Nov 5, 2018)

So, code using this is just begging for desaster anyways?


----------



## aragats (Nov 5, 2018)

Zirias said:


> begging for disaster


Indeed!

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.


----------



## yuripv (Nov 5, 2018)

Yes, you want to use copyin()/copyout(), otherwise SMAP comes after you.


----------



## zirias@ (Nov 6, 2018)

aragats said:


> 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?



yuripv said:


> 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?


----------



## yuripv (Nov 6, 2018)

https://en.wikipedia.org/wiki/Supervisor_Mode_Access_Prevention

and it's now implemented in 12, so if even it worked previously, it won't anymore; sysutils/acpi_call being one of the examples.


----------



## zirias@ (Nov 6, 2018)

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?


----------



## Barney (Oct 6, 2019)

Zirias said:


> 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?


----------



## zirias@ (Oct 11, 2019)

Barney said:


> Did you ever figure this out?


No, I just used the copy functions for the whole 8k buffer and it works fine.


Barney said:


> is there a way to lock down the user buffer for the copy?


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?


----------



## Barney (Oct 11, 2019)

Zirias said:


> 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.


----------

