aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/drivers/fb.c2
-rw-r--r--kernel/features/fs.c8
-rw-r--r--kernel/features/io.c4
-rw-r--r--kernel/features/mm.c40
-rw-r--r--kernel/features/proc.c12
-rw-r--r--kernel/inc/fs.h6
-rw-r--r--kernel/inc/mm.h8
7 files changed, 45 insertions, 35 deletions
diff --git a/kernel/drivers/fb.c b/kernel/drivers/fb.c
index fce0c9e..f62c486 100644
--- a/kernel/drivers/fb.c
+++ b/kernel/drivers/fb.c
@@ -34,7 +34,7 @@ static res fb_ioctl(u32 request, void *arg1, void *arg2, void *arg3)
if (!info)
return -ENOENT;
- if (!memory_writable(arg1))
+ if (!memory_writable_range(memory_range(arg1, sizeof(struct vbe_basic))))
return -EFAULT;
if (fb_owner != 0 && proc_from_pid(fb_owner))
diff --git a/kernel/features/fs.c b/kernel/features/fs.c
index 34c70e8..6cb10c8 100644
--- a/kernel/features/fs.c
+++ b/kernel/features/fs.c
@@ -147,7 +147,7 @@ res vfs_read(const char *path, void *buf, u32 offset, u32 count)
if (!memory_readable(path))
return -EFAULT;
- if (!memory_writable(buf))
+ if (!memory_writable_range(memory_range(buf, count)))
return -EFAULT;
struct mount_info *m = vfs_find_mount_info(path);
@@ -170,12 +170,12 @@ res vfs_read(const char *path, void *buf, u32 offset, u32 count)
return m->dev->vfs->read(path, buf, offset, count, m->dev);
}
-res vfs_write(const char *path, void *buf, u32 offset, u32 count)
+res vfs_write(const char *path, const void *buf, u32 offset, u32 count)
{
if (!memory_readable(path))
return -EFAULT;
- if (!memory_writable(buf))
+ if (!memory_readable_range(memory_range(buf, count)))
return -EFAULT;
struct mount_info *m = vfs_find_mount_info(path);
@@ -203,7 +203,7 @@ res vfs_stat(const char *path, struct stat *buf)
if (!memory_readable(path))
return -EFAULT;
- if (!memory_writable(buf))
+ if (!memory_writable_range(memory_range(buf, sizeof(*buf))))
return -EFAULT;
struct mount_info *m = vfs_find_mount_info(path);
diff --git a/kernel/features/io.c b/kernel/features/io.c
index fbae5cf..d4737bf 100644
--- a/kernel/features/io.c
+++ b/kernel/features/io.c
@@ -120,7 +120,7 @@ res io_control(enum io_type io, u32 request, void *arg1, void *arg2, void *arg3)
res io_write(enum io_type io, const void *buf, u32 offset, u32 count)
{
- if (!memory_readable(buf))
+ if (!memory_readable_range(memory_range(buf, count)))
return -EFAULT;
struct io_dev *dev;
@@ -132,7 +132,7 @@ res io_write(enum io_type io, const void *buf, u32 offset, u32 count)
res io_read(enum io_type io, void *buf, u32 offset, u32 count)
{
- if (!memory_readable(buf))
+ if (!memory_writable_range(memory_range(buf, count)))
return -EFAULT;
struct io_dev *dev;
diff --git a/kernel/features/mm.c b/kernel/features/mm.c
index 4ed3ab9..a3812bd 100644
--- a/kernel/features/mm.c
+++ b/kernel/features/mm.c
@@ -608,28 +608,48 @@ u8 memory_is_user(const void *addr)
return PDI((u32)addr) >= PAGE_KERNEL_COUNT;
}
-u8 memory_readable(const void *addr)
+u8 memory_readable_range(struct memory_range vrange)
{
- if (!addr)
+ if (!vrange.base)
return 0;
struct proc *proc = proc_current();
- if (proc && !memory_bypass_validity)
- return memory_is_user(addr) && virtual_user_readable(proc->page_dir, (u32)addr);
- else
+ if (memory_bypass_validity || !proc)
return 1;
+
+ u32 offset = 0;
+ do {
+ u8 valid = memory_is_user((void *)(vrange.base + offset)) &&
+ virtual_user_readable(proc->page_dir, vrange.base + offset);
+ if (!valid)
+ return 0;
+
+ offset += PAGE_SIZE;
+ } while (offset < vrange.size);
+
+ return 1;
}
-u8 memory_writable(const void *addr)
+u8 memory_writable_range(struct memory_range vrange)
{
- if (!addr)
+ if (!vrange.base)
return 0;
struct proc *proc = proc_current();
- if (proc && !memory_bypass_validity)
- return memory_is_user(addr) && virtual_user_writable(proc->page_dir, (u32)addr);
- else
+ if (memory_bypass_validity || !proc)
return 1;
+
+ u32 offset = 0;
+ do {
+ u8 valid = memory_is_user((void *)(vrange.base + offset)) &&
+ virtual_user_writable(proc->page_dir, vrange.base + offset);
+ if (!valid)
+ return 0;
+
+ offset += PAGE_SIZE;
+ } while (offset < vrange.size);
+
+ return 1;
}
struct memory_range memory_range_from(u32 base, u32 size)
diff --git a/kernel/features/proc.c b/kernel/features/proc.c
index 4cf4005..b47df0b 100644
--- a/kernel/features/proc.c
+++ b/kernel/features/proc.c
@@ -256,17 +256,6 @@ struct procfs_message {
u32 size;
};
-static res procfs_write(const char *path, void *buf, u32 offset, u32 count, struct vfs_dev *dev)
-{
- UNUSED(path);
- UNUSED(buf);
- UNUSED(offset);
- UNUSED(count);
- UNUSED(dev);
-
- return -ENOENT;
-}
-
static res procfs_read(const char *path, void *buf, u32 offset, u32 count, struct vfs_dev *dev)
{
(void)dev;
@@ -331,7 +320,6 @@ NORETURN void proc_init(void)
struct vfs *vfs = zalloc(sizeof(*vfs));
vfs->type = VFS_PROCFS;
vfs->read = procfs_read;
- vfs->write = procfs_write;
vfs->perm = procfs_perm;
vfs->data = NULL;
struct vfs_dev *dev = zalloc(sizeof(*dev));
diff --git a/kernel/inc/fs.h b/kernel/inc/fs.h
index 8dbf028..329af21 100644
--- a/kernel/inc/fs.h
+++ b/kernel/inc/fs.h
@@ -20,7 +20,7 @@ struct vfs_dev {
struct vfs *vfs;
void *data;
res (*read)(void *buf, u32 offset, u32 count, struct vfs_dev *dev) NONNULL;
- res (*write)(void *buf, u32 offset, u32 count, struct vfs_dev *dev) NONNULL;
+ res (*write)(const void *buf, u32 offset, u32 count, struct vfs_dev *dev) NONNULL;
res (*ioctl)(u32 request, void *arg1, void *arg2, void *arg3, struct vfs_dev *dev)
ATTR((nonnull(5)));
};
@@ -38,7 +38,7 @@ struct vfs {
void *data;
res (*read)(const char *path, void *buf, u32 offset, u32 count,
struct vfs_dev *dev) NONNULL;
- res (*write)(const char *path, void *buf, u32 offset, u32 count,
+ res (*write)(const char *path, const void *buf, u32 offset, u32 count,
struct vfs_dev *dev) NONNULL;
res (*ioctl)(const char *path, u32 request, void *arg1, void *arg2, void *arg3,
struct vfs_dev *dev) ATTR((nonnull(1, 6)));
@@ -62,7 +62,7 @@ void vfs_add_dev(struct vfs_dev *dev) NONNULL;
// No NONNULL on syscalls
res vfs_read(const char *path, void *buf, u32 offset, u32 count);
-res vfs_write(const char *path, void *buf, u32 offset, u32 count);
+res vfs_write(const char *path, const void *buf, u32 offset, u32 count);
res vfs_stat(const char *path, struct stat *buf);
struct vfs_dev *device_get_by_name(const char *name) NONNULL;
diff --git a/kernel/inc/mm.h b/kernel/inc/mm.h
index dc28a8d..e912fec 100644
--- a/kernel/inc/mm.h
+++ b/kernel/inc/mm.h
@@ -116,7 +116,7 @@ struct memory_proc_link {
#define MEMORY_USER (1 << 0)
#define MEMORY_CLEAR (1 << 1)
#define MEMORY_READONLY (1 << 2)
-#define memory_range(base, size) ((struct memory_range){ (base), (size) })
+#define memory_range(base, size) ((struct memory_range){ (u32)(base), (size) })
struct memory_range memory_range_from(u32 base, u32 size);
struct memory_range memory_range_around(u32 base, u32 size);
@@ -135,8 +135,10 @@ void memory_bypass_disable(void);
// No NONNULL on verification (for syscalls etc)
u8 memory_is_user(const void *addr);
-u8 memory_readable(const void *addr);
-u8 memory_writable(const void *addr);
+u8 memory_readable_range(struct memory_range vrange);
+u8 memory_writable_range(struct memory_range vrange);
+#define memory_readable(addr) memory_readable_range(memory_range((addr), 1))
+#define memory_writable(addr) memory_writable_range(memory_range((addr), 1))
// User interface - No NONNULL on syscalls
res memory_sys_alloc(struct page_dir *dir, u32 size, u32 *addr, u32 *id, u8 shared);