Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 252769
b: refs/heads/master
c: 526b4af
h: refs/heads/master
i:
  252767: f0a1106
v: v3
  • Loading branch information
Thomas Renninger authored and Len Brown committed May 29, 2011
1 parent 7148d32 commit 251f09c
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 80 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: aecad432fd68dafa5b3b497c4816fbfce6fd4066
refs/heads/master: 526b4af47f44148c9d665e57723ed9f86634c6e3
5 changes: 5 additions & 0 deletions trunk/Documentation/acpi/method-customizing.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ Note: We can use a kernel with multiple custom ACPI method running,
But each individual write to debugfs can implement a SINGLE
method override. i.e. if we want to insert/override multiple
ACPI methods, we need to redo step c) ~ g) for multiple times.

Note: Be aware that root can mis-use this driver to modify arbitrary
memory and gain additional rights, if root's privileges got
restricted (for example if root is not allowed to load additional
modules after boot).
15 changes: 15 additions & 0 deletions trunk/drivers/acpi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,21 @@ config ACPI_HED
which is used to report some hardware errors notified via
SCI, mainly the corrected errors.

config ACPI_CUSTOM_METHOD
tristate "Allow ACPI methods to be inserted/replaced at run time"
depends on DEBUG_FS
default n
help
This debug facility allows ACPI AML methods to me inserted and/or
replaced without rebooting the system. For details refer to:
Documentation/acpi/method-customizing.txt.

NOTE: This option is security sensitive, because it allows arbitrary
kernel memory to be written to by root (uid=0) users, allowing them
to bypass certain security measures (e.g. if root is not allowed to
load additional kernel modules after boot, this feature may be used
to override that restriction).

source "drivers/acpi/apei/Kconfig"

endif # ACPI
1 change: 1 addition & 0 deletions trunk/drivers/acpi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ obj-$(CONFIG_ACPI_SBS) += sbs.o
obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
obj-$(CONFIG_ACPI_HED) += hed.o
obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o

# processor has its own "processor." module_param namespace
processor-y := processor_driver.o processor_throttling.o
Expand Down
100 changes: 100 additions & 0 deletions trunk/drivers/acpi/custom_method.c
Original file line number Diff line number Diff line change
@@ -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);
80 changes: 1 addition & 79 deletions trunk/drivers/acpi/debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,94 +3,16 @@
*/

#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");

struct dentry *acpi_debugfs_dir;
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)
return -ENOENT;

cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
acpi_debugfs_dir, NULL, &cm_fops);
if (!cm_dentry)
return -ENODEV;

return 0;
}
EXPORT_SYMBOL_GPL(acpi_debugfs_dir);

void __init acpi_debugfs_init(void)
{
acpi_debugfs_dir = debugfs_create_dir("acpi", NULL);

acpi_custom_method_init();
}

0 comments on commit 251f09c

Please sign in to comment.