diff options
author | Kay Sievers <kay@vrfy.org> | 2013-05-21 10:00:42 +0200 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2013-05-21 10:00:42 +0200 |
commit | 3e87d31ad5fdd44cb3476b91ee55e7f74ffbbe45 (patch) | |
tree | afb9cebc001ef11d84510bbec3f3dc79871ef317 | |
parent | d4a2a92b88e41afc7cf10113aa3c22156e1f5152 (diff) | |
download | kdbus-bus-3e87d31ad5fdd44cb3476b91ee55e7f74ffbbe45.tar.gz kdbus-bus-3e87d31ad5fdd44cb3476b91ee55e7f74ffbbe45.tar.bz2 kdbus-bus-3e87d31ad5fdd44cb3476b91ee55e7f74ffbbe45.zip |
pool: accept only anonymous memory
-rw-r--r-- | connection.c | 10 | ||||
-rw-r--r-- | pool.c | 30 | ||||
-rw-r--r-- | pool.h | 2 |
3 files changed, 36 insertions, 6 deletions
diff --git a/connection.c b/connection.c index fc57df0bad4..12136935917 100644 --- a/connection.c +++ b/connection.c @@ -859,8 +859,6 @@ static int kdbus_conn_open(struct inode *inode, struct file *file) INIT_LIST_HEAD(&conn->connection_entry); INIT_LIST_HEAD(&conn->monitor_entry); - file->private_data = conn; - INIT_WORK(&conn->work, kdbus_conn_work); init_timer(&conn->timer); @@ -1191,7 +1189,7 @@ static long kdbus_conn_ioctl_ep(struct file *file, unsigned int cmd, break; } - /* enforce page alignment and page granularity */ + /* enforce page alignment */ if (!IS_ALIGNED(item->vec.address, PAGE_SIZE) || !IS_ALIGNED(item->vec.size, PAGE_SIZE)) { ret = -EFAULT; @@ -1199,6 +1197,12 @@ static long kdbus_conn_ioctl_ep(struct file *file, unsigned int cmd, } p = KDBUS_PTR(item->vec.address); + if (!kdbus_pool_is_anon_map(current->mm, p, + item->vec.size)) { + ret = -EFAULT; + break; + } + ret = kdbus_pool_init(&conn->pool, p, item->vec.size); break; @@ -302,6 +302,25 @@ void kdbus_pool_slice_unmap(struct kdbus_slice *slice) slice->pg = NULL; } +bool kdbus_pool_is_anon_map(struct mm_struct *mm, + void __user *buf, size_t size) +{ + unsigned long addr = (unsigned long) buf; + struct vm_area_struct *vma; + + vma = find_vma(mm, addr); + if (!vma) + return false; + + if (vma->vm_file) + return false; + + if (addr + size > vma->vm_end) + return false; + + return true; +} + /* pin the receiver's memory range/pages */ int kdbus_pool_slice_map(struct kdbus_slice *slice, struct task_struct *task) { @@ -323,17 +342,22 @@ int kdbus_pool_slice_map(struct kdbus_slice *slice, struct task_struct *task) base = addr & PAGE_MASK; slice->pg_off = addr - base; - /* pin the receiver's pool page(s); the task + /* pin the receiver's pool page(s) we will write to; the task * is pinned as long as the connection is open */ mm = get_task_mm(task); if (!mm) { kdbus_pool_slice_unmap(slice); return -ESHUTDOWN; } + down_read(&mm->mmap_sem); - have = get_user_pages(task, mm, base, n, - true, false, slice->pg, NULL); + if (kdbus_pool_is_anon_map(mm, slice->buf, slice->size)) + have = get_user_pages(task, mm, base, n, true, false, + slice->pg, NULL); + else + have = -EFAULT; up_read(&mm->mmap_sem); + mmput(mm); if (have < 0) { @@ -62,6 +62,8 @@ struct kdbus_slice { int kdbus_pool_init(struct kdbus_pool *pool, void __user *buf, size_t size); void kdbus_pool_cleanup(struct kdbus_pool *pool); +bool kdbus_pool_is_anon_map(struct mm_struct *mm, + void __user *buf, size_t size); void __user *kdbus_pool_alloc(struct kdbus_pool *pool, size_t size, struct kdbus_slice **slice); |