aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/devcoredump.c56
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 @@
31#include <linux/fs.h> 31#include <linux/fs.h>
32#include <linux/workqueue.h> 32#include <linux/workqueue.h>
33 33
34static struct class devcd_class;
35
36/* global disable flag, for security purposes */
37static bool devcd_disabled;
38
34/* if data isn't read by userspace after 5 minutes then delete it */ 39/* if data isn't read by userspace after 5 minutes then delete it */
35#define DEVCD_TIMEOUT (HZ * 60 * 5) 40#define DEVCD_TIMEOUT (HZ * 60 * 5)
36 41
@@ -121,11 +126,51 @@ static const struct attribute_group *devcd_dev_groups[] = {
121 &devcd_dev_group, NULL, 126 &devcd_dev_group, NULL,
122}; 127};
123 128
129static int devcd_free(struct device *dev, void *data)
130{
131 struct devcd_entry *devcd = dev_to_devcd(dev);
132
133 flush_delayed_work(&devcd->del_wk);
134 return 0;
135}
136
137static ssize_t disabled_show(struct class *class, struct class_attribute *attr,
138 char *buf)
139{
140 return sprintf(buf, "%d\n", devcd_disabled);
141}
142
143static ssize_t disabled_store(struct class *class, struct class_attribute *attr,
144 const char *buf, size_t count)
145{
146 long tmp = simple_strtol(buf, NULL, 10);
147
148 /*
149 * This essentially makes the attribute write-once, since you can't
150 * go back to not having it disabled. This is intentional, it serves
151 * as a system lockdown feature.
152 */
153 if (tmp != 1)
154 return -EINVAL;
155
156 devcd_disabled = true;
157
158 class_for_each_device(&devcd_class, NULL, NULL, devcd_free);
159
160 return count;
161}
162
163static struct class_attribute devcd_class_attrs[] = {
164 __ATTR_RW(disabled),
165 __ATTR_NULL
166};
167
124static struct class devcd_class = { 168static struct class devcd_class = {
125 .name = "devcoredump", 169 .name = "devcoredump",
126 .owner = THIS_MODULE, 170 .owner = THIS_MODULE,
127 .dev_release = devcd_dev_release, 171 .dev_release = devcd_dev_release,
128 .dev_groups = devcd_dev_groups, 172 .dev_groups = devcd_dev_groups,
173 .class_attrs = devcd_class_attrs,
129}; 174};
130 175
131static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count, 176static 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,
192 struct devcd_entry *devcd; 237 struct devcd_entry *devcd;
193 struct device *existing; 238 struct device *existing;
194 239
240 if (devcd_disabled)
241 goto free;
242
195 existing = class_find_device(&devcd_class, NULL, dev, 243 existing = class_find_device(&devcd_class, NULL, dev,
196 devcd_match_failing); 244 devcd_match_failing);
197 if (existing) { 245 if (existing) {
@@ -249,14 +297,6 @@ static int __init devcoredump_init(void)
249} 297}
250__initcall(devcoredump_init); 298__initcall(devcoredump_init);
251 299
252static int devcd_free(struct device *dev, void *data)
253{
254 struct devcd_entry *devcd = dev_to_devcd(dev);
255
256 flush_delayed_work(&devcd->del_wk);
257 return 0;
258}
259
260static void __exit devcoredump_exit(void) 300static void __exit devcoredump_exit(void)
261{ 301{
262 class_for_each_device(&devcd_class, NULL, NULL, devcd_free); 302 class_for_each_device(&devcd_class, NULL, NULL, devcd_free);