summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/syscalls.c36
-rw-r--r--src/kernel/vfs/request.c9
-rw-r--r--src/kernel/vfs/request.h2
3 files changed, 46 insertions, 1 deletions
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 436000c..50ff589 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -548,6 +548,41 @@ ssize_t _sys_getxattr(hid_t hid, const char __user *name, void __user *buf, size
return 0;
}
+ssize_t _sys_setxattr(hid_t hid, const char __user *name, const 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->writeable) {
+ SYSCALL_RETURN(-EACCES);
+ }
+ char tmpbuf[XATTRNAME_MAX];
+ 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_SETXATTR,
+ .backend = h->backend,
+ .id = h->file_id,
+ .caller = proc_cur,
+ .kin = namebuf,
+ .kinlen = namelen-1,
+ .uin = buf,
+ .uinlen = 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);
@@ -607,6 +642,7 @@ long _syscall(long num, long a, long b, long c, long d, long e) {
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_SETXATTR: _sys_setxattr(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 9c5b327..194ee49 100644
--- a/src/kernel/vfs/request.c
+++ b/src/kernel/vfs/request.c
@@ -174,6 +174,12 @@ vfsback_useraccept(VfsReq *req)
space -= len+1;
}
if (req->uin) {
+ if (space < req->uinlen && req->type == VFSOP_SETXATTR) {
+ /* don't truncate xattr values */
+ // TODO test
+ vfsreq_finish_short(req, -ERANGE);
+ return;
+ }
if (req->kin) {
/* save the address of the "second buffer" in id2,
* which should be free */
@@ -181,6 +187,9 @@ vfsback_useraccept(VfsReq *req)
res.id2 = buf;
}
+ /* intentionally overriding the prior len */
+ assert(len == 0 || req->type == VFSOP_SETXATTR);
+
len = min(req->uinlen, space);
len = pcpy_bi(handler, buf, req->caller, req->uin, len);
}
diff --git a/src/kernel/vfs/request.h b/src/kernel/vfs/request.h
index 484fdd7..fa62b35 100644
--- a/src/kernel/vfs/request.h
+++ b/src/kernel/vfs/request.h
@@ -45,7 +45,7 @@ struct VfsReq {
size_t kinlen;
/* user inputs and outputs - just point to some buffer in the caller */
- char __user *uin;
+ const char __user *uin;
size_t uinlen;
char __user *out;
size_t outlen;