aboutsummaryrefslogtreecommitdiff
path: root/kernel/api/access.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/api/access.c')
-rw-r--r--kernel/api/access.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/kernel/api/access.c b/kernel/api/access.c
new file mode 100644
index 0000000..d56e45d
--- /dev/null
+++ b/kernel/api/access.c
@@ -0,0 +1,136 @@
+#include "errno.h"
+#include "globals.h"
+#include <mm/mm.h>
+#include <util/string.h>
+
+#include "util/debug.h"
+
+#include "mm/kmalloc.h"
+#include "mm/mman.h"
+
+#include "api/access.h"
+#include "api/syscall.h"
+
+static inline long userland_address(const void *addr)
+{
+ return addr >= (void *)USER_MEM_LOW && addr < (void *)USER_MEM_HIGH;
+}
+
+/*
+ * Check for permissions on [uaddr, uaddr + nbytes), then
+ * copy nbytes from userland address uaddr to kernel address kaddr.
+ * Do not access the userland virtual addresses directly; instead,
+ * use vmmap_read.
+ */
+long copy_from_user(void *kaddr, const void *uaddr, size_t nbytes)
+{
+ if (!range_perm(curproc, uaddr, nbytes, PROT_READ))
+ {
+ return -EFAULT;
+ }
+ KASSERT(userland_address(uaddr) && !userland_address(kaddr));
+ return vmmap_read(curproc->p_vmmap, uaddr, kaddr, nbytes);
+}
+
+/*
+ * Check for permissions on [uaddr, uaddr + nbytes), then
+ * copy nbytes from kernel address kaddr to userland address uaddr.
+ * Do not access the userland virtual addresses directly; instead,
+ * use vmmap_write.
+ */
+long copy_to_user(void *uaddr, const void *kaddr, size_t nbytes)
+{
+ if (!range_perm(curproc, uaddr, nbytes, PROT_WRITE))
+ {
+ return -EFAULT;
+ }
+ KASSERT(userland_address(uaddr) && !userland_address(kaddr));
+ return vmmap_write(curproc->p_vmmap, uaddr, kaddr, nbytes);
+}
+
+/*
+ * Duplicate the string identified by ustr into kernel memory.
+ * The kernel memory string kstr should be allocated using kmalloc.
+ */
+long user_strdup(argstr_t *ustr, char **kstrp)
+{
+ KASSERT(!userland_address(ustr));
+ KASSERT(userland_address(ustr->as_str));
+
+ *kstrp = kmalloc(ustr->as_len + 1);
+ if (!*kstrp)
+ return -ENOMEM;
+ long ret = copy_from_user(*kstrp, ustr->as_str, ustr->as_len + 1);
+ if (ret)
+ {
+ kfree(*kstrp);
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * Duplicate the string of vectors identified by uvec into kernel memory.
+ * The vector itself (char**) and each string (char*) should be allocated
+ * using kmalloc.
+ */
+long user_vecdup(argvec_t *uvec, char ***kvecp)
+{
+ KASSERT(!userland_address(uvec));
+ KASSERT(userland_address(uvec->av_vec));
+
+ char **kvec = kmalloc((uvec->av_len + 1) * sizeof(char *));
+ *kvecp = kvec;
+
+ if (!kvec)
+ {
+ return -ENOMEM;
+ }
+ memset(kvec, 0, (uvec->av_len + 1) * sizeof(char *));
+
+ long ret = 0;
+ for (size_t i = 0; i < uvec->av_len && !ret; i++)
+ {
+ argstr_t argstr;
+ copy_from_user(&argstr, uvec->av_vec + i, sizeof(argstr_t));
+ ret = user_strdup(&argstr, kvec + i);
+ }
+
+ if (ret)
+ {
+ for (size_t i = 0; i < uvec->av_len; i++)
+ if (kvec[i])
+ kfree(kvec[i]);
+ kfree(kvec);
+ *kvecp = NULL;
+ }
+
+ return ret;
+}
+
+/*
+ * Return 1 if process p has permissions perm for virtual address vaddr;
+ * otherwise return 0.
+ *
+ * Check against the vmarea's protections on the mapping.
+ */
+long addr_perm(proc_t *p, const void *vaddr, int perm)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return 0;
+}
+
+/*
+ * Return 1 if process p has permissions perm for virtual address range [vaddr,
+ * vaddr + len); otherwise return 0.
+ *
+ * Hints:
+ * You can use addr_perm in your implementation.
+ * Make sure to consider the case when the range of addresses that is being
+ * checked is less than a page.
+ */
+long range_perm(proc_t *p, const void *vaddr, size_t len, int perm)
+{
+ NOT_YET_IMPLEMENTED("VM: ***none***");
+ return 0;
+}