| /* Copyright (c) 2009, 2010 The Regents of the University of California |
| * Barret Rhoden <brho@cs.berkeley.edu> |
| * Andrew Waterman <waterman@cs.berkeley.edu> |
| * See LICENSE for details. |
| * |
| * Functions for working with userspace's address space. */ |
| |
| #pragma once |
| |
| #include <ros/common.h> |
| #include <process.h> |
| |
| /* Is this a valid user pointer for read/write? It doesn't care if the address |
| * is paged out or even an unmapped region: simply if it is in part of the |
| * address space that could be RW user. Will also check for len bytes. */ |
| static inline bool is_user_rwaddr(const void *addr, size_t len); |
| /* Same deal, but read-only */ |
| static inline bool is_user_raddr(const void *addr, size_t len); |
| |
| #include <arch/uaccess.h> |
| |
| int strcpy_from_user(struct proc *p, char *dst, const char *src); |
| int strcpy_to_user(struct proc *p, char *dst, const char *src); |
| |
| /** |
| * @brief Copies data from a user buffer to a kernel buffer. |
| * |
| * @param p the process associated with the user program |
| * from which the buffer is being copied |
| * @param dest the destination address of the kernel buffer |
| * @param va the address of the userspace buffer from which we are copying |
| * @param len the length of the userspace buffer |
| * |
| * @return ESUCCESS on success |
| * @return -EFAULT the page assocaited with 'va' is not present, the user |
| * lacks the proper permissions, or there was an invalid 'va' |
| */ |
| int memcpy_from_user(struct proc *p, void *dest, const void *va, size_t len); |
| |
| /** |
| * @brief Copies data to a user buffer from a kernel buffer. |
| * |
| * @param p the process associated with the user program |
| * to which the buffer is being copied |
| * @param dest the destination address of the user buffer |
| * @param src the address of the kernel buffer from which we are copying |
| * @param len the length of the user buffer |
| * |
| * @return ESUCCESS on success |
| * @return -EFAULT the page assocaited with 'va' is not present, the user |
| * lacks the proper permissions, or there was an invalid 'va' |
| */ |
| int memcpy_to_user(struct proc *p, void *dest, const void *src, size_t len); |
| |
| /* Same as above, but sets errno */ |
| int memcpy_from_user_errno(struct proc *p, void *dst, const void *src, int len); |
| int memcpy_to_user_errno(struct proc *p, void *dst, const void *src, int len); |
| int memcpy_to_safe(void *dst, const void *src, size_t amt); |
| int memcpy_from_safe(void *dst, const void *src, size_t amt); |
| |
| /* Creates a buffer (kmalloc) and safely copies into it from va. Can return an |
| * error code. Check its response with IS_ERR(). Must be paired with |
| * user_memdup_free() if this succeeded. */ |
| void *user_memdup(struct proc *p, const void *va, int len); |
| /* Same as above, but sets errno */ |
| void *user_memdup_errno(struct proc *p, const void *va, int len); |
| void user_memdup_free(struct proc *p, void *va); |
| /* Same as memdup, but just does strings. still needs memdup_freed */ |
| char *user_strdup(struct proc *p, const char *u_string, size_t strlen); |
| char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen); |
| char *copy_in_path(struct proc *p, const char *path, size_t path_l); |
| void free_path(struct proc *p, char *t_path); |
| void *kmalloc_errno(int len); |
| bool uva_is_kva(struct proc *p, void *uva, void *kva); |
| uintptr_t uva2kva(struct proc *p, void *uva, size_t len, int prot); |
| /* In arch/pmap{64}.c */ |
| uintptr_t gva2gpa(struct proc *p, uintptr_t cr3, uintptr_t gva); |
| |
| /* Helper for is_user_r{w,}addr. |
| * |
| * These checks are for addresses that the kernel accesses on behalf of the |
| * user, which are mapped into the user's address space. One interpretation is |
| * whether or not the user is allowed to refer to this memory, hence the |
| * MMAP_LOWEST_VA check. But note that the user is allowed to attempt virtual |
| * memory accesses outside of this range. VMM code may interpose on low memory |
| * PFs to emulate certain instructions. However, the kernel should never be |
| * given such a pointer. |
| * |
| * Without the MMAP_LOWEST_VA check, the kernel would still PF on a bad user |
| * pointer (say the user gave us 0x10; we have nothing mapped at addr 0). |
| * However, it would be more difficult to detect if the PF was the kernel acting |
| * on behalf of the user or if the kernel itself had a null pointer deref. By |
| * checking early, the kernel will catch low addresses and error out before page |
| * faulting. */ |
| static inline bool __is_user_addr(const void *addr, size_t len, uintptr_t lim) |
| { |
| if (unlikely((uintptr_t) addr < MMAP_LOWEST_VA)) |
| return FALSE; |
| if (unlikely((uintptr_t) addr >= lim)) |
| return FALSE; |
| if (unlikely(lim - (uintptr_t) addr < len)) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| static inline size_t __valid_user_bytes_from(const void *addr, uintptr_t lim) |
| { |
| if (unlikely((uintptr_t) addr < MMAP_LOWEST_VA)) |
| return 0; |
| if (unlikely((uintptr_t) addr >= lim)) |
| return 0; |
| |
| return (size_t) (lim - (uintptr_t) addr); |
| } |
| |
| /* UWLIM is defined as virtual address below which a process can write */ |
| static inline bool is_user_rwaddr(const void *addr, size_t len) |
| { |
| return __is_user_addr(addr, len, UWLIM); |
| } |
| |
| /* ULIM is defined as virtual address below which a process can read */ |
| static inline bool is_user_raddr(const void *addr, size_t len) |
| { |
| return __is_user_addr(addr, len, ULIM); |
| } |
| |
| static inline size_t valid_user_rwbytes_from(const void *addr) |
| { |
| return __valid_user_bytes_from(addr, UWLIM); |
| } |
| |
| static inline size_t valid_user_rbytes_from(const void *addr) |
| { |
| return __valid_user_bytes_from(addr, ULIM); |
| } |