From 50b4b45d0075282355f1a9698d81147aae020e35 Mon Sep 17 00:00:00 2001 From: Matheus Date: Sun, 9 Jun 2024 19:31:26 -0300 Subject: [PATCH] kernel: usercopy functions --- kernel-src/arch/x86-64/mmu.c | 24 +++-- kernel-src/fs/sockfs.c | 68 ++++++++------ kernel-src/include/kernel/scheduler.h | 1 + kernel-src/include/kernel/sock.h | 17 +++- kernel-src/include/kernel/syscalls.h | 1 + kernel-src/include/kernel/usercopy.h | 29 ++++++ kernel-src/include/x86-64/arch/context.h | 2 +- kernel-src/include/x86-64/arch/mmu.h | 2 + kernel-src/io/block/block.c | 10 +- kernel-src/io/fb.c | 7 +- kernel-src/io/pty.c | 7 +- kernel-src/io/tty.c | 56 +++++++----- kernel-src/mm/usercopy.c | 111 +++++++++++++++++++++++ kernel-src/sys/syscalls/accept.c | 1 + kernel-src/sys/syscalls/bind.c | 4 +- kernel-src/sys/syscalls/chdir.c | 20 ++-- kernel-src/sys/syscalls/chmod.c | 15 ++- kernel-src/sys/syscalls/chroot.c | 20 ++-- kernel-src/sys/syscalls/clockget.c | 24 +++-- kernel-src/sys/syscalls/connect.c | 4 +- kernel-src/sys/syscalls/execve.c | 87 ++++++++++++++++-- kernel-src/sys/syscalls/faccessat.c | 16 +++- kernel-src/sys/syscalls/fchownat.c | 12 ++- kernel-src/sys/syscalls/futex.c | 7 +- kernel-src/sys/syscalls/getdent.c | 13 +-- kernel-src/sys/syscalls/getpeername.c | 8 +- kernel-src/sys/syscalls/getsockname.c | 5 +- kernel-src/sys/syscalls/gettid.c | 1 + kernel-src/sys/syscalls/hostname.c | 14 +-- kernel-src/sys/syscalls/ioctl.c | 5 + kernel-src/sys/syscalls/linkat.c | 23 +++-- kernel-src/sys/syscalls/mkdirat.c | 16 +++- kernel-src/sys/syscalls/mount.c | 54 ++++++++--- kernel-src/sys/syscalls/open.c | 15 ++- kernel-src/sys/syscalls/poll.c | 15 ++- kernel-src/sys/syscalls/read.c | 8 +- kernel-src/sys/syscalls/readlinkat.c | 20 ++-- kernel-src/sys/syscalls/recvmsg.c | 11 ++- kernel-src/sys/syscalls/renameat.c | 25 +++-- kernel-src/sys/syscalls/sendmsg.c | 8 +- kernel-src/sys/syscalls/setitimer.c | 26 ++++-- kernel-src/sys/syscalls/setsockopt.c | 8 +- kernel-src/sys/syscalls/sigaction.c | 16 +++- kernel-src/sys/syscalls/sigaltstack.c | 12 ++- kernel-src/sys/syscalls/sigprocmask.c | 10 +- kernel-src/sys/syscalls/sigreturn.c | 7 +- kernel-src/sys/syscalls/sleep.c | 16 ++-- kernel-src/sys/syscalls/stat.c | 24 +++-- kernel-src/sys/syscalls/uname.c | 16 ++-- kernel-src/sys/syscalls/unlinkat.c | 19 ++-- kernel-src/sys/syscalls/utime.c | 20 +++- kernel-src/sys/syscalls/waitpid.c | 7 +- kernel-src/sys/syscalls/write.c | 5 +- 53 files changed, 712 insertions(+), 260 deletions(-) create mode 100644 kernel-src/include/kernel/usercopy.h create mode 100644 kernel-src/mm/usercopy.c diff --git a/kernel-src/arch/x86-64/mmu.c b/kernel-src/arch/x86-64/mmu.c index 09c075ec..eea7248c 100644 --- a/kernel-src/arch/x86-64/mmu.c +++ b/kernel-src/arch/x86-64/mmu.c @@ -263,6 +263,7 @@ static volatile struct limine_kernel_address_request kaddrreq = { #define ERROR_FETCH 16 static void pfisr(isr_t *self, context_t *ctx) { + thread_t *thread = _cpu()->thread; interrupt_set(true); int vmmerror = 0; if (ctx->error & ERROR_PRESENT) @@ -275,18 +276,29 @@ static void pfisr(isr_t *self, context_t *ctx) { vmmerror |= VMM_ACTION_EXEC; if (vmm_pagefault((void *)ctx->cr2, ctx->cs != 8, vmmerror) == false) { - if (ARCH_CONTEXT_ISUSER(ctx)) - signal_signalthread(_cpu()->thread, SIGSEGV, true); - else + if (thread->usercopyctx) { + memcpy(ctx, thread->usercopyctx, sizeof(context_t)); + thread->usercopyctx = NULL; + CTX_RET(ctx) = EFAULT; + } else if (ARCH_CONTEXT_ISUSER(ctx)) { + signal_signalthread(thread, SIGSEGV, true); + } else { _panic("Page Fault", ctx); + } } } static void gpfisr(isr_t *self, context_t *ctx) { - if (ARCH_CONTEXT_ISUSER(ctx)) - signal_signalthread(_cpu()->thread, SIGSEGV, true); - else + thread_t *thread = _cpu()->thread; + if (thread->usercopyctx) { + memcpy(ctx, thread->usercopyctx, sizeof(context_t)); + thread->usercopyctx = NULL; + CTX_RET(ctx) = EFAULT; + } else if (ARCH_CONTEXT_ISUSER(ctx)) { + signal_signalthread(thread, SIGSEGV, true); + } else { _panic("General Protection Fault", ctx); + } } void arch_mmu_init() { diff --git a/kernel-src/fs/sockfs.c b/kernel-src/fs/sockfs.c index 6663f223..d5b21c9f 100644 --- a/kernel-src/fs/sockfs.c +++ b/kernel-src/fs/sockfs.c @@ -70,13 +70,16 @@ int sockfs_setattr(vnode_t *node, vattr_t *attr, int which, cred_t *cred) { // arg can be in userspace int sockfs_ioctl(vnode_t *node, unsigned long request, void *arg, int *result) { switch (request) { - case SIOCSIFADDR: - { - ifreq_t *ifreq = arg; - netdev_t *netdev = netdev_getdev(ifreq->name); + case SIOCSIFADDR: { + ifreq_t ifreq; + int e = USERCOPY_POSSIBLY_FROM_USER(&ifreq, arg, sizeof(ifreq_t)); + if (e) + return e; + + netdev_t *netdev = netdev_getdev(ifreq.name); if(netdev) { sockaddr_t sockaddr; - int e = sock_convertaddress(&sockaddr, &ifreq->addr); + e = sock_convertaddress(&sockaddr, &ifreq.addr); if (e) return e; netdev->ip = sockaddr.ipv4addr.addr; @@ -85,50 +88,57 @@ int sockfs_ioctl(vnode_t *node, unsigned long request, void *arg, int *result) { } break; } - case SIOCGIFHWADDR: - { + case SIOCGIFHWADDR: { ifreq_t *ifreq = arg; - netdev_t *netdev = netdev_getdev(ifreq->name); + ifreq_t kifreq; + int e = USERCOPY_POSSIBLY_FROM_USER(&kifreq, arg, sizeof(ifreq_t)); + if (e) + return e; + + netdev_t *netdev = netdev_getdev(kifreq.name); if (netdev) { - memcpy(ifreq->addr.addr, netdev->mac.address, sizeof(mac_t)); - return 0; + return USERCOPY_POSSIBLY_TO_USER(ifreq->addr.addr, netdev->mac.address, sizeof(mac_t)); } else { return ENODEV; } break; } - case SIOCADDRT: - { + case SIOCADDRT: { abirtentry_t abirtentry; - memcpy(&abirtentry, arg, sizeof(abirtentry_t)); - - abisockaddr_t abiaddr; - abisockaddr_t abigateway; - abisockaddr_t abimask; - memcpy(&abiaddr, (void *)&abirtentry.rt_dst, sizeof(abisockaddr_t)); - memcpy(&abigateway, (void *)&abirtentry.rt_gateway, sizeof(abisockaddr_t)); - memcpy(&abimask, (void *)&abirtentry.rt_genmask, sizeof(abisockaddr_t)); + int e = USERCOPY_POSSIBLY_FROM_USER(&abirtentry, arg, sizeof(abirtentry_t)); + if (e) + return e; sockaddr_t addr; sockaddr_t gateway; sockaddr_t mask; - int e = sock_convertaddress(&addr, &abiaddr); + e = sock_convertaddress(&addr, &abirtentry.rt_dst); if (e) return e; - e = sock_convertaddress(&gateway, &abigateway); + e = sock_convertaddress(&gateway, &abirtentry.rt_gateway); if (e) return e; - e = sock_convertaddress(&mask, &abimask); + e = sock_convertaddress(&mask, &abirtentry.rt_genmask); if (e) return e; - char *dev = alloc(strlen(abirtentry.rt_dev) + 1); + size_t devlen; + e = USERCOPY_POSSIBLY_STRLEN_FROM_USER(abirtentry.rt_dev, &devlen); + if (e) + return e; + + char *dev = alloc(devlen + 1); if (dev == NULL) return ENOMEM; - strcpy(dev, abirtentry.rt_dev); + + e = USERCOPY_POSSIBLY_FROM_USER(dev, abirtentry.rt_dev, devlen); + if (e) { + free(dev); + return e; + } netdev_t *netdev = netdev_getdev(dev); if (netdev == NULL) { @@ -141,15 +151,13 @@ int sockfs_ioctl(vnode_t *node, unsigned long request, void *arg, int *result) { free(dev); return e; } - case FIONREAD: - { + case FIONREAD: { socket_t *socket = SOCKFS_SOCKET_FROM_NODE(node); - int *count = arg; if (socket->ops->datacount == NULL) return ENOTTY; - *count = socket->ops->datacount(socket); - return 0; + int count = socket->ops->datacount(socket); + return USERCOPY_POSSIBLY_TO_USER(arg, &count, sizeof(int)); } default: return ENOTTY; diff --git a/kernel-src/include/kernel/scheduler.h b/kernel-src/include/kernel/scheduler.h index bc563315..05eda5f7 100644 --- a/kernel-src/include/kernel/scheduler.h +++ b/kernel-src/include/kernel/scheduler.h @@ -51,6 +51,7 @@ typedef struct thread_t { int wakeupreason; bool shouldexit; void *kernelarg; + context_t *usercopyctx; struct { spinlock_t lock; stack_t stack; diff --git a/kernel-src/include/kernel/sock.h b/kernel-src/include/kernel/sock.h index ddca5f17..72689300 100644 --- a/kernel-src/include/kernel/sock.h +++ b/kernel-src/include/kernel/sock.h @@ -5,6 +5,7 @@ #include #include #include +#include #define SOCKET_STATE_UNBOUND 0 #define SOCKET_STATE_BOUND 1 @@ -93,11 +94,16 @@ static inline int sock_addrtoabiaddr(int socktype, sockaddr_t *sockaddr, abisock } static inline int sock_copymsghdr(msghdr_t *khdr, msghdr_t *uhdr) { - memcpy(khdr, uhdr, sizeof(msghdr_t)); + if (usercopy_fromuser(khdr, uhdr, sizeof(msghdr_t))) + return EFAULT; + iovec_t *iovectmp = alloc(sizeof(iovec_t) * khdr->iovcount); if (iovectmp == NULL) return ENOMEM; - memcpy(iovectmp, khdr->iov, sizeof(iovec_t) * khdr->iovcount); + + if (usercopy_fromuser(iovectmp, khdr->iov, sizeof(iovec_t) * khdr->iovcount)) + return EFAULT; + khdr->iov = iovectmp; if (khdr->addr) { @@ -106,7 +112,12 @@ static inline int sock_copymsghdr(msghdr_t *khdr, msghdr_t *uhdr) { free(iovectmp); return ENOMEM; } - memcpy(addrtmp, khdr->addr, khdr->addrlen); + + if (usercopy_fromuser(addrtmp, khdr->addr, khdr->addrlen)) { + free(iovectmp); + return EFAULT; + } + khdr->addr = addrtmp; } diff --git a/kernel-src/include/kernel/syscalls.h b/kernel-src/include/kernel/syscalls.h index 5d695e5a..0fafc060 100644 --- a/kernel-src/include/kernel/syscalls.h +++ b/kernel-src/include/kernel/syscalls.h @@ -6,6 +6,7 @@ #include #include #include +#include typedef struct { uint64_t ret; diff --git a/kernel-src/include/kernel/usercopy.h b/kernel-src/include/kernel/usercopy.h new file mode 100644 index 00000000..290bae4c --- /dev/null +++ b/kernel-src/include/kernel/usercopy.h @@ -0,0 +1,29 @@ +#ifndef _USERCOPY_H +#define _USERCOPY_H + +#include +#include +#include + +//IS_USER_ADDRESS(a) is provided by arch/mmu.h +#include + +static inline int _usercopy_memcpy_wrapper(void *dst, void *src, size_t size) { + memcpy(dst, src, size); + return 0; +} +static inline int _usercopy_strlen_wrapper(void *str, size_t *size) { + *size = strlen(str); + return 0; +} + +#define USERCOPY_POSSIBLY_FROM_USER(kernel, user, size) (IS_USER_ADDRESS(user) ? usercopy_fromuser(kernel, user, size) : _usercopy_memcpy_wrapper(kernel, user, size)) +#define USERCOPY_POSSIBLY_TO_USER(user, kernel, size) (IS_USER_ADDRESS(user) ? usercopy_touser(user, kernel, size) : _usercopy_memcpy_wrapper(user, kernel, size)) +#define USERCOPY_POSSIBLY_STRLEN_FROM_USER(user, sizep) (IS_USER_ADDRESS(user) ? usercopy_strlen(user, sizep) : _usercopy_strlen_wrapper(user, sizep)) + +int usercopy_touser(void *user, void *kernel, size_t size); +int usercopy_fromuser(void *kernel, void *user, size_t size); +int usercopy_fromuseratomic32(uint32_t *user32, uint32_t *value); +int usercopy_strlen(const char *, size_t *size); + +#endif diff --git a/kernel-src/include/x86-64/arch/context.h b/kernel-src/include/x86-64/arch/context.h index 4ffdb76a..4f1de9b5 100644 --- a/kernel-src/include/x86-64/arch/context.h +++ b/kernel-src/include/x86-64/arch/context.h @@ -77,7 +77,7 @@ typedef struct { } void arch_context_switch(context_t *context); -void arch_context_saveandcall(void (*fn)(context_t *context, void *argument), void *stack, void *argument); +int arch_context_saveandcall(void (*fn)(context_t *context, void *argument), void *stack, void *argument); #include diff --git a/kernel-src/include/x86-64/arch/mmu.h b/kernel-src/include/x86-64/arch/mmu.h index 6a4de5fb..6e89bdef 100644 --- a/kernel-src/include/x86-64/arch/mmu.h +++ b/kernel-src/include/x86-64/arch/mmu.h @@ -10,6 +10,8 @@ #define USERSPACE_START (void *)0x0000000000001000 #define USERSPACE_END (void *)0x0000800000000000 +#define IS_USER_ADDRESS(a) ((void *)a < USERSPACE_END) + #define PAGE_SIZE 4096 #define ARCH_MMU_FLAGS_READ (uint64_t)1 #define ARCH_MMU_FLAGS_WRITE (uint64_t)2 diff --git a/kernel-src/io/block/block.c b/kernel-src/io/block/block.c index 3965099a..ee46cfeb 100644 --- a/kernel-src/io/block/block.c +++ b/kernel-src/io/block/block.c @@ -6,6 +6,7 @@ #include #include #include +#include #define DISK_READ(desc, buf, lba, size) (desc)->read(desc->private, buf, lba, size) #define DISK_WRITE(desc, buf, lba, size) (desc)->write(desc->private, buf, lba, size) @@ -140,10 +141,11 @@ static int ioctl(int minor, unsigned long request, void *arg, int *result) { switch (request) { case BLOCK_IOCTL_GETDESC: - *(blockdesc_t *)arg = *desc; - ((blockdesc_t *)arg)->write = NULL; - ((blockdesc_t *)arg)->read = NULL; - ((blockdesc_t *)arg)->private = NULL; + blockdesc_t copy = *desc; + copy.write = NULL; + copy.read = NULL; + copy.private = NULL; + ret = USERCOPY_POSSIBLY_TO_USER(arg, ©, sizeof(blockdesc_t)); break; default: ret = ENOTTY; diff --git a/kernel-src/io/fb.c b/kernel-src/io/fb.c index c50aea30..32bc7ec8 100644 --- a/kernel-src/io/fb.c +++ b/kernel-src/io/fb.c @@ -6,6 +6,7 @@ #include #include #include +#include typedef struct bitfield_t { uint32_t offset; @@ -177,11 +178,9 @@ static int ioctl(int minor, unsigned long request, void *arg, int *result){ case FBIOPUT_VSCREENINFO: break; case FBIOGET_FSCREENINFO: - *(fixinfo_t *)arg = fixinfos[minor]; - break; + return USERCOPY_POSSIBLY_TO_USER(arg, &fixinfos[minor], sizeof(fixinfo_t)); case FBIOGET_VSCREENINFO: - *(varinfo_t *)arg = varinfos[minor]; - break; + return USERCOPY_POSSIBLY_TO_USER(arg, &varinfos[minor], sizeof(varinfo_t)); default: return ENOTTY; } diff --git a/kernel-src/io/pty.c b/kernel-src/io/pty.c index d67b5452..78a4a2b2 100644 --- a/kernel-src/io/pty.c +++ b/kernel-src/io/pty.c @@ -3,6 +3,7 @@ #include #include #include +#include #define PTY_BUFFER 4096 #define PTY_MAX 1024 @@ -198,12 +199,10 @@ static int ioctl(int minor, unsigned long request, void *_arg, int *result) { switch (request) { case TIOCGPTN: { - int *arg = _arg; - *arg = pty->minor; - break; + return USERCOPY_POSSIBLY_TO_USER(_arg, &pty->minor, sizeof(int)); } default: - return tty_ioctl(pty->tty, request, _arg, result); + return tty_ioctl(pty->tty, request, _arg, result); } return 0; diff --git a/kernel-src/io/tty.c b/kernel-src/io/tty.c index 877cb598..f041cdc2 100644 --- a/kernel-src/io/tty.c +++ b/kernel-src/io/tty.c @@ -3,6 +3,7 @@ #include #include #include +#include #define TTY_MAX_COUNT 4096 #define CONTROLLING_TTY_MINOR TTY_MAX_COUNT @@ -300,14 +301,13 @@ static int poll(int minor, polldata_t *data, int events) { int tty_ioctl(tty_t *tty, unsigned long req, void *arg, int *result) { switch (req) { - case TIOCGWINSZ: { - winsize_t *w = arg; - *w = tty->winsize; - break; - } + case TIOCGWINSZ: + return USERCOPY_POSSIBLY_TO_USER(arg, &tty->winsize, sizeof(winsize_t)); case TIOCSWINSZ: { - winsize_t *w = arg; - tty->winsize = *w; + int e = USERCOPY_POSSIBLY_FROM_USER(&tty->winsize, arg, sizeof(winsize_t)); + if (e) + return e; + proc_t *foreground = getforeground(tty); if (foreground) { jobctl_signal(foreground, SIGWINCH); @@ -315,18 +315,22 @@ int tty_ioctl(tty_t *tty, unsigned long req, void *arg, int *result) { } break; } - case TCGETS: { - *(termios_t *)arg = tty->termios; - break; - } - case TCSETS: { - tty->termios = *(termios_t *)arg; - break; - } + case TCGETS: + return USERCOPY_POSSIBLY_TO_USER(arg, &tty->termios, sizeof(termios_t)); + case TCSETS: + return USERCOPY_POSSIBLY_FROM_USER(&tty->termios, arg, sizeof(termios_t)); case TIOCSCTTY: { - int *steal = arg; - if (steal && *steal == 1) - printf("tty: stealing not supported\n"); + if (arg) { + int steal; + int e = USERCOPY_POSSIBLY_FROM_USER(&steal, arg, sizeof(int)); + if (e) + return e; + + if (steal == 1) { + printf("tty: stealing not supported\n"); + return EINVAL; + } + } // set as controlling tty jobctl_setctty(_cpu()->thread->proc, tty); break; @@ -336,14 +340,17 @@ int tty_ioctl(tty_t *tty, unsigned long req, void *arg, int *result) { if (foreground == NULL) return ENOTTY; - int *pgrp = arg; - *pgrp = foreground->pid; + int pgrp = foreground->pid; PROC_RELEASE(foreground); - break; + + return USERCOPY_POSSIBLY_TO_USER(arg, &pgrp, sizeof(int)); } case TIOCSPGRP: { - int *pgrpptr = arg; - int pgrp = *pgrpptr; + int pgrp; + int e = USERCOPY_POSSIBLY_FROM_USER(&pgrp, arg, sizeof(int)); + if (e) + return e; + proc_t *proc = sched_getprocfrompid(pgrp); if (proc == NULL) return ESRCH; @@ -354,8 +361,7 @@ int tty_ioctl(tty_t *tty, unsigned long req, void *arg, int *result) { } case TTY_IOCTL_NAME: { size_t len = min(strlen(tty->name) + 1, TTY_NAME_MAX); - memcpy(arg, tty->name, len); - break; + return USERCOPY_POSSIBLY_TO_USER(arg, tty->name, len); } default: return ENOTTY; diff --git a/kernel-src/mm/usercopy.c b/kernel-src/mm/usercopy.c new file mode 100644 index 00000000..ba74123e --- /dev/null +++ b/kernel-src/mm/usercopy.c @@ -0,0 +1,111 @@ +#include +#include +#include + +typedef struct { + void *dst; + void *src; + size_t size; +} memcpydesc_t; + +typedef struct { + const char *str; + size_t *size; +} strlendesc_t; + +typedef struct { + uint32_t *value; + uint32_t *address; +} atomic32desc_t; + +static void memcpyinternal(context_t *ctx, void *arg) { + memcpydesc_t *desc = arg; + + // this sets up the thread so that in the next invalid page fault, it will jump to + // this context with CTX_RET set to EFAULT + _cpu()->thread->usercopyctx = ctx; + + memcpy(desc->dst, desc->src, desc->size); + + // no errors! + CTX_RET(ctx) = 0; + _cpu()->thread->usercopyctx = NULL; +} + +static void strleninternal(context_t *ctx, void *arg) { + strlendesc_t *desc = arg; + + // this sets up the thread so that in the next invalid page fault, it will jump to + // this context with CTX_RET set to EFAULT + _cpu()->thread->usercopyctx = ctx; + + *desc->size = strlen(desc->str); + + // no errors! + CTX_RET(ctx) = 0; + _cpu()->thread->usercopyctx = NULL; +} + +static void atomic32internal(context_t *ctx, void *arg) { + atomic32desc_t *desc = arg; + + // this sets up the thread so that in the next invalid page fault, it will jump to + // this context with CTX_RET set to EFAULT + _cpu()->thread->usercopyctx = ctx; + + __atomic_load(desc->address, desc->value, __ATOMIC_SEQ_CST); + + // no errors! + CTX_RET(ctx) = 0; + _cpu()->thread->usercopyctx = NULL; +} + +int usercopy_touser(void *user, void *kernel, size_t size) { + memcpydesc_t desc = { + .dst = user, + .src = kernel, + .size = size + }; + + if (IS_USER_ADDRESS(user) == false) + return EFAULT; + + return arch_context_saveandcall(memcpyinternal, NULL, &desc); +} + +int usercopy_fromuser(void *kernel, void *user, size_t size) { + memcpydesc_t desc = { + .dst = kernel, + .src = user, + .size = size + }; + + if (IS_USER_ADDRESS(user) == false) + return EFAULT; + + return arch_context_saveandcall(memcpyinternal, NULL, &desc); +} + +int usercopy_strlen(const char *str, size_t *size) { + strlendesc_t desc = { + .str = str, + .size = size + }; + + if (IS_USER_ADDRESS(str) == false) + return EFAULT; + + return arch_context_saveandcall(strleninternal, NULL, &desc); +} + +int usercopy_fromuseratomic32(uint32_t *user32, uint32_t *value) { + atomic32desc_t desc = { + .value = value, + .address = user32 + }; + + if (IS_USER_ADDRESS(user32) == false) + return EFAULT; + + return arch_context_saveandcall(atomic32internal, NULL, &desc); +} diff --git a/kernel-src/sys/syscalls/accept.c b/kernel-src/sys/syscalls/accept.c index 9f3f09b5..ac71f898 100644 --- a/kernel-src/sys/syscalls/accept.c +++ b/kernel-src/sys/syscalls/accept.c @@ -3,6 +3,7 @@ #include #include +// TODO handle abisockaddr syscallret_t syscall_accept(context_t *, int oldfd, abisockaddr_t *abisockaddr, int *addrlen, int acceptflags) { syscallret_t ret = { .ret = -1 diff --git a/kernel-src/sys/syscalls/bind.c b/kernel-src/sys/syscalls/bind.c index e5b742c4..64cd664b 100644 --- a/kernel-src/sys/syscalls/bind.c +++ b/kernel-src/sys/syscalls/bind.c @@ -35,7 +35,9 @@ syscallret_t syscall_bind(context_t *, int fd, void *uaddr, size_t addrlen) { goto cleanup; } - memcpy(addr, uaddr, addrlen); + ret.errno = usercopy_fromuser(addr, uaddr, addrlen); + if (ret.errno) + goto cleanup; sockaddr_t sockaddr; ret.errno = sock_convertaddress(&sockaddr, addr); diff --git a/kernel-src/sys/syscalls/chdir.c b/kernel-src/sys/syscalls/chdir.c index 0852faa3..99717999 100644 --- a/kernel-src/sys/syscalls/chdir.c +++ b/kernel-src/sys/syscalls/chdir.c @@ -4,19 +4,27 @@ #include #include -syscallret_t syscall_chdir(context_t *, const char *upath) { +syscallret_t syscall_chdir(context_t *, char *upath) { syscallret_t ret = { .ret = -1 }; - if (upath > (char *)USERSPACE_END) { - ret.errno = EFAULT; + size_t pathlen = 0; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); + if (path == NULL) { + ret.errno = ENOMEM; return ret; } - // TODO safe string ops - char *path = alloc(strlen(upath) + 1); - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } vnode_t *ref = path[0] == '/' ? sched_getroot() : sched_getcwd(); vnode_t *new = NULL; diff --git a/kernel-src/sys/syscalls/chmod.c b/kernel-src/sys/syscalls/chmod.c index 16a61c06..841f9b6d 100644 --- a/kernel-src/sys/syscalls/chmod.c +++ b/kernel-src/sys/syscalls/chmod.c @@ -16,18 +16,27 @@ static int dochmod(vnode_t *node, mode_t mode) { return VOP_SETATTR(node, &attr, V_ATTR_MODE, cred); } -syscallret_t syscall_fchmodat(context_t *, int dirfd, const char *upath, mode_t mode, int flags) { +syscallret_t syscall_fchmodat(context_t *, int dirfd, char *upath, mode_t mode, int flags) { syscallret_t ret = { .ret = -1 }; - char *path = alloc(strlen(upath) + 1); + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); if (path == NULL) { ret.errno = ENOMEM; return ret; } - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } file_t *file = NULL; vnode_t *dirnode = NULL; diff --git a/kernel-src/sys/syscalls/chroot.c b/kernel-src/sys/syscalls/chroot.c index 5cec4834..0692dd5b 100644 --- a/kernel-src/sys/syscalls/chroot.c +++ b/kernel-src/sys/syscalls/chroot.c @@ -4,19 +4,27 @@ #include #include -syscallret_t syscall_chroot(context_t *, const char *upath) { +syscallret_t syscall_chroot(context_t *, char *upath) { syscallret_t ret = { .ret = -1 }; - if (upath > (char *)USERSPACE_END) { - ret.errno = EFAULT; + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); + if (path == NULL) { + ret.errno = ENOMEM; return ret; } - // TODO safe string ops - char *path = alloc(strlen(upath) + 1); - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } vnode_t *ref = path[0] == '/' ? sched_getroot() : sched_getcwd(); vnode_t *new = NULL; diff --git a/kernel-src/sys/syscalls/clockget.c b/kernel-src/sys/syscalls/clockget.c index 1923436a..d0a2036e 100644 --- a/kernel-src/sys/syscalls/clockget.c +++ b/kernel-src/sys/syscalls/clockget.c @@ -7,30 +7,28 @@ #define CLOCK_REALTIME 0 #define CLOCK_BOOTTIME 7 -syscallret_t syscall_clockget(context_t *, int clockid, timespec_t *tp){ +syscallret_t syscall_clockget(context_t *, int clockid, timespec_t *tp) { syscallret_t ret = { .ret = -1 }; - if ((void *)tp > USERSPACE_END) { - ret.errno = EFAULT; - return ret; - } - switch (clockid) { - case CLOCK_REALTIME: - // TODO safe memcpy - *tp = timekeeper_time(); + case CLOCK_REALTIME: { + timespec_t ts = timekeeper_time(); + usercopy_touser(tp, &ts, sizeof(timespec_t)); ret.errno = 0; break; - case CLOCK_BOOTTIME: - // TODO safe memcpy - *tp = timekeeper_timefromboot(); + } + case CLOCK_BOOTTIME: { + timespec_t ts = timekeeper_timefromboot(); + usercopy_touser(tp, &ts, sizeof(timespec_t)); ret.errno = 0; break; - default: + } + default: { ret.errno = EINVAL; break; + } } ret.ret = ret.errno ? -1 : 0; diff --git a/kernel-src/sys/syscalls/connect.c b/kernel-src/sys/syscalls/connect.c index 50dbd0bd..a56ad907 100644 --- a/kernel-src/sys/syscalls/connect.c +++ b/kernel-src/sys/syscalls/connect.c @@ -36,7 +36,9 @@ syscallret_t syscall_connect(context_t *, int fd, abisockaddr_t *uaddr, size_t a goto cleanup; } - memcpy(addr, uaddr, addrlen); + ret.errno = usercopy_fromuser(addr, uaddr, addrlen); + if (ret.errno) + goto cleanup; sockaddr_t sockaddr; ret.errno = sock_convertaddress(&sockaddr, addr); diff --git a/kernel-src/sys/syscalls/execve.c b/kernel-src/sys/syscalls/execve.c index 86a5951a..a23bc6c6 100644 --- a/kernel-src/sys/syscalls/execve.c +++ b/kernel-src/sys/syscalls/execve.c @@ -29,13 +29,27 @@ static syscallret_t execve(context_t *context, char *upath, char *uargv[], char return ret; } - // TODO user str ops - char *path = alloc(strlen(upath) + 1); + if (depth == 0 && (IS_USER_ADDRESS(upath) == false || IS_USER_ADDRESS(uargv) == false || IS_USER_ADDRESS(uenvp) == false)) { + ret.errno = EFAULT; + return ret; + } + + size_t pathlen; + ret.errno = USERCOPY_POSSIBLY_STRLEN_FROM_USER(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); if (path == NULL) { ret.errno = ENOMEM; return ret; } - strcpy(path, upath); + + ret.errno = USERCOPY_POSSIBLY_FROM_USER(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } size_t argsize = 0; size_t envsize = 0; @@ -49,8 +63,25 @@ static syscallret_t execve(context_t *context, char *upath, char *uargv[], char void *stack = NULL; char shebang[SHEBANG_SIZE]; - while (uargv[argsize++]); - while (uenvp[envsize++]); + for (;;) { + char *arg; + ret.errno = USERCOPY_POSSIBLY_FROM_USER(&arg, &uargv[argsize], sizeof(arg)); + ++argsize; + if (ret.errno) + goto error; + if (arg == NULL) + break; + } + + for (;;) { + char *env; + ret.errno = USERCOPY_POSSIBLY_FROM_USER(&env, &uenvp[envsize], sizeof(env)); + ++envsize; + if (ret.errno) + goto error; + if (env == NULL) + break; + } size_t argoffset = (sbold ? 1 : 0) + (sbarg ? 1 : 0); argsize += argoffset; @@ -84,22 +115,60 @@ static syscallret_t execve(context_t *context, char *upath, char *uargv[], char argv[0] = tmp; } + // copy arguments for (int i = argoffset; i < argsize - 1; ++i) { - argv[i] = alloc(strlen(uargv[i - argoffset]) + 1); + void *uarg; + ret.errno = USERCOPY_POSSIBLY_FROM_USER(&uarg, &uargv[i - argoffset], sizeof(uarg)); + if (ret.errno) + goto error; + + if (IS_USER_ADDRESS(uarg) == false && depth == 0) { + ret.errno = EFAULT; + goto error; + } + + size_t len; + ret.errno = USERCOPY_POSSIBLY_STRLEN_FROM_USER(uarg, &len); + if (ret.errno) + goto error; + + argv[i] = alloc(len + 1); if (argv[i] == NULL) { ret.errno = ENOMEM; goto error; } - strcpy(argv[i], uargv[i - argoffset]); + + ret.errno = USERCOPY_POSSIBLY_FROM_USER(argv[i], uarg, len); + if (ret.errno) + goto error; } + // copy env for (int i = 0; i < envsize - 1; ++i) { - envp[i] = alloc(strlen(uenvp[i]) + 1); + void *uenv; + ret.errno = USERCOPY_POSSIBLY_FROM_USER(&uenv, &uenvp[i], sizeof(uenv)); + if (ret.errno) + goto error; + + if (IS_USER_ADDRESS(uenv) == false && depth == 0) { + ret.errno = EFAULT; + goto error; + } + + size_t len; + ret.errno = USERCOPY_POSSIBLY_STRLEN_FROM_USER(uenv, &len); + if (ret.errno) + goto error; + + envp[i] = alloc(len + 1); if (envp[i] == NULL) { ret.errno = ENOMEM; goto error; } - strcpy(envp[i], uenvp[i]); + + ret.errno = USERCOPY_POSSIBLY_FROM_USER(envp[i], uenv, len); + if (ret.errno) + goto error; } refnode = *path == '/' ? sched_getroot() : sched_getcwd(); diff --git a/kernel-src/sys/syscalls/faccessat.c b/kernel-src/sys/syscalls/faccessat.c index dde4615a..a9231b4d 100644 --- a/kernel-src/sys/syscalls/faccessat.c +++ b/kernel-src/sys/syscalls/faccessat.c @@ -5,19 +5,27 @@ #include #include -syscallret_t syscall_faccessat(context_t *, int dirfd, const char *upath, int mode, int flags) { +syscallret_t syscall_faccessat(context_t *, int dirfd, char *upath, int mode, int flags) { syscallret_t ret = { .ret = -1 }; - char *path = alloc(strlen(upath) + 1); + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); if (path == NULL) { ret.errno = ENOMEM; return ret; } - // TODO safe strcopy - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } vnode_t *dirnode = NULL; file_t *file = NULL; diff --git a/kernel-src/sys/syscalls/fchownat.c b/kernel-src/sys/syscalls/fchownat.c index f4e7d23f..0914f072 100644 --- a/kernel-src/sys/syscalls/fchownat.c +++ b/kernel-src/sys/syscalls/fchownat.c @@ -2,7 +2,7 @@ #include #include -syscallret_t syscall_fchownat(context_t *, int fd, const char *upath, uid_t owner, gid_t group, int flags) { +syscallret_t syscall_fchownat(context_t *, int fd, char *upath, uid_t owner, gid_t group, int flags) { syscallret_t ret = { .ret = -1 }; @@ -11,7 +11,10 @@ syscallret_t syscall_fchownat(context_t *, int fd, const char *upath, uid_t owne vnode_t *dirnode = NULL; file_t *file = NULL; char *path = NULL; - size_t pathlen = strlen(upath); + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; if (pathlen == 0 && (flags & AT_EMPTY_PATH)) { // chown is done on the file pointed to by fd @@ -32,7 +35,10 @@ syscallret_t syscall_fchownat(context_t *, int fd, const char *upath, uid_t owne goto cleanup; } - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) + goto cleanup; + ret.errno = dirfd_enter(path, fd, &file, &dirnode); if (ret.errno) goto cleanup; diff --git a/kernel-src/sys/syscalls/futex.c b/kernel-src/sys/syscalls/futex.c index 0e5625fc..dafe5865 100644 --- a/kernel-src/sys/syscalls/futex.c +++ b/kernel-src/sys/syscalls/futex.c @@ -74,12 +74,14 @@ syscallret_t syscall_futex(context_t *, uint32_t *futexp, int op, uint32_t value MUTEX_ACQUIRE(&futexmutex, false); + bool doleave = true; uint32_t word; - __atomic_load(futexp, &word, __ATOMIC_RELAXED); + ret.errno = usercopy_fromuseratomic32(futexp, &word); + if (ret.errno) + goto cleanup; uint32_t *physical = vmm_getphysical(futexp); futex_t *futex = getfutex(physical); - bool doleave = true; switch (op) { case FUTEX_WAKE: @@ -161,6 +163,7 @@ syscallret_t syscall_futex(context_t *, uint32_t *futexp, int op, uint32_t value ret.errno = ENOSYS; } + cleanup: if (doleave) poll_leave(&desc); diff --git a/kernel-src/sys/syscalls/getdent.c b/kernel-src/sys/syscalls/getdent.c index eb8cb167..3759a1e7 100644 --- a/kernel-src/sys/syscalls/getdent.c +++ b/kernel-src/sys/syscalls/getdent.c @@ -9,11 +9,6 @@ syscallret_t syscall_getdents(context_t *, int dirfd, void *ubuffer, size_t read .ret = -1 }; - if (ubuffer > USERSPACE_END) { - ret.errno = EFAULT; - return ret; - } - size_t count = readmax / sizeof(dent_t); if (count == 0) { @@ -46,11 +41,13 @@ syscallret_t syscall_getdents(context_t *, int dirfd, void *ubuffer, size_t read goto cleanup; fd->offset = offset + ret.ret; - ret.ret *= sizeof(dent_t); - // TODO safe memcpy - memcpy(ubuffer, buffer, ret.ret); + ret.errno = usercopy_touser(ubuffer, buffer, ret.ret); + if (ret.errno) { + ret.ret = -1; + goto cleanup; + } cleanup: free(buffer); diff --git a/kernel-src/sys/syscalls/getpeername.c b/kernel-src/sys/syscalls/getpeername.c index cce07161..0b3ee7c6 100644 --- a/kernel-src/sys/syscalls/getpeername.c +++ b/kernel-src/sys/syscalls/getpeername.c @@ -6,6 +6,9 @@ syscallret_t syscall_getpeername(context_t *, int fd, void *uaddr, int *addrlen) .ret = -1 }; + ret.errno = ENOSYS; + return ret; + file_t *file = fd_get(fd); if (file == NULL) { ret.errno = EBADF; @@ -30,7 +33,10 @@ syscallret_t syscall_getpeername(context_t *, int fd, void *uaddr, int *addrlen) if (ret.errno) goto cleanup; - memcpy(uaddr, &abisockaddr, min(*addrlen, sizeof(abisockaddr_t))); + ret.errno = usercopy_touser(uaddr, &abisockaddr, min(*addrlen, sizeof(abisockaddr_t))); + if (ret.errno) + goto cleanup; + *addrlen = sizeof(abisockaddr_t); ret.ret = 0; diff --git a/kernel-src/sys/syscalls/getsockname.c b/kernel-src/sys/syscalls/getsockname.c index 6701c2c0..827a8cab 100644 --- a/kernel-src/sys/syscalls/getsockname.c +++ b/kernel-src/sys/syscalls/getsockname.c @@ -30,7 +30,10 @@ syscallret_t syscall_getsockname(context_t *, int fd, void *uaddr, int *addrlen) if (ret.errno) goto cleanup; - memcpy(uaddr, &abisockaddr, min(*addrlen, sizeof(abisockaddr_t))); + ret.errno = usercopy_touser(uaddr, &abisockaddr, min(*addrlen, sizeof(abisockaddr_t))); + if (ret.errno) + goto cleanup; + *addrlen = sizeof(abisockaddr_t); ret.ret = 0; diff --git a/kernel-src/sys/syscalls/gettid.c b/kernel-src/sys/syscalls/gettid.c index f8918f3a..6c7fe931 100644 --- a/kernel-src/sys/syscalls/gettid.c +++ b/kernel-src/sys/syscalls/gettid.c @@ -6,5 +6,6 @@ syscallret_t syscall_gettid(context_t *) { .errno = 0, .ret = _cpu()->thread->tid }; + return ret; } diff --git a/kernel-src/sys/syscalls/hostname.c b/kernel-src/sys/syscalls/hostname.c index 38633e31..53654c4e 100644 --- a/kernel-src/sys/syscalls/hostname.c +++ b/kernel-src/sys/syscalls/hostname.c @@ -31,29 +31,31 @@ syscallret_t syscall_hostname(context_t *, char *unew, size_t newsize, char *uol char new[HOST_NAME_MAX]; char old[HOST_NAME_MAX + 1]; - if (unew) - memcpy(new, unew, newsize); + if (unew) { + ret.errno = usercopy_fromuser(new, unew, newsize); + if (ret.errno) + return ret; + } interrupt_set(false); spinlock_acquire(&lock); + size_t copysize = min(oldsize - 1, bufferlen); if (uold) { - size_t copysize = min(oldsize - 1, bufferlen); - memcpy(old, buffer, copysize); old[copysize] = '\0'; } if (unew) { bufferlen = newsize; - strcpy(buffer, new); + memcpy(buffer, new, newsize); } spinlock_release(&lock); interrupt_set(true); if (uold) - strcpy(uold, old); + ret.errno = usercopy_touser(uold, old, copysize + 1); ret.errno = 0; ret.ret = 0; diff --git a/kernel-src/sys/syscalls/ioctl.c b/kernel-src/sys/syscalls/ioctl.c index 8563876a..1194c39e 100644 --- a/kernel-src/sys/syscalls/ioctl.c +++ b/kernel-src/sys/syscalls/ioctl.c @@ -7,6 +7,11 @@ syscallret_t syscall_ioctl(context_t *, int fd, unsigned long request, void *arg .ret = -1 }; + if (IS_USER_ADDRESS(arg) == false) { + ret.errno = EFAULT; + return ret; + } + file_t *file = fd_get(fd); if (file == NULL) { ret.errno = EBADF; diff --git a/kernel-src/sys/syscalls/linkat.c b/kernel-src/sys/syscalls/linkat.c index e6fb67b8..85927341 100644 --- a/kernel-src/sys/syscalls/linkat.c +++ b/kernel-src/sys/syscalls/linkat.c @@ -2,27 +2,38 @@ #include -syscallret_t syscall_linkat(context_t *, int olddirfd, const char *uoldpath, int newdirfd, const char *unewpath, int flags, int type) { +syscallret_t syscall_linkat(context_t *, int olddirfd, char *uoldpath, int newdirfd, char *unewpath, int flags, int type) { syscallret_t ret = { .ret = -1 }; - char *oldpath = alloc(strlen(uoldpath) + 1); + size_t oldpathlen; + size_t newpathlen; + + if (usercopy_strlen(uoldpath, &oldpathlen) || usercopy_strlen(unewpath, &newpathlen)) { + ret.errno = EFAULT; + return ret; + } + + char *oldpath = alloc(oldpathlen + 1); if (oldpath == NULL) { ret.errno = ENOMEM; return ret; } - char *newpath = alloc(strlen(unewpath) + 1); + char *newpath = alloc(newpathlen + 1); if (newpath == NULL) { free(oldpath); ret.errno = ENOMEM; return ret; } - // TODO safe strcopy - strcpy(oldpath, uoldpath); - strcpy(newpath, unewpath); + if (usercopy_fromuser(oldpath, uoldpath, oldpathlen) || usercopy_fromuser(newpath, unewpath, newpathlen)) { + ret.errno = EFAULT; + free(newpath); + free(oldpath); + return ret; + } vnode_t *olddirnode = NULL; file_t *oldfile = NULL; diff --git a/kernel-src/sys/syscalls/mkdirat.c b/kernel-src/sys/syscalls/mkdirat.c index 797996dc..5410af77 100644 --- a/kernel-src/sys/syscalls/mkdirat.c +++ b/kernel-src/sys/syscalls/mkdirat.c @@ -5,19 +5,27 @@ #include #include -syscallret_t syscall_mkdirat(context_t *, int dirfd, const char *upath, mode_t mode) { +syscallret_t syscall_mkdirat(context_t *, int dirfd, char *upath, mode_t mode) { syscallret_t ret = { .ret = -1 }; - char *path = alloc(strlen(upath) + 1); + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); if (path == NULL) { ret.errno = ENOMEM; return ret; } - // TODO safe strcopy - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } vnode_t *dirnode = NULL; file_t *file = NULL; diff --git a/kernel-src/sys/syscalls/mount.c b/kernel-src/sys/syscalls/mount.c index 30117313..a5b0f61b 100644 --- a/kernel-src/sys/syscalls/mount.c +++ b/kernel-src/sys/syscalls/mount.c @@ -4,24 +4,36 @@ #include #include -syscallret_t syscall_mount(context_t *context, const char *ubacking, const char *umountpoint, const char *ufs, unsigned long flags, void *data) { +static void freeptrs(void *a, void *b, void *c) { + if (a) + free(a); + + if (b) + free (b); + + if (c) + free (c); +} + +syscallret_t syscall_mount(context_t *context, char *ubacking, char *umountpoint, char *ufs, unsigned long flags, void *data) { syscallret_t ret = { .ret = -1 }; __assert(flags == 0); - if ((void *)ubacking > USERSPACE_END || (void *)umountpoint > USERSPACE_END || (void *)ufs > USERSPACE_END) { + size_t mountpointlen, fslen; + + if (usercopy_strlen(umountpoint, &mountpointlen) || usercopy_strlen(ufs, &fslen)) { ret.errno = EFAULT; return ret; } ret.errno = ENOMEM; - char *mountpoint = alloc(strlen(umountpoint) + 1); - if (mountpoint == NULL) { + char *mountpoint = alloc(mountpointlen + 1); + if (mountpoint == NULL) return ret; - } - char *fs = alloc(strlen(ufs) + 1); + char *fs = alloc(fslen + 1); if (fs == NULL) { free(mountpoint); return ret; @@ -29,16 +41,32 @@ syscallret_t syscall_mount(context_t *context, const char *ubacking, const char char *backing = NULL; if (ubacking) { - backing = alloc(strlen(ubacking) + 1); - if (backing == NULL) { - free(mountpoint); - free(fs); + size_t backinglen; + + ret.errno = usercopy_strlen(ubacking, &backinglen); + if (ret.errno) { + freeptrs(mountpoint, fs, NULL); + return ret; + } + + backing = alloc(backinglen + 1); + if (backing == NULL) { + freeptrs(mountpoint, fs, NULL); + return ret; + } + + ret.errno = usercopy_fromuser(backing, ubacking, backinglen); + if (ret.errno) { + freeptrs(backing, mountpoint, fs); return ret; } - strcpy(backing, ubacking); } - strcpy(fs, ufs); - strcpy(mountpoint, umountpoint); + + if (usercopy_fromuser(fs, ufs, fslen) || usercopy_fromuser(mountpoint, umountpoint, mountpointlen)) { + ret.errno = EFAULT; + freeptrs(fs, mountpoint, backing); + return ret; + } vnode_t *backingrefnode = NULL; if (ubacking) diff --git a/kernel-src/sys/syscalls/open.c b/kernel-src/sys/syscalls/open.c index 3e911dfe..85b1b713 100644 --- a/kernel-src/sys/syscalls/open.c +++ b/kernel-src/sys/syscalls/open.c @@ -5,7 +5,7 @@ #include #include -syscallret_t syscall_openat(context_t *context, int dirfd, const char *path, int flags, mode_t mode) { +syscallret_t syscall_openat(context_t *context, int dirfd, char *path, int flags, mode_t mode) { syscallret_t ret = { .ret = -1, .errno = -1 @@ -17,16 +17,25 @@ syscallret_t syscall_openat(context_t *context, int dirfd, const char *path, int vnode_t *dirnode = NULL; file_t *dirfile = NULL; - size_t pathsize = strlen(path); // TODO u_strlen + size_t pathsize; + ret.errno = usercopy_strlen(path, &pathsize); char *pathbuf = alloc(pathsize + 1); if (pathbuf == NULL) { ret.errno = ENOMEM; return ret; } - strcpy(pathbuf, path); // TODO u_strcpy + ret.errno = usercopy_fromuser(pathbuf, path, pathsize); + if (ret.errno) { + free(pathbuf); + return ret; + } ret.errno = dirfd_enter(pathbuf, dirfd, &dirfile, &dirnode); + if (ret.errno) { + free(pathbuf); + return ret; + } retry_open: file_t *newfile = NULL; diff --git a/kernel-src/sys/syscalls/poll.c b/kernel-src/sys/syscalls/poll.c index e1d47459..1a9d6804 100644 --- a/kernel-src/sys/syscalls/poll.c +++ b/kernel-src/sys/syscalls/poll.c @@ -16,11 +16,6 @@ syscallret_t syscall_poll(context_t *, pollfd_t *fds, size_t nfds, int timeoutms .ret = -1 }; - if ((void *)fds > USERSPACE_END) { - ret.errno = EFAULT; - return ret; - } - size_t fdsbuffsize = nfds * sizeof(pollfd_t); pollfd_t *fdsbuff = alloc(fdsbuffsize); if (fdsbuff == NULL) { @@ -28,7 +23,11 @@ syscallret_t syscall_poll(context_t *, pollfd_t *fds, size_t nfds, int timeoutms return ret; } - memcpy(fdsbuff, fds, fdsbuffsize); + ret.errno = usercopy_fromuser(fdsbuff, fds, fdsbuffsize); + if (ret.errno) { + free(fdsbuff); + return ret; + } // we need to keep holding the files so another thread doesn't close them and break everything file_t **filebuff = alloc(sizeof(file_t *) * nfds); @@ -80,7 +79,7 @@ syscallret_t syscall_poll(context_t *, pollfd_t *fds, size_t nfds, int timeoutms } } - memcpy(fds, fdsbuff, fdsbuffsize); + ret.errno = usercopy_touser(fds, fdsbuff, fdsbuffsize); poll_leave(&desc); poll_destroydesc(&desc); @@ -91,7 +90,7 @@ syscallret_t syscall_poll(context_t *, pollfd_t *fds, size_t nfds, int timeoutms fd_release(filebuff[i]); } - ret.ret = eventcount; + ret.ret = ret.errno ? -1 : eventcount; cleanup: if (filebuff) diff --git a/kernel-src/sys/syscalls/read.c b/kernel-src/sys/syscalls/read.c index d672585e..f49d42b1 100644 --- a/kernel-src/sys/syscalls/read.c +++ b/kernel-src/sys/syscalls/read.c @@ -36,12 +36,8 @@ syscallret_t syscall_read(context_t *context, int fd, void *buffer, size_t size) goto cleanup; file->offset = offset + bytesread; - ret.ret = bytesread; - ret.errno = 0; - - // TODO safe memcpy - memcpy(buffer, kernelbuff, bytesread); - + ret.errno = usercopy_touser(buffer, kernelbuff, bytesread); + ret.ret = ret.errno ? -1 : bytesread; cleanup: if (file) fd_release(file); diff --git a/kernel-src/sys/syscalls/readlinkat.c b/kernel-src/sys/syscalls/readlinkat.c index cf6f8ebd..d8ffaecf 100644 --- a/kernel-src/sys/syscalls/readlinkat.c +++ b/kernel-src/sys/syscalls/readlinkat.c @@ -4,18 +4,27 @@ #include #include -syscallret_t syscall_readlinkat(context_t *, int dirfd, const char *upath, char *ubuffer, size_t ubuffersize) { +syscallret_t syscall_readlinkat(context_t *, int dirfd, char *upath, char *ubuffer, size_t ubuffersize) { syscallret_t ret = { .ret = -1 }; - char *path = alloc(strlen(upath) + 1); + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); if (path == NULL) { ret.errno = ENOMEM; return ret; } - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } file_t *file = NULL; vnode_t *dirnode = NULL; @@ -36,9 +45,8 @@ syscallret_t syscall_readlinkat(context_t *, int dirfd, const char *upath, char size_t bufferlen = strlen(buffer); size_t copylen = bufferlen > ubuffersize ? ubuffersize : bufferlen; - memcpy(ubuffer, buffer, copylen); - - ret.ret = copylen; + ret.errno = usercopy_touser(ubuffer, buffer, copylen); + ret.ret = ret.errno ? -1 : copylen; cleanup: diff --git a/kernel-src/sys/syscalls/recvmsg.c b/kernel-src/sys/syscalls/recvmsg.c index 0ef464e2..88e54a00 100644 --- a/kernel-src/sys/syscalls/recvmsg.c +++ b/kernel-src/sys/syscalls/recvmsg.c @@ -48,14 +48,19 @@ syscallret_t syscall_recvmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) uintmax_t iovoffset = 0; for (int i = 0; i < msghdr.iovcount; ++i) { - memcpy(msghdr.iov[i].addr, (void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].len); + ret.errno = usercopy_touser(msghdr.iov[i].addr, (void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].len); + if (ret.errno) + goto cleanup; iovoffset += msghdr.iov[i].len; } - if (umsghdr->addr) { - ret.errno = sock_addrtoabiaddr(socket->type, &sockaddr, umsghdr->addr); + if (msghdr.addr) { + abisockaddr_t abisockaddr; + ret.errno = sock_addrtoabiaddr(socket->type, &sockaddr, &abisockaddr); if (ret.errno) goto cleanup; + + ret.errno = usercopy_touser(msghdr.addr, &abisockaddr, min(sizeof(abisockaddr), msghdr.addrlen)); } cleanup: diff --git a/kernel-src/sys/syscalls/renameat.c b/kernel-src/sys/syscalls/renameat.c index 0133edca..53ff70e5 100644 --- a/kernel-src/sys/syscalls/renameat.c +++ b/kernel-src/sys/syscalls/renameat.c @@ -3,31 +3,40 @@ #include #include -syscallret_t syscall_renameat(context_t *context, int olddirfd, const char *uoldpath, int newdirfd, const char *unewpath, unsigned int flags) { +syscallret_t syscall_renameat(context_t *context, int olddirfd, char *uoldpath, int newdirfd, char *unewpath, unsigned int flags) { syscallret_t ret = { .ret = -1 }; __assert(flags == 0); + size_t oldpathlen; + size_t newpathlen; + + if (usercopy_strlen(uoldpath, &oldpathlen) || usercopy_strlen(unewpath, &newpathlen)) { + ret.errno = EFAULT; + return ret; + } + char *oldcomponent = NULL; char *newcomponent = NULL; - char *oldpath = alloc(strlen(uoldpath) + 1); + char *oldpath = alloc(oldpathlen + 1); if (oldpath == NULL) { ret.errno = ENOMEM; return ret; } - char *newpath = alloc(strlen(unewpath) + 1); + char *newpath = alloc(newpathlen + 1); if (newpath == NULL) { free(oldpath); ret.errno = ENOMEM; return ret; } - // TODO safe strcopy - strcpy(oldpath, uoldpath); - strcpy(newpath, unewpath); + if (usercopy_fromuser(oldpath, uoldpath, oldpathlen) || usercopy_fromuser(newpath, unewpath, newpathlen)) { + ret.errno = EFAULT; + return ret; + } vnode_t *olddirnode = NULL; file_t *oldfile = NULL; @@ -45,8 +54,8 @@ syscallret_t syscall_renameat(context_t *context, int olddirfd, const char *uold if (ret.errno) goto cleanup; - oldcomponent = alloc(strlen(oldpath)); - newcomponent = alloc(strlen(newpath)); + oldcomponent = alloc(strlen(oldpath) + 1); + newcomponent = alloc(strlen(newpath) + 1); if (oldcomponent == NULL && newcomponent == NULL) goto cleanup; diff --git a/kernel-src/sys/syscalls/sendmsg.c b/kernel-src/sys/syscalls/sendmsg.c index 550de3f5..d9a79069 100644 --- a/kernel-src/sys/syscalls/sendmsg.c +++ b/kernel-src/sys/syscalls/sendmsg.c @@ -5,8 +5,9 @@ #include #include +// TODO nosignal syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) { - __assert(flags == 0); + //__assert(flags == 0); syscallret_t ret; msghdr_t msghdr; @@ -25,7 +26,10 @@ syscallret_t syscall_sendmsg(context_t *, int fd, msghdr_t *umsghdr, int flags) uintmax_t iovoffset = 0; for (int i = 0; i < msghdr.iovcount; ++i) { - memcpy((void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].addr, msghdr.iov[i].len); + ret.errno = usercopy_fromuser((void *)((uintptr_t)buffer + iovoffset), msghdr.iov[i].addr, msghdr.iov[i].len); + if (ret.errno) + goto cleanup; + iovoffset += msghdr.iov[i].len; } diff --git a/kernel-src/sys/syscalls/setitimer.c b/kernel-src/sys/syscalls/setitimer.c index 9652d4a5..46d04e9f 100644 --- a/kernel-src/sys/syscalls/setitimer.c +++ b/kernel-src/sys/syscalls/setitimer.c @@ -45,11 +45,14 @@ syscallret_t syscall_getitimer(context_t *context, int which, itimerval_t *value MUTEX_RELEASE(&_cpu()->thread->proc->timer.mutex); - value->interval.s = oldrepeat / 1000000; - value->interval.us = oldrepeat % 1000000; - value->value.s = oldremaining / 1000000; - value->value.us = oldremaining % 1000000; - ret.errno = 0; + itimerval_t tmp; + + tmp.interval.s = oldrepeat / 1000000; + tmp.interval.us = oldrepeat % 1000000; + tmp.value.s = oldremaining / 1000000; + tmp.value.us = oldremaining % 1000000; + ret.errno = usercopy_touser(value, &tmp, sizeof(tmp)); + ret.ret = ret.errno ? -1 : 0; return ret; } @@ -67,8 +70,11 @@ syscallret_t syscall_setitimer(context_t *context, int which, itimerval_t *unew, } itimerval_t val = {0}; - if (unew) - val = *unew; + if (unew) { + ret.errno = usercopy_fromuser(&val, unew, sizeof(val)); + if (ret.errno) + return ret; + } MUTEX_ACQUIRE(&_cpu()->thread->proc->timer.mutex, false); uintmax_t oldremaining, oldrepeat; @@ -84,13 +90,17 @@ syscallret_t syscall_setitimer(context_t *context, int which, itimerval_t *unew, MUTEX_RELEASE(&_cpu()->thread->proc->timer.mutex); + ret.errno = 0; if (uold) { + itimerval_t tmp; uold->interval.s = oldrepeat / 1000000; uold->interval.us = oldrepeat % 1000000; uold->value.s = oldremaining / 1000000; uold->value.us = oldremaining % 1000000; + ret.errno = usercopy_touser(uold, &tmp, sizeof(tmp)); } - ret.errno = 0; + ret.ret = ret.errno ? -1 : 0; + return ret; } diff --git a/kernel-src/sys/syscalls/setsockopt.c b/kernel-src/sys/syscalls/setsockopt.c index c035d3aa..8dab71ce 100644 --- a/kernel-src/sys/syscalls/setsockopt.c +++ b/kernel-src/sys/syscalls/setsockopt.c @@ -21,7 +21,11 @@ syscallret_t syscall_setsockopt(context_t *, int fd, int level, int optname, voi ret.errno = ENOMEM; return ret; } - memcpy(buffer, val, len); + ret.errno = usercopy_fromuser(buffer, val, len); + if (ret.errno) { + free(buffer); + return ret; + } } file_t *file = fd_get(fd); @@ -43,7 +47,7 @@ syscallret_t syscall_setsockopt(context_t *, int fd, int level, int optname, voi switch (optname) { case SO_BINDTODEVICE: { if (val) { - socket->netdev = netdev_getdev(val); + socket->netdev = netdev_getdev(buffer); ret.errno = socket->netdev ? 0 : ENODEV; } else { socket->netdev = NULL; diff --git a/kernel-src/sys/syscalls/sigaction.c b/kernel-src/sys/syscalls/sigaction.c index 977830e0..74f3288a 100644 --- a/kernel-src/sys/syscalls/sigaction.c +++ b/kernel-src/sys/syscalls/sigaction.c @@ -14,14 +14,22 @@ syscallret_t syscall_sigaction(context_t *, int sig, sigaction_t *new, sigaction sigaction_t newtmp, oldtmp; if (new) { - newtmp = *new; - __assert(newtmp.flags & SA_RESTORER); + ret.errno = usercopy_fromuser(&newtmp, new, sizeof(sigaction_t)); + if (ret.errno) + return ret; + + if ((newtmp.flags & SA_RESTORER) == 0) { + ret.errno = EINVAL; + return ret; + } } signal_action(_cpu()->thread->proc, sig, new ? &newtmp : NULL, old ? &oldtmp : NULL); - if (old) - *old = oldtmp; + if (old && usercopy_touser(old, &oldtmp, sizeof(sigaction_t))) { + ret.errno = EFAULT; + return ret; + } ret.errno = 0; ret.ret = 0; diff --git a/kernel-src/sys/syscalls/sigaltstack.c b/kernel-src/sys/syscalls/sigaltstack.c index 091557ee..da8bb604 100644 --- a/kernel-src/sys/syscalls/sigaltstack.c +++ b/kernel-src/sys/syscalls/sigaltstack.c @@ -7,13 +7,17 @@ syscallret_t syscall_sigaltstack(context_t *, stack_t *new, stack_t *old) { }; stack_t newtmp, oldtmp; - if (new) - newtmp = *new; + if (new && usercopy_fromuser(&newtmp, new, sizeof(stack_t))) { + ret.errno = EFAULT; + return ret; + } signal_altstack(_cpu()->thread, new ? &newtmp : NULL, old ? &oldtmp : NULL); - if (old) - *old = oldtmp; + if (old && usercopy_touser(old, &oldtmp, sizeof(stack_t))) { + ret.errno = EFAULT; + return ret; + } ret.errno = 0; ret.ret = 0; diff --git a/kernel-src/sys/syscalls/sigprocmask.c b/kernel-src/sys/syscalls/sigprocmask.c index 7c61a667..3c48667a 100644 --- a/kernel-src/sys/syscalls/sigprocmask.c +++ b/kernel-src/sys/syscalls/sigprocmask.c @@ -18,13 +18,17 @@ syscallret_t syscall_sigprocmask(context_t *, int how, sigset_t *set, sigset_t * return ret; } - new = *set; + ret.errno = usercopy_fromuser(&new, set, sizeof(sigset_t)); + if (ret.errno) + return ret; } signal_changemask(_cpu()->thread, how, set ? &new : NULL, oldset ? &old : NULL); - if (oldset) - *oldset = old; + if (oldset && usercopy_touser(oldset, &old, sizeof(sigset_t))) { + ret.errno = EFAULT; + return ret; + } ret.ret = 0; ret.errno = 0; diff --git a/kernel-src/sys/syscalls/sigreturn.c b/kernel-src/sys/syscalls/sigreturn.c index d1f1736c..77b396ef 100644 --- a/kernel-src/sys/syscalls/sigreturn.c +++ b/kernel-src/sys/syscalls/sigreturn.c @@ -5,9 +5,12 @@ // this expects CTX_SP to be pointing to the signal frame __attribute__((noreturn)) void syscall_sigreturn(context_t *context) { - // TODO check if the information is valid sigframe_t sigframe; - memcpy(&sigframe, (void *)CTX_SP(context), sizeof(sigframe_t)); + int error = usercopy_fromuser(&sigframe, (void *)CTX_SP(context), sizeof(sigframe_t)); + if (error || ARCH_CONTEXT_ISUSER(&sigframe.context) == false) { + printf("syscall_sigreturn: bad return stack or bad return information\n"); + sched_terminateprogram(SIGSEGV); + } interrupt_set(false); signal_altstack(_cpu()->thread, &sigframe.oldstack, NULL); diff --git a/kernel-src/sys/syscalls/sleep.c b/kernel-src/sys/syscalls/sleep.c index 9f688f0d..cdf77458 100644 --- a/kernel-src/sys/syscalls/sleep.c +++ b/kernel-src/sys/syscalls/sleep.c @@ -14,12 +14,10 @@ syscallret_t syscall_nanosleep(context_t *, timespec_t *utime, timespec_t *remai .ret = -1 }; - if ((void *)utime > USERSPACE_END || (void *)remaining > USERSPACE_END) { - ret.errno = EFAULT; + timespec_t time; + ret.errno = usercopy_fromuser(&time, utime, sizeof(timespec_t)); + if (ret.errno) return ret; - } - - timespec_t time = *utime; if (time.ns > 999999999 || time.ns < 0) { ret.errno = EINVAL; @@ -34,8 +32,12 @@ syscallret_t syscall_nanosleep(context_t *, timespec_t *utime, timespec_t *remai ret.errno = sched_yield(); - if (ret.errno) - timer_remove(_cpu()->timer, &sleepentry); + if (ret.errno) { + uintmax_t remainingus = timer_remove(_cpu()->timer, &sleepentry); + time.ns = (remainingus % 1000000) * 1000; + time.s = (remainingus / 1000000); + ret.errno = usercopy_touser(remaining, &time, sizeof(timespec_t)) ? EFAULT : EINTR; + } sched_targetcpu(NULL); diff --git a/kernel-src/sys/syscalls/stat.c b/kernel-src/sys/syscalls/stat.c index 289acc8a..a23d494d 100644 --- a/kernel-src/sys/syscalls/stat.c +++ b/kernel-src/sys/syscalls/stat.c @@ -44,9 +44,8 @@ syscallret_t syscall_fstat(context_t *ctx, int fd, stat_t *ustat) { if (ret.errno) goto cleanup; - // TODO safe memcpy - *ustat = buf; - ret.ret = 0; + ret.errno = usercopy_touser(ustat, &buf, sizeof(stat_t)); + ret.ret = ret.errno ? -1 : 0; cleanup: fd_release(file); @@ -58,12 +57,22 @@ syscallret_t syscall_fstatat(context_t *ctx, int dirfd, char *upath, stat_t *ust .ret = -1 }; - char *path = alloc(strlen(upath) + 1); + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); if (path == NULL) { ret.errno = ENOMEM; return ret; } - strcpy(path, upath); + + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } vnode_t *dirnode = NULL; file_t *file = NULL; @@ -81,9 +90,8 @@ syscallret_t syscall_fstatat(context_t *ctx, int dirfd, char *upath, stat_t *ust if (ret.errno) goto cleanup; - // TODO safe memcpy - *ustat = buf; - ret.ret = 0; + ret.errno = usercopy_touser(ustat, &buf, sizeof(stat_t)); + ret.ret = ret.errno ? -1 : 0; cleanup: if (node) diff --git a/kernel-src/sys/syscalls/uname.c b/kernel-src/sys/syscalls/uname.c index 9d134921..c83eaed8 100644 --- a/kernel-src/sys/syscalls/uname.c +++ b/kernel-src/sys/syscalls/uname.c @@ -11,6 +11,8 @@ typedef struct { } utsname_t; void hostname_get(char *buf); +static char *sysname = "Astral"; +static char *release = "Astral"; syscallret_t syscall_uname(context_t *, utsname_t *utsname) { syscallret_t ret = {0}; @@ -18,12 +20,14 @@ syscallret_t syscall_uname(context_t *, utsname_t *utsname) { char hostname[HOST_NAME_MAX + 1]; hostname_get(hostname); - strcpy(utsname->sysname, "Astral"); - strcpy(utsname->nodename, hostname); - strcpy(utsname->release, "Astral"); - strcpy(utsname->version, BUILD_DATE); - strcpy(utsname->machine, BUILD_TARGET); - strcpy(utsname->domainname, hostname); + if ( + usercopy_touser(utsname->sysname, sysname, strlen(sysname) + 1) || + usercopy_touser(utsname->nodename, hostname, strlen(hostname) + 1) || + usercopy_touser(utsname->release, release, strlen(release) + 1) || + usercopy_touser(utsname->version, BUILD_DATE, strlen(BUILD_DATE) + 1) || + usercopy_touser(utsname->machine, BUILD_TARGET, strlen(BUILD_TARGET) + 1) || + usercopy_touser(utsname->domainname, hostname, strlen(hostname) + 1)) + ret.errno = EFAULT; return ret; } diff --git a/kernel-src/sys/syscalls/unlinkat.c b/kernel-src/sys/syscalls/unlinkat.c index ddc6327c..b33bcc8b 100644 --- a/kernel-src/sys/syscalls/unlinkat.c +++ b/kernel-src/sys/syscalls/unlinkat.c @@ -5,25 +5,32 @@ #include #include -syscallret_t syscall_unlinkat(context_t *, int dirfd, const char *upath, int flags) { +syscallret_t syscall_unlinkat(context_t *, int dirfd, char *upath, int flags) { syscallret_t ret = { .ret = -1 }; - size_t pathlen = strlen(upath) + 1; - char *path = alloc(pathlen); + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + return ret; + + char *path = alloc(pathlen + 1); if (path == NULL) { ret.errno = ENOMEM; return ret; } - // TODO safe strcopy - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) { + free(path); + return ret; + } vnode_t *dirnode = NULL; file_t *file = NULL; - char *component = alloc(pathlen); + char *component = alloc(pathlen + 1); if (component == NULL) { ret.errno = ENOMEM; goto cleanup; diff --git a/kernel-src/sys/syscalls/utime.c b/kernel-src/sys/syscalls/utime.c index 4f9cde38..2e32d1a7 100644 --- a/kernel-src/sys/syscalls/utime.c +++ b/kernel-src/sys/syscalls/utime.c @@ -4,14 +4,18 @@ syscallret_t syscall_utimensat(context_t *, int fd, char *upath, timespec_t uts[2], int flags) { syscallret_t ret = { - .ret = -1 + .ret = -1, + .errno = 0 }; timespec_t ts[2]; if (uts == NULL) ts[0] = ts[1] = timekeeper_time(); else - memcpy(ts, uts, sizeof(timespec_t) * 2); + ret.errno = usercopy_fromuser(ts, uts, sizeof(timespec_t) * 2); + + if (ret.errno) + return ret; vnode_t *node = NULL; vnode_t *dirnode = NULL; @@ -31,13 +35,21 @@ syscallret_t syscall_utimensat(context_t *, int fd, char *upath, timespec_t uts[ fd_release(file); } else { // operation is done on the file pointed to by the path relative to fd - path = alloc(strlen(upath) + 1); + size_t pathlen; + ret.errno = usercopy_strlen(upath, &pathlen); + if (ret.errno) + goto cleanup; + + path = alloc(pathlen + 1); if (path == NULL) { ret.errno = ENOMEM; goto cleanup; } - strcpy(path, upath); + ret.errno = usercopy_fromuser(path, upath, pathlen); + if (ret.errno) + goto cleanup; + ret.errno = dirfd_enter(path, fd, &file, &dirnode); if (ret.errno) goto cleanup; diff --git a/kernel-src/sys/syscalls/waitpid.c b/kernel-src/sys/syscalls/waitpid.c index c651ef9c..508227dc 100644 --- a/kernel-src/sys/syscalls/waitpid.c +++ b/kernel-src/sys/syscalls/waitpid.c @@ -14,7 +14,6 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt .ret = -1 }; - // TODO address check __assert((options & ~KNOWN_FLAGS) == 0); // TODO implement these __assert(pid == -1 || pid > 0); @@ -94,10 +93,11 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt proc->child = iterator->sibling; } - // TODO memory safe operation if (status) { int statustmp = iterator->status; - *status = statustmp; + ret.errno = usercopy_touser(status, &statustmp, sizeof(statustmp)); + } else { + ret.errno = 0; } MUTEX_RELEASE(&proc->mutex); @@ -125,7 +125,6 @@ syscallret_t syscall_waitpid(context_t *context, pid_t pid, int *status, int opt } ret.ret = iterator->pid; - ret.errno = 0; __assert(iterator); // process will no longer be referenced by the child list diff --git a/kernel-src/sys/syscalls/write.c b/kernel-src/sys/syscalls/write.c index 784a5dde..046c5731 100644 --- a/kernel-src/sys/syscalls/write.c +++ b/kernel-src/sys/syscalls/write.c @@ -27,8 +27,9 @@ syscallret_t syscall_write(context_t *context, int fd, void *buffer, size_t size goto cleanup; } - // TODO safe memcpy - memcpy(kernelbuff, buffer, size); + ret.errno = usercopy_fromuser(kernelbuff, buffer, size); + if (ret.errno) + goto cleanup; size_t byteswritten; uintmax_t offset = file->offset;