diff options
author | Thomas Renninger <trenn@suse.de> | 2011-05-26 12:26:24 +0200 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2011-05-29 01:50:40 -0400 |
commit | 526b4af47f44148c9d665e57723ed9f86634c6e3 (patch) | |
tree | 7906a3b45703aa730d5e7ebadc36a55aee5417ca /drivers/acpi/custom_method.c | |
parent | aecad432fd68dafa5b3b497c4816fbfce6fd4066 (diff) |
ACPI: Split out custom_method functionality into an own driver
With /sys/kernel/debug/acpi/custom_method root can write
to arbitrary memory and increase his priveleges, even if
these are restricted.
-> Make this an own debug .config option and warn about the
security issue in the config description.
-> Still keep acpi/debugfs.c which now only creates an empty
/sys/kernel/debug/acpi directory. There might be other
users of it later.
Signed-off-by: Thomas Renninger <trenn@suse.de>
Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-by: rui.zhang@intel.com
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/custom_method.c')
-rw-r--r-- | drivers/acpi/custom_method.c | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c new file mode 100644 index 00000000000..5d42c2414ae --- /dev/null +++ b/drivers/acpi/custom_method.c @@ -0,0 +1,100 @@ +/* + * 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> + +#include "internal.h" + +#define _COMPONENT ACPI_SYSTEM_COMPONENT +ACPI_MODULE_NAME("custom_method"); +MODULE_LICENSE("GPL"); + +static struct dentry *cm_dentry; + +/* /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, +}; + +static int __init acpi_custom_method_init(void) +{ + if (acpi_debugfs_dir == NULL) + return -ENOENT; + + cm_dentry = debugfs_create_file("custom_method", S_IWUSR, + acpi_debugfs_dir, NULL, &cm_fops); + if (cm_dentry == NULL) + return -ENODEV; + + return 0; +} + +static void __exit acpi_custom_method_exit(void) +{ + if (cm_dentry) + debugfs_remove(cm_dentry); + } + +module_init(acpi_custom_method_init); +module_exit(acpi_custom_method_exit); |