diff options
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/malloc.c | 1 | ||||
-rw-r--r-- | src/kernel/malloc.h | 1 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 47 | ||||
-rw-r--r-- | src/kernel/vfs/request.c | 8 |
4 files changed, 51 insertions, 6 deletions
diff --git a/src/kernel/malloc.c b/src/kernel/malloc.c index 2fe4792..eb0d01f 100644 --- a/src/kernel/malloc.c +++ b/src/kernel/malloc.c @@ -28,6 +28,7 @@ static const char *tagnames[] = { "RootCache", /* TagRootCache */ "PageRefcount", /* TagPageRefcount */ "Intr", /* TagIntr */ + "XattrName", /* TagXattrName */ }; static_assert(sizeof(tagnames) == sizeof(const char *) * TagLast); diff --git a/src/kernel/malloc.h b/src/kernel/malloc.h index af033f5..2108dad 100644 --- a/src/kernel/malloc.h +++ b/src/kernel/malloc.h @@ -30,6 +30,7 @@ enum MallocTag { TagRootCache, TagPageRefcount, TagIntr, + TagXattrName, TagLast, }; diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 0730620..436000c 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -302,11 +302,13 @@ long _sys_fs_respond(hid_t hid, const void __user *buf, long ret, int flags) { if (!h || h->type != HANDLE_FS_REQ) SYSCALL_RETURN(-EBADF); VfsReq *req = h->req; if (req) { + // TODO this shouldn't be limited to 32 bits + long len = min(ret, capped_cast32(req->outlen)); if (ret > 0 && req->type == VFSOP_READ) { - /* vfsreq_finish can't copy this data, as it doesn't know where the - * buf argument came from */ - ret = min(ret, capped_cast32(req->outlen)); - ret = pcpy_bi(req->caller, req->out, proc_cur, buf, ret); + ret = pcpy_bi(req->caller, req->out, proc_cur, buf, len); + } else if (ret > 0 && req->type == VFSOP_GETXATTR) { + /* intentionally ignoring the return value */ + pcpy_bi(req->caller, req->out, proc_cur, buf, len); } vfsreq_finish(req, (void __user *)buf, ret, flags, proc_cur); } @@ -510,6 +512,42 @@ void _sys_intr_return(struct intr_data __user *intr, int flags) { regs_safecopy(&proc_cur->regs, &d.reg); } +ssize_t _sys_getxattr(hid_t hid, const char __user *name, void __user *buf, size_t len, int flags) { + Handle *h = hs_get(proc_cur->hs, hid); + if (!h) { + SYSCALL_RETURN(-EBADF); + } + if (h->type != HANDLE_FILE || flags != 0) { + SYSCALL_RETURN(-ENOSYS); + } + if (!h->readable) { + SYSCALL_RETURN(-EACCES); + } + char tmpbuf[XATTRNAME_MAX]; + // TODO test pcpy_from_str edge cases + size_t namelen = pcpy_from_str(proc_cur, tmpbuf, name, XATTRNAME_MAX); + if (namelen == 0) { + SYSCALL_RETURN(-EFAULT); + } + assert(namelen <= XATTRNAME_MAX); + assert(tmpbuf[namelen-1] == '\0'); + + char *namebuf = kmalloc(namelen, TagXattrName); + memcpy(namebuf, tmpbuf, namelen); + + vfsreq_dispatchcopy((VfsReq) { + .type = VFSOP_GETXATTR, + .backend = h->backend, + .id = h->file_id, + .caller = proc_cur, + .kin = namebuf, + .kinlen = namelen-1, + .out = buf, + .outlen = len, + }); + return 0; +} + long _sys_execbuf(void __user *ubuf, size_t len) { if (len == 0) SYSCALL_RETURN(0); static_assert(EXECBUF_MAX_LEN <= KMALLOC_MAX); @@ -568,6 +606,7 @@ long _syscall(long num, long a, long b, long c, long d, long e) { break; case _SYS_GETNULL: _sys_getnull(a); break; case _SYS_DUPLEX: _sys_duplex(a, b, c); break; case _SYS_INTR_RETURN: _sys_intr_return((userptr_t)a, b); + break; case _SYS_GETXATTR: _sys_getxattr(a, (userptr_t)b, (userptr_t)c, d, e); break; case _SYS_EXECBUF: _sys_execbuf((userptr_t)a, b); break; case _SYS_DEBUG_KLOG: _sys_debug_klog((userptr_t)a, b); break; diff --git a/src/kernel/vfs/request.c b/src/kernel/vfs/request.c index 9b60080..50fcc22 100644 --- a/src/kernel/vfs/request.c +++ b/src/kernel/vfs/request.c @@ -151,8 +151,12 @@ vfsback_useraccept(VfsReq *req) assert(!(req->kin && req->uin)); if (req->kin) { void __user *buf = handler->awaited_req.buf; - len = min(req->kinlen, handler->awaited_req.max_len); - pcpy_to(handler, buf, req->kin, len); + if (req->kinlen+1 <= handler->awaited_req.max_len) { + len = req->kinlen; + pcpy_to(handler, buf, req->kin, len+1); /* +1 for NUL */ + } else { + panic_unimplemented(); // TODO! fail + } } else if (req->uin) { void __user *buf = handler->awaited_req.buf; len = min(req->uinlen, handler->awaited_req.max_len); |