summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKay Sievers <kay@vrfy.org>2013-05-21 10:00:42 +0200
committerKay Sievers <kay@vrfy.org>2013-05-21 10:00:42 +0200
commit3e87d31ad5fdd44cb3476b91ee55e7f74ffbbe45 (patch)
treeafb9cebc001ef11d84510bbec3f3dc79871ef317
parentd4a2a92b88e41afc7cf10113aa3c22156e1f5152 (diff)
downloadkdbus-bus-3e87d31ad5fdd44cb3476b91ee55e7f74ffbbe45.tar.gz
kdbus-bus-3e87d31ad5fdd44cb3476b91ee55e7f74ffbbe45.tar.bz2
kdbus-bus-3e87d31ad5fdd44cb3476b91ee55e7f74ffbbe45.zip
pool: accept only anonymous memory
-rw-r--r--connection.c10
-rw-r--r--pool.c30
-rw-r--r--pool.h2
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;
diff --git a/pool.c b/pool.c
index bf0711d9aa7..06e6f32b725 100644
--- a/pool.c
+++ b/pool.c
@@ -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) {
diff --git a/pool.h b/pool.h
index 096aa27fea5..8b52ede0c0c 100644
--- a/pool.h
+++ b/pool.h
@@ -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);