0001
0002
0003
0004
0005
0006 #include <linux/init.h>
0007 #include <linux/module.h>
0008 #include <linux/kernel.h>
0009 #include <linux/uaccess.h>
0010 #include <linux/debugfs.h>
0011 #include <linux/acpi.h>
0012 #include <linux/security.h>
0013
0014 #include "internal.h"
0015
0016 MODULE_LICENSE("GPL");
0017
0018 static struct dentry *cm_dentry;
0019
0020
0021
0022 static ssize_t cm_write(struct file *file, const char __user *user_buf,
0023 size_t count, loff_t *ppos)
0024 {
0025 static char *buf;
0026 static u32 max_size;
0027 static u32 uncopied_bytes;
0028
0029 struct acpi_table_header table;
0030 acpi_status status;
0031 int ret;
0032
0033 ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
0034 if (ret)
0035 return ret;
0036
0037 if (!(*ppos)) {
0038
0039 if (count <= sizeof(struct acpi_table_header))
0040 return -EINVAL;
0041 if (copy_from_user(&table, user_buf,
0042 sizeof(struct acpi_table_header)))
0043 return -EFAULT;
0044 uncopied_bytes = max_size = table.length;
0045
0046 kfree(buf);
0047 buf = kzalloc(max_size, GFP_KERNEL);
0048 if (!buf)
0049 return -ENOMEM;
0050 }
0051
0052 if (buf == NULL)
0053 return -EINVAL;
0054
0055 if ((*ppos > max_size) ||
0056 (*ppos + count > max_size) ||
0057 (*ppos + count < count) ||
0058 (count > uncopied_bytes)) {
0059 kfree(buf);
0060 buf = NULL;
0061 return -EINVAL;
0062 }
0063
0064 if (copy_from_user(buf + (*ppos), user_buf, count)) {
0065 kfree(buf);
0066 buf = NULL;
0067 return -EFAULT;
0068 }
0069
0070 uncopied_bytes -= count;
0071 *ppos += count;
0072
0073 if (!uncopied_bytes) {
0074 status = acpi_install_method(buf);
0075 kfree(buf);
0076 buf = NULL;
0077 if (ACPI_FAILURE(status))
0078 return -EINVAL;
0079 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
0080 }
0081
0082 return count;
0083 }
0084
0085 static const struct file_operations cm_fops = {
0086 .write = cm_write,
0087 .llseek = default_llseek,
0088 };
0089
0090 static int __init acpi_custom_method_init(void)
0091 {
0092 cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
0093 acpi_debugfs_dir, NULL, &cm_fops);
0094 return 0;
0095 }
0096
0097 static void __exit acpi_custom_method_exit(void)
0098 {
0099 debugfs_remove(cm_dentry);
0100 }
0101
0102 module_init(acpi_custom_method_init);
0103 module_exit(acpi_custom_method_exit);