mirror of
https://github.com/torvalds/linux.git
synced 2024-11-16 00:52:01 +00:00
2949ad5071
File position is not controlled, it may lead to overwrites of arbitrary kernel memory. Also the code may kfree() the same pointer multiple times. One more flaw is still present: if multiple processes open the file then all 3 static variables are shared, leading to various race conditions. They should be moved to file->private_data. Signed-off-by: Vasiliy Kulikov <segoon@openwall.com> Reviewed-by: WANG Cong <xiyou.wangcong@gmail.com> Reviewed-by: Eugene Teo <eugeneteo@kernel.org> Cc: stable@kernel.org Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
103 lines
2.1 KiB
C
103 lines
2.1 KiB
C
/*
|
|
* debugfs.c - ACPI debugfs interface to userspace.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/debugfs.h>
|
|
#include <acpi/acpi_drivers.h>
|
|
|
|
#define _COMPONENT ACPI_SYSTEM_COMPONENT
|
|
ACPI_MODULE_NAME("debugfs");
|
|
|
|
|
|
/* /sys/modules/acpi/parameters/aml_debug_output */
|
|
|
|
module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object,
|
|
bool, 0644);
|
|
MODULE_PARM_DESC(aml_debug_output,
|
|
"To enable/disable the ACPI Debug Object output.");
|
|
|
|
/* /sys/kernel/debug/acpi/custom_method */
|
|
|
|
static ssize_t cm_write(struct file *file, const char __user * user_buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
static char *buf;
|
|
static u32 max_size;
|
|
static u32 uncopied_bytes;
|
|
|
|
struct acpi_table_header table;
|
|
acpi_status status;
|
|
|
|
if (!(*ppos)) {
|
|
/* parse the table header to get the table length */
|
|
if (count <= sizeof(struct acpi_table_header))
|
|
return -EINVAL;
|
|
if (copy_from_user(&table, user_buf,
|
|
sizeof(struct acpi_table_header)))
|
|
return -EFAULT;
|
|
uncopied_bytes = max_size = table.length;
|
|
buf = kzalloc(max_size, GFP_KERNEL);
|
|
if (!buf)
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (buf == NULL)
|
|
return -EINVAL;
|
|
|
|
if ((*ppos > max_size) ||
|
|
(*ppos + count > max_size) ||
|
|
(*ppos + count < count) ||
|
|
(count > uncopied_bytes))
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(buf + (*ppos), user_buf, count)) {
|
|
kfree(buf);
|
|
buf = NULL;
|
|
return -EFAULT;
|
|
}
|
|
|
|
uncopied_bytes -= count;
|
|
*ppos += count;
|
|
|
|
if (!uncopied_bytes) {
|
|
status = acpi_install_method(buf);
|
|
kfree(buf);
|
|
buf = NULL;
|
|
if (ACPI_FAILURE(status))
|
|
return -EINVAL;
|
|
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static const struct file_operations cm_fops = {
|
|
.write = cm_write,
|
|
.llseek = default_llseek,
|
|
};
|
|
|
|
int __init acpi_debugfs_init(void)
|
|
{
|
|
struct dentry *acpi_dir, *cm_dentry;
|
|
|
|
acpi_dir = debugfs_create_dir("acpi", NULL);
|
|
if (!acpi_dir)
|
|
goto err;
|
|
|
|
cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
|
|
acpi_dir, NULL, &cm_fops);
|
|
if (!cm_dentry)
|
|
goto err;
|
|
|
|
return 0;
|
|
|
|
err:
|
|
if (acpi_dir)
|
|
debugfs_remove(acpi_dir);
|
|
return -EINVAL;
|
|
}
|