^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * custom_method.c - debugfs interface for customizing ACPI control method
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/security.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static struct dentry *cm_dentry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* /sys/kernel/debug/acpi/custom_method */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static ssize_t cm_write(struct file *file, const char __user * user_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) size_t count, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static u32 max_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static u32 uncopied_bytes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct acpi_table_header table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) ret = security_locked_down(LOCKDOWN_ACPI_TABLES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (!(*ppos)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) /* parse the table header to get the table length */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (count <= sizeof(struct acpi_table_header))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (copy_from_user(&table, user_buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) sizeof(struct acpi_table_header)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) uncopied_bytes = max_size = table.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* make sure the buf is not allocated */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) buf = kzalloc(max_size, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (!buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (buf == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if ((*ppos > max_size) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) (*ppos + count > max_size) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) (*ppos + count < count) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) (count > uncopied_bytes)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (copy_from_user(buf + (*ppos), user_buf, count)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) uncopied_bytes -= count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *ppos += count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (!uncopied_bytes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) status = acpi_install_method(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) kfree(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) buf = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static const struct file_operations cm_fops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) .write = cm_write,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .llseek = default_llseek,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int __init acpi_custom_method_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) cm_dentry = debugfs_create_file("custom_method", S_IWUSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) acpi_debugfs_dir, NULL, &cm_fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static void __exit acpi_custom_method_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) debugfs_remove(cm_dentry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) module_init(acpi_custom_method_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) module_exit(acpi_custom_method_exit);