summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/malloc.c1
-rw-r--r--src/kernel/malloc.h1
-rw-r--r--src/kernel/syscalls.c47
-rw-r--r--src/kernel/vfs/request.c8
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);