From d68537c1ca22d58f1c219d970d5aa462df9e0c6b Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 22 Feb 2025 02:18:33 -0500 Subject: kernel: vfs: Add support for write() Signed-off-by: Ian Moffett --- lib/libc/include/unistd.h | 1 + lib/libc/src/unistd/write.c | 38 ++++++++++++++++++++++++++++++++++ sys/fs/initramfs.c | 1 + sys/include/sys/fcntl.h | 5 +++++ sys/include/sys/filedesc.h | 2 ++ sys/include/sys/syscall.h | 1 + sys/include/sys/vfs.h | 1 + sys/include/sys/vnode.h | 2 ++ sys/kern/kern_descrip.c | 50 ++++++++++++++++++++++++++++++++++++++------- sys/kern/kern_syscall.c | 1 + sys/kern/vfs_subr.c | 13 ++++++++++++ sys/kern/vfs_syscalls.c | 12 +++++++++++ 12 files changed, 120 insertions(+), 7 deletions(-) create mode 100644 lib/libc/src/unistd/write.c diff --git a/lib/libc/include/unistd.h b/lib/libc/include/unistd.h index 50d6800..c487d38 100644 --- a/lib/libc/include/unistd.h +++ b/lib/libc/include/unistd.h @@ -36,6 +36,7 @@ __BEGIN_DECLS ssize_t read(int fd, void *buf, size_t count); +ssize_t write(int fd, const void *buf, size_t count); int close(int fd); __END_DECLS diff --git a/lib/libc/src/unistd/write.c b/lib/libc/src/unistd/write.c new file mode 100644 index 0000000..2672016 --- /dev/null +++ b/lib/libc/src/unistd/write.c @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +ssize_t +write(int fd, const void *buf, size_t count) +{ + return syscall(SYS_write, fd, (uintptr_t)buf, count); +} diff --git a/sys/fs/initramfs.c b/sys/fs/initramfs.c index acef462..fd746ef 100644 --- a/sys/fs/initramfs.c +++ b/sys/fs/initramfs.c @@ -275,6 +275,7 @@ initramfs_init(struct fs_info *fip) const struct vops g_initramfs_vops = { .lookup = initramfs_lookup, .read = initramfs_read, + .write = NULL, .reclaim = initramfs_reclaim, .getattr = initramfs_getattr }; diff --git a/sys/include/sys/fcntl.h b/sys/include/sys/fcntl.h index 7a62cdd..122a378 100644 --- a/sys/include/sys/fcntl.h +++ b/sys/include/sys/fcntl.h @@ -34,4 +34,9 @@ #define O_WRONLY 0x0001 #define O_RDWR 0x0002 +/* Makes seal checking easier */ +#if defined(_KERNEL) +#define O_ALLOW_WR (O_RDWR | O_WRONLY) +#endif + #endif /* !_SYS_FCTNL_H_ */ diff --git a/sys/include/sys/filedesc.h b/sys/include/sys/filedesc.h index 9a6230a..a544811 100644 --- a/sys/include/sys/filedesc.h +++ b/sys/include/sys/filedesc.h @@ -39,12 +39,14 @@ struct filedesc { off_t offset; bool is_dir; int refcnt; + int flags; struct vnode *vp; struct spinlock lock; }; int fd_close(unsigned int fd); int fd_read(unsigned int fd, void *buf, size_t count); +int fd_write(unsigned int fd, void *buf, size_t count); int fd_alloc(struct filedesc **fd_out); int fd_open(const char *pathname, int flags); diff --git a/sys/include/sys/syscall.h b/sys/include/sys/syscall.h index b724e8b..41d1e78 100644 --- a/sys/include/sys/syscall.h +++ b/sys/include/sys/syscall.h @@ -42,6 +42,7 @@ #define SYS_close 4 #define SYS_stat 5 #define SYS_sysctl 6 +#define SYS_write 7 #if defined(_KERNEL) /* Syscall return value and arg type */ diff --git a/sys/include/sys/vfs.h b/sys/include/sys/vfs.h index 61f6673..1ff722a 100644 --- a/sys/include/sys/vfs.h +++ b/sys/include/sys/vfs.h @@ -38,6 +38,7 @@ scret_t sys_open(struct syscall_args *scargs); scret_t sys_close(struct syscall_args *args); scret_t sys_read(struct syscall_args *scargs); +scret_t sys_write(struct syscall_args *sargs); scret_t sys_stat(struct syscall_args *scargs); #endif /* _KERNEL */ diff --git a/sys/include/sys/vnode.h b/sys/include/sys/vnode.h index 5cbaa15..33092f9 100644 --- a/sys/include/sys/vnode.h +++ b/sys/include/sys/vnode.h @@ -101,6 +101,7 @@ struct vops { int(*lookup)(struct vop_lookup_args *args); int(*getattr)(struct vop_getattr_args *args); int(*read)(struct vnode *vp, struct sio_txn *sio); + int(*write)(struct vnode *vp, struct sio_txn *sio); int(*reclaim)(struct vnode *vp); }; @@ -117,6 +118,7 @@ int vfs_release_vnode(struct vnode *vp); int vfs_vop_lookup(struct vnode *vp, struct vop_lookup_args *args); int vfs_vop_read(struct vnode *vp, struct sio_txn *sio); +int vfs_vop_write(struct vnode *vp, struct sio_txn *sio); int vfs_vop_getattr(struct vnode *vp, struct vop_getattr_args *args); #endif /* _KERNEL */ diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index d1ed044..201db3e 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -135,15 +136,16 @@ fd_close(unsigned int fd) } /* - * Read bytes from a file using a file + * Read/write bytes to/from a file using a file * descriptor number. * * @fd: File descriptor number. - * @buf: Buffer to read into. + * @buf: Buffer with data to read/write * @count: Number of bytes to read. + * @write: Set to 1 for writes */ -int -fd_read(unsigned int fd, void *buf, size_t count) +static int +fd_rw(unsigned int fd, void *buf, size_t count, uint8_t write) { char *kbuf = NULL; struct filedesc *filedes; @@ -173,13 +175,34 @@ fd_read(unsigned int fd, void *buf, size_t count) goto done; } + /* Check if this violates the file seal */ + if (!ISSET(filedes->flags, O_ALLOW_WR) && write) { + return -EPERM; + } else if (ISSET(O_RDONLY, filedes->flags) && write) { + return -EPERM; + } + sio.len = count; sio.buf = kbuf; sio.offset = filedes->offset; - if ((count = vfs_vop_read(filedes->vp, &sio)) < 0) { - retval = -EIO; - goto done; + if (write) { + /* Copy in user buffer */ + if (copyin(buf, kbuf, count) < 0) { + retval = -EFAULT; + goto done; + } + + /* Call VFS write hook */ + if ((count = vfs_vop_write(filedes->vp, &sio)) < 0) { + retval = -EIO; + goto done; + } + } else { + if ((count = vfs_vop_read(filedes->vp, &sio)) < 0) { + retval = -EIO; + goto done; + } } if (copyout(kbuf, buf, count) < 0) { @@ -195,6 +218,18 @@ done: return retval; } +int +fd_read(unsigned int fd, void *buf, size_t count) +{ + return fd_rw(fd, buf, count, 0); +} + +int +fd_write(unsigned int fd, void *buf, size_t count) +{ + return fd_rw(fd, buf, count, 1); +} + /* * Open a file and get a file descriptor * number. @@ -224,6 +259,7 @@ fd_open(const char *pathname, int flags) } filedes->vp = nd.vp; + filedes->flags = flags; return filedes->fdno; } diff --git a/sys/kern/kern_syscall.c b/sys/kern/kern_syscall.c index 1d961a7..986d82a 100644 --- a/sys/kern/kern_syscall.c +++ b/sys/kern/kern_syscall.c @@ -41,6 +41,7 @@ scret_t(*g_sctab[])(struct syscall_args *) = { sys_close, /* SYS_close */ sys_stat, /* SYS_stat */ sys_sysctl, /* SYS_sysctl */ + sys_write, /* SYS_write */ }; const size_t MAX_SYSCALLS = NELEM(g_sctab); diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index f67bcfe..da0a4f9 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -166,6 +166,19 @@ vfs_vop_read(struct vnode *vp, struct sio_txn *sio) return vops->read(vp, sio); } +int +vfs_vop_write(struct vnode *vp, struct sio_txn *sio) +{ + const struct vops *vops = vp->vops; + + if (vops == NULL) + return -EIO; + if (vops->write == NULL) + return -EIO; + + return vops->write(vp, sio); +} + int vfs_vop_getattr(struct vnode *vp, struct vop_getattr_args *args) { diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index fa613c2..6f2d683 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -128,6 +128,18 @@ sys_read(struct syscall_args *scargs) scargs->arg2); } +/* + * arg0: fd + * arg1: buf + * arg2: count + */ +scret_t +sys_write(struct syscall_args *scargs) +{ + return fd_write(scargs->arg0, (void *)scargs->arg1, + scargs->arg2); +} + /* * arg0: path * arg1: buf -- cgit v1.2.3