diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/drivers/fb.c | 2 | ||||
-rw-r--r-- | kernel/features/fs.c | 8 | ||||
-rw-r--r-- | kernel/features/io.c | 4 | ||||
-rw-r--r-- | kernel/features/mm.c | 40 | ||||
-rw-r--r-- | kernel/features/proc.c | 12 | ||||
-rw-r--r-- | kernel/inc/fs.h | 6 | ||||
-rw-r--r-- | kernel/inc/mm.h | 8 |
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); |