Contributors: 3
Author |
Tokens |
Token Proportion |
Commits |
Commit Proportion |
Laura Abbott |
334 |
96.81% |
4 |
57.14% |
Benjamin Gaignard |
9 |
2.61% |
1 |
14.29% |
Greg Kroah-Hartman |
2 |
0.58% |
2 |
28.57% |
Total |
345 |
|
7 |
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2011 Google, Inc.
*/
#include <linux/kernel.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include "ion.h"
union ion_ioctl_arg {
struct ion_allocation_data allocation;
struct ion_heap_query query;
};
static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg)
{
switch (cmd) {
case ION_IOC_HEAP_QUERY:
if (arg->query.reserved0 ||
arg->query.reserved1 ||
arg->query.reserved2)
return -EINVAL;
break;
default:
break;
}
return 0;
}
/* fix up the cases where the ioctl direction bits are incorrect */
static unsigned int ion_ioctl_dir(unsigned int cmd)
{
switch (cmd) {
default:
return _IOC_DIR(cmd);
}
}
long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret = 0;
unsigned int dir;
union ion_ioctl_arg data;
dir = ion_ioctl_dir(cmd);
if (_IOC_SIZE(cmd) > sizeof(data))
return -EINVAL;
/*
* The copy_from_user is unconditional here for both read and write
* to do the validate. If there is no write for the ioctl, the
* buffer is cleared
*/
if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))
return -EFAULT;
ret = validate_ioctl_arg(cmd, &data);
if (ret) {
pr_warn_once("%s: ioctl validate failed\n", __func__);
return ret;
}
if (!(dir & _IOC_WRITE))
memset(&data, 0, sizeof(data));
switch (cmd) {
case ION_IOC_ALLOC:
{
int fd;
fd = ion_alloc(data.allocation.len,
data.allocation.heap_id_mask,
data.allocation.flags);
if (fd < 0)
return fd;
data.allocation.fd = fd;
break;
}
case ION_IOC_HEAP_QUERY:
ret = ion_query_heaps(&data.query);
break;
default:
return -ENOTTY;
}
if (dir & _IOC_READ) {
if (copy_to_user((void __user *)arg, &data, _IOC_SIZE(cmd)))
return -EFAULT;
}
return ret;
}