summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/fs/initramfs.c1
-rw-r--r--sys/include/sys/fcntl.h5
-rw-r--r--sys/include/sys/filedesc.h2
-rw-r--r--sys/include/sys/syscall.h1
-rw-r--r--sys/include/sys/vfs.h1
-rw-r--r--sys/include/sys/vnode.h2
-rw-r--r--sys/kern/kern_descrip.c50
-rw-r--r--sys/kern/kern_syscall.c1
-rw-r--r--sys/kern/vfs_subr.c13
-rw-r--r--sys/kern/vfs_syscalls.c12
10 files changed, 81 insertions, 7 deletions
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 <sys/errno.h>
#include <sys/proc.h>
#include <sys/limits.h>
+#include <sys/fcntl.h>
#include <sys/namei.h>
#include <sys/filedesc.h>
#include <sys/systm.h>
@@ -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
@@ -167,6 +167,19 @@ vfs_vop_read(struct vnode *vp, struct sio_txn *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)
{
const struct vops *vops = vp->vops;
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
@@ -129,6 +129,18 @@ sys_read(struct syscall_args *scargs)
}
/*
+ * 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
*/