From 3cb36b632a79c2f5e1372516fc519a6f8016c6cc Mon Sep 17 00:00:00 2001 From: Bahadir Balban Date: Fri, 7 Nov 2008 12:32:10 +0200 Subject: [PATCH] Fixed various bugs in user buffer validation/mapping and mmap() syscall path. --- tasks/libposix/mmap.c | 2 +- tasks/mm0/main.c | 1 + tasks/mm0/src/file.c | 4 ++-- tasks/mm0/src/mmap.c | 31 +++++++++++++------------------ tasks/mm0/src/user.c | 2 +- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/tasks/libposix/mmap.c b/tasks/libposix/mmap.c index 4b4ca0a..5c4c10e 100644 --- a/tasks/libposix/mmap.c +++ b/tasks/libposix/mmap.c @@ -61,7 +61,7 @@ void *mmap2(void *start, size_t length, int prot, int flags, int fd, off_t pgoff errno = -(int)ret; return MAP_FAILED; } - return 0; + return ret; } diff --git a/tasks/mm0/main.c b/tasks/mm0/main.c index 96c34fd..1146845 100644 --- a/tasks/mm0/main.c +++ b/tasks/mm0/main.c @@ -111,6 +111,7 @@ void handle_requests(void) case L4_IPC_TAG_MMAP: { struct sys_mmap_args *args = (struct sys_mmap_args *)mr[0]; ret = (int)sys_mmap(sender, args); + break; } case L4_IPC_TAG_MUNMAP: { ret = sys_munmap(sender, (void *)mr[0], (unsigned long)mr[1]); diff --git a/tasks/mm0/src/file.c b/tasks/mm0/src/file.c index a8dcac9..4e253b9 100644 --- a/tasks/mm0/src/file.c +++ b/tasks/mm0/src/file.c @@ -615,7 +615,7 @@ int sys_read(struct tcb *task, int fd, void *buf, int count) /* Check user buffer validity. */ if ((ret = pager_validate_user_range(task, buf, - (unsigned long)(buf + count), + (unsigned long)count, VM_READ)) < 0) return -EFAULT; @@ -685,7 +685,7 @@ int sys_write(struct tcb *task, int fd, void *buf, int count) /* Check user buffer validity. */ if ((ret = pager_validate_user_range(task, buf, - (unsigned long)(buf + count), + (unsigned long)count, VM_WRITE | VM_READ)) < 0) return -EINVAL; diff --git a/tasks/mm0/src/mmap.c b/tasks/mm0/src/mmap.c index 3eeaae1..3cece38 100644 --- a/tasks/mm0/src/mmap.c +++ b/tasks/mm0/src/mmap.c @@ -193,7 +193,9 @@ void *do_mmap(struct vm_file *mapfile, unsigned long file_offset, /* Check invalid map address */ if (!mmap_address_validate(task, map_address, flags)) { - if (!(map_address = mmap_new_address(task, flags, npages))) + if (flags & VMA_FIXED) + return PTR_ERR(-EINVAL); + else if (!(map_address = mmap_new_address(task, flags, npages))) return PTR_ERR(-ENOMEM); } else { /* @@ -262,31 +264,22 @@ void *do_mmap(struct vm_file *mapfile, unsigned long file_offset, /* mmap system call implementation */ void *__sys_mmap(struct tcb *task, void *start, size_t length, int prot, - int flags, int fd, unsigned long pfn) + int flags, int fd, unsigned long file_offset) { - unsigned long npages = __pfn(page_align_up(length)); - unsigned long base = (unsigned long)start; - struct vm_file *file = 0; unsigned int vmflags = 0; + struct vm_file *file = 0; int err; - /* Check fd validity */ + /* Check file validity */ if (!(flags & MAP_ANONYMOUS)) if (!task->files->fd[fd].vmfile) if ((err = file_open(task, fd)) < 0) return PTR_ERR(err); - if (base < task->start || base >= task->end) + /* Check file offset is page aligned */ + if (!is_page_aligned(file_offset)) return PTR_ERR(-EINVAL); - /* Exclude task's stack, text and data from mmappable area in task's space */ - if (base < task->map_start || base >= task->map_end || !base) { - if (flags & MAP_FIXED) /* Its fixed, we cannot satisfy it */ - return PTR_ERR(-EINVAL); - else - start = 0; - } - /* TODO: * Check that @start does not already have a mapping. * Check that pfn + npages range is within the file range. @@ -318,7 +311,8 @@ void *__sys_mmap(struct tcb *task, void *start, size_t length, int prot, if (prot & PROT_EXEC) vmflags |= VM_EXEC; - return do_mmap(file, __pfn_to_addr(pfn), task, base, vmflags, npages); + return do_mmap(file, file_offset, task, (unsigned long)start, + vmflags, __pfn(page_align_up(length))); } void *sys_mmap(struct tcb *task, struct sys_mmap_args *args) @@ -332,8 +326,9 @@ void *sys_mmap(struct tcb *task, struct sys_mmap_args *args) VM_READ | VM_WRITE))) return PTR_ERR(-EINVAL); - ret = __sys_mmap(task, args->start, args->length, args->prot, - args->flags, args->fd, args->offset); + ret = __sys_mmap(task, mapped_args->start, mapped_args->length, + mapped_args->prot, mapped_args->flags, mapped_args->fd, + mapped_args->offset); pager_unmap_user_range(mapped_args, sizeof(*args)); diff --git a/tasks/mm0/src/user.c b/tasks/mm0/src/user.c index 18addea..3809baf 100644 --- a/tasks/mm0/src/user.c +++ b/tasks/mm0/src/user.c @@ -68,6 +68,6 @@ void *pager_validate_map_user_range(struct tcb *user, void *userptr, void pager_unmap_user_range(void *mapped_ptr, unsigned long size) { l4_unmap_helper((void *)page_align(mapped_ptr), - __pfn(page_align(mapped_ptr) + page_align_up(size))); + __pfn(page_align_up(size))); }