Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Copyright(c) 2014 Intel Mobile Communications GmbH
4 : : * Copyright(c) 2015 Intel Deutschland GmbH
5 : : *
6 : : * Contact Information:
7 : : * Intel Linux Wireless <ilw@linux.intel.com>
8 : : * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
9 : : *
10 : : * Author: Johannes Berg <johannes@sipsolutions.net>
11 : : */
12 : : #include <linux/module.h>
13 : : #include <linux/device.h>
14 : : #include <linux/devcoredump.h>
15 : : #include <linux/list.h>
16 : : #include <linux/slab.h>
17 : : #include <linux/fs.h>
18 : : #include <linux/workqueue.h>
19 : :
20 : : static struct class devcd_class;
21 : :
22 : : /* global disable flag, for security purposes */
23 : : static bool devcd_disabled;
24 : :
25 : : /* if data isn't read by userspace after 5 minutes then delete it */
26 : : #define DEVCD_TIMEOUT (HZ * 60 * 5)
27 : :
28 : : struct devcd_entry {
29 : : struct device devcd_dev;
30 : : void *data;
31 : : size_t datalen;
32 : : struct module *owner;
33 : : ssize_t (*read)(char *buffer, loff_t offset, size_t count,
34 : : void *data, size_t datalen);
35 : : void (*free)(void *data);
36 : : struct delayed_work del_wk;
37 : : struct device *failing_dev;
38 : : };
39 : :
40 : 0 : static struct devcd_entry *dev_to_devcd(struct device *dev)
41 : : {
42 : 0 : return container_of(dev, struct devcd_entry, devcd_dev);
43 : : }
44 : :
45 : 0 : static void devcd_dev_release(struct device *dev)
46 : : {
47 : 0 : struct devcd_entry *devcd = dev_to_devcd(dev);
48 : :
49 : 0 : devcd->free(devcd->data);
50 : 0 : module_put(devcd->owner);
51 : :
52 : : /*
53 : : * this seems racy, but I don't see a notifier or such on
54 : : * a struct device to know when it goes away?
55 : : */
56 [ # # ]: 0 : if (devcd->failing_dev->kobj.sd)
57 : 0 : sysfs_delete_link(&devcd->failing_dev->kobj, &dev->kobj,
58 : : "devcoredump");
59 : :
60 : 0 : put_device(devcd->failing_dev);
61 : 0 : kfree(devcd);
62 : 0 : }
63 : :
64 : 0 : static void devcd_del(struct work_struct *wk)
65 : : {
66 : 0 : struct devcd_entry *devcd;
67 : :
68 : 0 : devcd = container_of(wk, struct devcd_entry, del_wk.work);
69 : :
70 : 0 : device_del(&devcd->devcd_dev);
71 : 0 : put_device(&devcd->devcd_dev);
72 : 0 : }
73 : :
74 : 0 : static ssize_t devcd_data_read(struct file *filp, struct kobject *kobj,
75 : : struct bin_attribute *bin_attr,
76 : : char *buffer, loff_t offset, size_t count)
77 : : {
78 : 0 : struct device *dev = kobj_to_dev(kobj);
79 : 0 : struct devcd_entry *devcd = dev_to_devcd(dev);
80 : :
81 : 0 : return devcd->read(buffer, offset, count, devcd->data, devcd->datalen);
82 : : }
83 : :
84 : 0 : static ssize_t devcd_data_write(struct file *filp, struct kobject *kobj,
85 : : struct bin_attribute *bin_attr,
86 : : char *buffer, loff_t offset, size_t count)
87 : : {
88 : 0 : struct device *dev = kobj_to_dev(kobj);
89 : 0 : struct devcd_entry *devcd = dev_to_devcd(dev);
90 : :
91 : 0 : mod_delayed_work(system_wq, &devcd->del_wk, 0);
92 : :
93 : 0 : return count;
94 : : }
95 : :
96 : : static struct bin_attribute devcd_attr_data = {
97 : : .attr = { .name = "data", .mode = S_IRUSR | S_IWUSR, },
98 : : .size = 0,
99 : : .read = devcd_data_read,
100 : : .write = devcd_data_write,
101 : : };
102 : :
103 : : static struct bin_attribute *devcd_dev_bin_attrs[] = {
104 : : &devcd_attr_data, NULL,
105 : : };
106 : :
107 : : static const struct attribute_group devcd_dev_group = {
108 : : .bin_attrs = devcd_dev_bin_attrs,
109 : : };
110 : :
111 : : static const struct attribute_group *devcd_dev_groups[] = {
112 : : &devcd_dev_group, NULL,
113 : : };
114 : :
115 : 0 : static int devcd_free(struct device *dev, void *data)
116 : : {
117 : 0 : struct devcd_entry *devcd = dev_to_devcd(dev);
118 : :
119 : 0 : flush_delayed_work(&devcd->del_wk);
120 : 0 : return 0;
121 : : }
122 : :
123 : 0 : static ssize_t disabled_show(struct class *class, struct class_attribute *attr,
124 : : char *buf)
125 : : {
126 : 0 : return sprintf(buf, "%d\n", devcd_disabled);
127 : : }
128 : :
129 : 0 : static ssize_t disabled_store(struct class *class, struct class_attribute *attr,
130 : : const char *buf, size_t count)
131 : : {
132 : 0 : long tmp = simple_strtol(buf, NULL, 10);
133 : :
134 : : /*
135 : : * This essentially makes the attribute write-once, since you can't
136 : : * go back to not having it disabled. This is intentional, it serves
137 : : * as a system lockdown feature.
138 : : */
139 [ # # ]: 0 : if (tmp != 1)
140 : : return -EINVAL;
141 : :
142 : 0 : devcd_disabled = true;
143 : :
144 : 0 : class_for_each_device(&devcd_class, NULL, NULL, devcd_free);
145 : :
146 : 0 : return count;
147 : : }
148 : : static CLASS_ATTR_RW(disabled);
149 : :
150 : : static struct attribute *devcd_class_attrs[] = {
151 : : &class_attr_disabled.attr,
152 : : NULL,
153 : : };
154 : : ATTRIBUTE_GROUPS(devcd_class);
155 : :
156 : : static struct class devcd_class = {
157 : : .name = "devcoredump",
158 : : .owner = THIS_MODULE,
159 : : .dev_release = devcd_dev_release,
160 : : .dev_groups = devcd_dev_groups,
161 : : .class_groups = devcd_class_groups,
162 : : };
163 : :
164 : 0 : static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count,
165 : : void *data, size_t datalen)
166 : : {
167 : 0 : return memory_read_from_buffer(buffer, count, &offset, data, datalen);
168 : : }
169 : :
170 : 0 : static void devcd_freev(void *data)
171 : : {
172 : 0 : vfree(data);
173 : 0 : }
174 : :
175 : : /**
176 : : * dev_coredumpv - create device coredump with vmalloc data
177 : : * @dev: the struct device for the crashed device
178 : : * @data: vmalloc data containing the device coredump
179 : : * @datalen: length of the data
180 : : * @gfp: allocation flags
181 : : *
182 : : * This function takes ownership of the vmalloc'ed data and will free
183 : : * it when it is no longer used. See dev_coredumpm() for more information.
184 : : */
185 : 0 : void dev_coredumpv(struct device *dev, void *data, size_t datalen,
186 : : gfp_t gfp)
187 : : {
188 : 0 : dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, devcd_freev);
189 : 0 : }
190 : : EXPORT_SYMBOL_GPL(dev_coredumpv);
191 : :
192 : 0 : static int devcd_match_failing(struct device *dev, const void *failing)
193 : : {
194 : 0 : struct devcd_entry *devcd = dev_to_devcd(dev);
195 : :
196 : 0 : return devcd->failing_dev == failing;
197 : : }
198 : :
199 : : /**
200 : : * devcd_free_sgtable - free all the memory of the given scatterlist table
201 : : * (i.e. both pages and scatterlist instances)
202 : : * NOTE: if two tables allocated with devcd_alloc_sgtable and then chained
203 : : * using the sg_chain function then that function should be called only once
204 : : * on the chained table
205 : : * @table: pointer to sg_table to free
206 : : */
207 : 0 : static void devcd_free_sgtable(void *data)
208 : : {
209 : 0 : _devcd_free_sgtable(data);
210 : 0 : }
211 : :
212 : : /**
213 : : * devcd_read_from_table - copy data from sg_table to a given buffer
214 : : * and return the number of bytes read
215 : : * @buffer: the buffer to copy the data to it
216 : : * @buf_len: the length of the buffer
217 : : * @data: the scatterlist table to copy from
218 : : * @offset: start copy from @offset@ bytes from the head of the data
219 : : * in the given scatterlist
220 : : * @data_len: the length of the data in the sg_table
221 : : */
222 : 0 : static ssize_t devcd_read_from_sgtable(char *buffer, loff_t offset,
223 : : size_t buf_len, void *data,
224 : : size_t data_len)
225 : : {
226 : 0 : struct scatterlist *table = data;
227 : :
228 [ # # ]: 0 : if (offset > data_len)
229 : : return -EINVAL;
230 : :
231 [ # # ]: 0 : if (offset + buf_len > data_len)
232 : 0 : buf_len = data_len - offset;
233 : 0 : return sg_pcopy_to_buffer(table, sg_nents(table), buffer, buf_len,
234 : : offset);
235 : : }
236 : :
237 : : /**
238 : : * dev_coredumpm - create device coredump with read/free methods
239 : : * @dev: the struct device for the crashed device
240 : : * @owner: the module that contains the read/free functions, use %THIS_MODULE
241 : : * @data: data cookie for the @read/@free functions
242 : : * @datalen: length of the data
243 : : * @gfp: allocation flags
244 : : * @read: function to read from the given buffer
245 : : * @free: function to free the given buffer
246 : : *
247 : : * Creates a new device coredump for the given device. If a previous one hasn't
248 : : * been read yet, the new coredump is discarded. The data lifetime is determined
249 : : * by the device coredump framework and when it is no longer needed the @free
250 : : * function will be called to free the data.
251 : : */
252 : 0 : void dev_coredumpm(struct device *dev, struct module *owner,
253 : : void *data, size_t datalen, gfp_t gfp,
254 : : ssize_t (*read)(char *buffer, loff_t offset, size_t count,
255 : : void *data, size_t datalen),
256 : : void (*free)(void *data))
257 : : {
258 : 0 : static atomic_t devcd_count = ATOMIC_INIT(0);
259 : 0 : struct devcd_entry *devcd;
260 : 0 : struct device *existing;
261 : :
262 [ # # ]: 0 : if (devcd_disabled)
263 : 0 : goto free;
264 : :
265 : 0 : existing = class_find_device(&devcd_class, NULL, dev,
266 : : devcd_match_failing);
267 [ # # ]: 0 : if (existing) {
268 : 0 : put_device(existing);
269 : 0 : goto free;
270 : : }
271 : :
272 [ # # ]: 0 : if (!try_module_get(owner))
273 : 0 : goto free;
274 : :
275 : 0 : devcd = kzalloc(sizeof(*devcd), gfp);
276 [ # # ]: 0 : if (!devcd)
277 : 0 : goto put_module;
278 : :
279 : 0 : devcd->owner = owner;
280 : 0 : devcd->data = data;
281 : 0 : devcd->datalen = datalen;
282 : 0 : devcd->read = read;
283 : 0 : devcd->free = free;
284 : 0 : devcd->failing_dev = get_device(dev);
285 : :
286 : 0 : device_initialize(&devcd->devcd_dev);
287 : :
288 : 0 : dev_set_name(&devcd->devcd_dev, "devcd%d",
289 : : atomic_inc_return(&devcd_count));
290 : 0 : devcd->devcd_dev.class = &devcd_class;
291 : :
292 [ # # ]: 0 : if (device_add(&devcd->devcd_dev))
293 : 0 : goto put_device;
294 : :
295 : 0 : if (sysfs_create_link(&devcd->devcd_dev.kobj, &dev->kobj,
296 : : "failing_device"))
297 : : /* nothing - symlink will be missing */;
298 : :
299 : 0 : if (sysfs_create_link(&dev->kobj, &devcd->devcd_dev.kobj,
300 : : "devcoredump"))
301 : : /* nothing - symlink will be missing */;
302 : :
303 : 0 : INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
304 : 0 : schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT);
305 : :
306 : : return;
307 : : put_device:
308 : 0 : put_device(&devcd->devcd_dev);
309 : 0 : put_module:
310 : 0 : module_put(owner);
311 : 0 : free:
312 : 0 : free(data);
313 : : }
314 : : EXPORT_SYMBOL_GPL(dev_coredumpm);
315 : :
316 : : /**
317 : : * dev_coredumpsg - create device coredump that uses scatterlist as data
318 : : * parameter
319 : : * @dev: the struct device for the crashed device
320 : : * @table: the dump data
321 : : * @datalen: length of the data
322 : : * @gfp: allocation flags
323 : : *
324 : : * Creates a new device coredump for the given device. If a previous one hasn't
325 : : * been read yet, the new coredump is discarded. The data lifetime is determined
326 : : * by the device coredump framework and when it is no longer needed
327 : : * it will free the data.
328 : : */
329 : 0 : void dev_coredumpsg(struct device *dev, struct scatterlist *table,
330 : : size_t datalen, gfp_t gfp)
331 : : {
332 : 0 : dev_coredumpm(dev, NULL, table, datalen, gfp, devcd_read_from_sgtable,
333 : : devcd_free_sgtable);
334 : 0 : }
335 : : EXPORT_SYMBOL_GPL(dev_coredumpsg);
336 : :
337 : 30 : static int __init devcoredump_init(void)
338 : : {
339 : 30 : return class_register(&devcd_class);
340 : : }
341 : : __initcall(devcoredump_init);
342 : :
343 : 0 : static void __exit devcoredump_exit(void)
344 : : {
345 : 0 : class_for_each_device(&devcd_class, NULL, NULL, devcd_free);
346 : 0 : class_unregister(&devcd_class);
347 : 0 : }
348 : : __exitcall(devcoredump_exit);
|