aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Renninger <trenn@suse.de>2011-05-26 06:26:24 -0400
committerLen Brown <len.brown@intel.com>2011-05-29 01:50:40 -0400
commit526b4af47f44148c9d665e57723ed9f86634c6e3 (patch)
tree7906a3b45703aa730d5e7ebadc36a55aee5417ca
parentaecad432fd68dafa5b3b497c4816fbfce6fd4066 (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>
-rw-r--r--Documentation/acpi/method-customizing.txt5
-rw-r--r--drivers/acpi/Kconfig15
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/custom_method.c100
-rw-r--r--drivers/acpi/debugfs.c80
5 files changed, 122 insertions, 79 deletions
diff --git a/Documentation/acpi/method-customizing.txt b/Documentation/acpi/method-customizing.txt
index 3e1d25aee3fb..5f55373dd53b 100644
--- a/Documentation/acpi/method-customizing.txt
+++ b/Documentation/acpi/method-customizing.txt
@@ -66,3 +66,8 @@ Note: We can use a kernel with multiple custom ACPI method running,
66 But each individual write to debugfs can implement a SINGLE 66 But each individual write to debugfs can implement a SINGLE
67 method override. i.e. if we want to insert/override multiple 67 method override. i.e. if we want to insert/override multiple
68 ACPI methods, we need to redo step c) ~ g) for multiple times. 68 ACPI methods, we need to redo step c) ~ g) for multiple times.
69
70Note: Be aware that root can mis-use this driver to modify arbitrary
71 memory and gain additional rights, if root's privileges got
72 restricted (for example if root is not allowed to load additional
73 modules after boot).
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 3a17ca5fff6f..d918e130bef3 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -380,6 +380,21 @@ config ACPI_HED
380 which is used to report some hardware errors notified via 380 which is used to report some hardware errors notified via
381 SCI, mainly the corrected errors. 381 SCI, mainly the corrected errors.
382 382
383config ACPI_CUSTOM_METHOD
384 tristate "Allow ACPI methods to be inserted/replaced at run time"
385 depends on DEBUG_FS
386 default n
387 help
388 This debug facility allows ACPI AML methods to me inserted and/or
389 replaced without rebooting the system. For details refer to:
390 Documentation/acpi/method-customizing.txt.
391
392 NOTE: This option is security sensitive, because it allows arbitrary
393 kernel memory to be written to by root (uid=0) users, allowing them
394 to bypass certain security measures (e.g. if root is not allowed to
395 load additional kernel modules after boot, this feature may be used
396 to override that restriction).
397
383source "drivers/acpi/apei/Kconfig" 398source "drivers/acpi/apei/Kconfig"
384 399
385endif # ACPI 400endif # ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index d113fa5100b2..cba0b2334b9b 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -62,6 +62,7 @@ obj-$(CONFIG_ACPI_SBS) += sbs.o
62obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o 62obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o
63obj-$(CONFIG_ACPI_HED) += hed.o 63obj-$(CONFIG_ACPI_HED) += hed.o
64obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o 64obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
65obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
65 66
66# processor has its own "processor." module_param namespace 67# processor has its own "processor." module_param namespace
67processor-y := processor_driver.o processor_throttling.o 68processor-y := processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c
new file mode 100644
index 000000000000..5d42c2414ae5
--- /dev/null
+++ b/drivers/acpi/custom_method.c
@@ -0,0 +1,100 @@
1/*
2 * debugfs.c - ACPI debugfs interface to userspace.
3 */
4
5#include <linux/init.h>
6#include <linux/module.h>
7#include <linux/kernel.h>
8#include <linux/uaccess.h>
9#include <linux/debugfs.h>
10#include <acpi/acpi_drivers.h>
11
12#include "internal.h"
13
14#define _COMPONENT ACPI_SYSTEM_COMPONENT
15ACPI_MODULE_NAME("custom_method");
16MODULE_LICENSE("GPL");
17
18static struct dentry *cm_dentry;
19
20/* /sys/kernel/debug/acpi/custom_method */
21
22static ssize_t cm_write(struct file *file, const char __user * user_buf,
23 size_t count, loff_t *ppos)
24{
25 static char *buf;
26 static u32 max_size;
27 static u32 uncopied_bytes;
28
29 struct acpi_table_header table;
30 acpi_status status;
31
32 if (!(*ppos)) {
33 /* parse the table header to get the table length */
34 if (count <= sizeof(struct acpi_table_header))
35 return -EINVAL;
36 if (copy_from_user(&table, user_buf,
37 sizeof(struct acpi_table_header)))
38 return -EFAULT;
39 uncopied_bytes = max_size = table.length;
40 buf = kzalloc(max_size, GFP_KERNEL);
41 if (!buf)
42 return -ENOMEM;
43 }
44
45 if (buf == NULL)
46 return -EINVAL;
47
48 if ((*ppos > max_size) ||
49 (*ppos + count > max_size) ||
50 (*ppos + count < count) ||
51 (count > uncopied_bytes))
52 return -EINVAL;
53
54 if (copy_from_user(buf + (*ppos), user_buf, count)) {
55 kfree(buf);
56 buf = NULL;
57 return -EFAULT;
58 }
59
60 uncopied_bytes -= count;
61 *ppos += count;
62
63 if (!uncopied_bytes) {
64 status = acpi_install_method(buf);
65 kfree(buf);
66 buf = NULL;
67 if (ACPI_FAILURE(status))
68 return -EINVAL;
69 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
70 }
71
72 return count;
73}
74
75static const struct file_operations cm_fops = {
76 .write = cm_write,
77 .llseek = default_llseek,
78};
79
80static int __init acpi_custom_method_init(void)
81{
82 if (acpi_debugfs_dir == NULL)
83 return -ENOENT;
84
85 cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
86 acpi_debugfs_dir, NULL, &cm_fops);
87 if (cm_dentry == NULL)
88 return -ENODEV;
89
90 return 0;
91}
92
93static void __exit acpi_custom_method_exit(void)
94{
95 if (cm_dentry)
96 debugfs_remove(cm_dentry);
97 }
98
99module_init(acpi_custom_method_init);
100module_exit(acpi_custom_method_exit);
diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c
index e7abc6e3bba0..182a9fc36355 100644
--- a/drivers/acpi/debugfs.c
+++ b/drivers/acpi/debugfs.c
@@ -3,9 +3,6 @@
3 */ 3 */
4 4
5#include <linux/init.h> 5#include <linux/init.h>
6#include <linux/module.h>
7#include <linux/kernel.h>
8#include <linux/uaccess.h>
9#include <linux/debugfs.h> 6#include <linux/debugfs.h>
10#include <acpi/acpi_drivers.h> 7#include <acpi/acpi_drivers.h>
11 8
@@ -13,84 +10,9 @@
13ACPI_MODULE_NAME("debugfs"); 10ACPI_MODULE_NAME("debugfs");
14 11
15struct dentry *acpi_debugfs_dir; 12struct dentry *acpi_debugfs_dir;
16static struct dentry *cm_dentry; 13EXPORT_SYMBOL_GPL(acpi_debugfs_dir);
17
18/* /sys/kernel/debug/acpi/custom_method */
19
20static ssize_t cm_write(struct file *file, const char __user * user_buf,
21 size_t count, loff_t *ppos)
22{
23 static char *buf;
24 static u32 max_size;
25 static u32 uncopied_bytes;
26
27 struct acpi_table_header table;
28 acpi_status status;
29
30 if (!(*ppos)) {
31 /* parse the table header to get the table length */
32 if (count <= sizeof(struct acpi_table_header))
33 return -EINVAL;
34 if (copy_from_user(&table, user_buf,
35 sizeof(struct acpi_table_header)))
36 return -EFAULT;
37 uncopied_bytes = max_size = table.length;
38 buf = kzalloc(max_size, GFP_KERNEL);
39 if (!buf)
40 return -ENOMEM;
41 }
42
43 if (buf == NULL)
44 return -EINVAL;
45
46 if ((*ppos > max_size) ||
47 (*ppos + count > max_size) ||
48 (*ppos + count < count) ||
49 (count > uncopied_bytes))
50 return -EINVAL;
51
52 if (copy_from_user(buf + (*ppos), user_buf, count)) {
53 kfree(buf);
54 buf = NULL;
55 return -EFAULT;
56 }
57
58 uncopied_bytes -= count;
59 *ppos += count;
60
61 if (!uncopied_bytes) {
62 status = acpi_install_method(buf);
63 kfree(buf);
64 buf = NULL;
65 if (ACPI_FAILURE(status))
66 return -EINVAL;
67 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
68 }
69
70 return count;
71}
72
73static const struct file_operations cm_fops = {
74 .write = cm_write,
75 .llseek = default_llseek,
76};
77
78static int __init acpi_custom_method_init(void)
79{
80 if (!acpi_debugfs_dir)
81 return -ENOENT;
82
83 cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
84 acpi_debugfs_dir, NULL, &cm_fops);
85 if (!cm_dentry)
86 return -ENODEV;
87
88 return 0;
89}
90 14
91void __init acpi_debugfs_init(void) 15void __init acpi_debugfs_init(void)
92{ 16{
93 acpi_debugfs_dir = debugfs_create_dir("acpi", NULL); 17 acpi_debugfs_dir = debugfs_create_dir("acpi", NULL);
94
95 acpi_custom_method_init();
96} 18}