summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/include/sys/system.h1
-rw-r--r--sys/kern/kern_subr.c39
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;
+}