diff options
Diffstat (limited to 'drivers/base/devcoredump.c')
| -rw-r--r-- | drivers/base/devcoredump.c | 56 | 
1 files changed, 48 insertions, 8 deletions
diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c index 96614b04544c..1bd120a0b084 100644 --- a/drivers/base/devcoredump.c +++ b/drivers/base/devcoredump.c @@ -31,6 +31,11 @@  #include <linux/fs.h>  #include <linux/workqueue.h> +static struct class devcd_class; + +/* global disable flag, for security purposes */ +static bool devcd_disabled; +  /* if data isn't read by userspace after 5 minutes then delete it */  #define DEVCD_TIMEOUT	(HZ * 60 * 5) @@ -121,11 +126,51 @@ static const struct attribute_group *devcd_dev_groups[] = {  	&devcd_dev_group, NULL,  }; +static int devcd_free(struct device *dev, void *data) +{ +	struct devcd_entry *devcd = dev_to_devcd(dev); + +	flush_delayed_work(&devcd->del_wk); +	return 0; +} + +static ssize_t disabled_show(struct class *class, struct class_attribute *attr, +			     char *buf) +{ +	return sprintf(buf, "%d\n", devcd_disabled); +} + +static ssize_t disabled_store(struct class *class, struct class_attribute *attr, +			      const char *buf, size_t count) +{ +	long tmp = simple_strtol(buf, NULL, 10); + +	/* +	 * This essentially makes the attribute write-once, since you can't +	 * go back to not having it disabled. This is intentional, it serves +	 * as a system lockdown feature. +	 */ +	if (tmp != 1) +		return -EINVAL; + +	devcd_disabled = true; + +	class_for_each_device(&devcd_class, NULL, NULL, devcd_free); + +	return count; +} + +static struct class_attribute devcd_class_attrs[] = { +	__ATTR_RW(disabled), +	__ATTR_NULL +}; +  static struct class devcd_class = {  	.name		= "devcoredump",  	.owner		= THIS_MODULE,  	.dev_release	= devcd_dev_release,  	.dev_groups	= devcd_dev_groups, +	.class_attrs	= devcd_class_attrs,  };  static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count, @@ -192,6 +237,9 @@ void dev_coredumpm(struct device *dev, struct module *owner,  	struct devcd_entry *devcd;  	struct device *existing; +	if (devcd_disabled) +		goto free; +  	existing = class_find_device(&devcd_class, NULL, dev,  				     devcd_match_failing);  	if (existing) { @@ -249,14 +297,6 @@ static int __init devcoredump_init(void)  }  __initcall(devcoredump_init); -static int devcd_free(struct device *dev, void *data) -{ -	struct devcd_entry *devcd = dev_to_devcd(dev); - -	flush_delayed_work(&devcd->del_wk); -	return 0; -} -  static void __exit devcoredump_exit(void)  {  	class_for_each_device(&devcd_class, NULL, NULL, devcd_free);  |