diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/include/sys/system.h | 1 | ||||
-rw-r--r-- | sys/kern/kern_subr.c | 39 |
2 files changed, 40 insertions, 0 deletions
diff --git a/sys/include/sys/system.h b/sys/include/sys/system.h index 77a6337..c2e47c2 100644 --- a/sys/include/sys/system.h +++ b/sys/include/sys/system.h @@ -35,6 +35,7 @@ #if defined(_KERNEL) int copyin(uintptr_t uaddr, void *kaddr, size_t len); int copyout(const void *kaddr, uintptr_t uaddr, size_t len); +int copyinstr(uintptr_t uaddr, char *kaddr, size_t len); #endif #endif /* !_SYS_SYSTEM_H_ */ diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c index dd1a618..d9b1b3a 100644 --- a/sys/kern/kern_subr.c +++ b/sys/kern/kern_subr.c @@ -93,3 +93,42 @@ copyout(const void *kaddr, uintptr_t uaddr, size_t len) memcpy((void *)uaddr, kaddr, len); return 0; } + +/* + * Copy in a string from userspace + * + * Unlike the typical copyin(), this routine will + * copy until we've hit NUL ('\0') + * + * @uaddr: Userspace address. + * @kaddr: Kernelspace address. + * @len: Length of string. + * + * XXX: Please note that if `len' is less than the actual + * string length, the returned value will not be + * NUL terminated. + */ +int +copyinstr(uintptr_t uaddr, char *kaddr, size_t len) +{ + char *dest = (char *)kaddr; + char *src = (char *)uaddr; + + if (!check_uaddr(uaddr)) { + return -EFAULT; + } + + for (size_t i = 0; i < len; ++i) { + if (!check_uaddr(uaddr + i)) { + return -EFAULT; + } + + dest[i] = src[i]; + + if (src[i] == '\0') { + break; + } + } + + return 0; +} |