aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2014-11-13 16:16:29 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-11-26 22:40:12 -0500
commitd45333294da8341f64d22219729249f7102c490e (patch)
treeb9b7194a4789377ddfbdf8591f52e974d468348f /drivers/base
parente135303bd5bebcd22bcf8a6b06ec0dd5a9432708 (diff)
devcoredump: provide a one-way disable function
Since device/firmware coredumps can contain private data, it can be desirable to turn them off unconditionally to be certain that no such data will be collected by the system. To achieve this, provide a "disabled" sysfs class attribute that can only be changed from 0 to 1 and not back. Upon disabling, discard existing coredumps and stop storing new ones. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Reviewed-by: Kees Cook <keescook@chromium.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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);