linux/drivers/base/devcoredump.c
<<
>>
Prefs
   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
  20static struct class devcd_class;
  21
  22/* global disable flag, for security purposes */
  23static 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
  28struct 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
  40static struct devcd_entry *dev_to_devcd(struct device *dev)
  41{
  42        return container_of(dev, struct devcd_entry, devcd_dev);
  43}
  44
  45static void devcd_dev_release(struct device *dev)
  46{
  47        struct devcd_entry *devcd = dev_to_devcd(dev);
  48
  49        devcd->free(devcd->data);
  50        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        if (devcd->failing_dev->kobj.sd)
  57                sysfs_delete_link(&devcd->failing_dev->kobj, &dev->kobj,
  58                                  "devcoredump");
  59
  60        put_device(devcd->failing_dev);
  61        kfree(devcd);
  62}
  63
  64static void devcd_del(struct work_struct *wk)
  65{
  66        struct devcd_entry *devcd;
  67
  68        devcd = container_of(wk, struct devcd_entry, del_wk.work);
  69
  70        device_del(&devcd->devcd_dev);
  71        put_device(&devcd->devcd_dev);
  72}
  73
  74static 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        struct device *dev = kobj_to_dev(kobj);
  79        struct devcd_entry *devcd = dev_to_devcd(dev);
  80
  81        return devcd->read(buffer, offset, count, devcd->data, devcd->datalen);
  82}
  83
  84static 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        struct device *dev = kobj_to_dev(kobj);
  89        struct devcd_entry *devcd = dev_to_devcd(dev);
  90
  91        mod_delayed_work(system_wq, &devcd->del_wk, 0);
  92
  93        return count;
  94}
  95
  96static 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
 103static struct bin_attribute *devcd_dev_bin_attrs[] = {
 104        &devcd_attr_data, NULL,
 105};
 106
 107static const struct attribute_group devcd_dev_group = {
 108        .bin_attrs = devcd_dev_bin_attrs,
 109};
 110
 111static const struct attribute_group *devcd_dev_groups[] = {
 112        &devcd_dev_group, NULL,
 113};
 114
 115static int devcd_free(struct device *dev, void *data)
 116{
 117        struct devcd_entry *devcd = dev_to_devcd(dev);
 118
 119        flush_delayed_work(&devcd->del_wk);
 120        return 0;
 121}
 122
 123static ssize_t disabled_show(struct class *class, struct class_attribute *attr,
 124                             char *buf)
 125{
 126        return sprintf(buf, "%d\n", devcd_disabled);
 127}
 128
 129static ssize_t disabled_store(struct class *class, struct class_attribute *attr,
 130                              const char *buf, size_t count)
 131{
 132        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        if (tmp != 1)
 140                return -EINVAL;
 141
 142        devcd_disabled = true;
 143
 144        class_for_each_device(&devcd_class, NULL, NULL, devcd_free);
 145
 146        return count;
 147}
 148static CLASS_ATTR_RW(disabled);
 149
 150static struct attribute *devcd_class_attrs[] = {
 151        &class_attr_disabled.attr,
 152        NULL,
 153};
 154ATTRIBUTE_GROUPS(devcd_class);
 155
 156static 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
 164static ssize_t devcd_readv(char *buffer, loff_t offset, size_t count,
 165                           void *data, size_t datalen)
 166{
 167        return memory_read_from_buffer(buffer, count, &offset, data, datalen);
 168}
 169
 170static void devcd_freev(void *data)
 171{
 172        vfree(data);
 173}
 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 */
 185void dev_coredumpv(struct device *dev, void *data, size_t datalen,
 186                   gfp_t gfp)
 187{
 188        dev_coredumpm(dev, NULL, data, datalen, gfp, devcd_readv, devcd_freev);
 189}
 190EXPORT_SYMBOL_GPL(dev_coredumpv);
 191
 192static int devcd_match_failing(struct device *dev, const void *failing)
 193{
 194        struct devcd_entry *devcd = dev_to_devcd(dev);
 195
 196        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 */
 207static void devcd_free_sgtable(void *data)
 208{
 209        _devcd_free_sgtable(data);
 210}
 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 */
 222static 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        struct scatterlist *table = data;
 227
 228        if (offset > data_len)
 229                return -EINVAL;
 230
 231        if (offset + buf_len > data_len)
 232                buf_len = data_len - offset;
 233        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 */
 252void 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        static atomic_t devcd_count = ATOMIC_INIT(0);
 259        struct devcd_entry *devcd;
 260        struct device *existing;
 261
 262        if (devcd_disabled)
 263                goto free;
 264
 265        existing = class_find_device(&devcd_class, NULL, dev,
 266                                     devcd_match_failing);
 267        if (existing) {
 268                put_device(existing);
 269                goto free;
 270        }
 271
 272        if (!try_module_get(owner))
 273                goto free;
 274
 275        devcd = kzalloc(sizeof(*devcd), gfp);
 276        if (!devcd)
 277                goto put_module;
 278
 279        devcd->owner = owner;
 280        devcd->data = data;
 281        devcd->datalen = datalen;
 282        devcd->read = read;
 283        devcd->free = free;
 284        devcd->failing_dev = get_device(dev);
 285
 286        device_initialize(&devcd->devcd_dev);
 287
 288        dev_set_name(&devcd->devcd_dev, "devcd%d",
 289                     atomic_inc_return(&devcd_count));
 290        devcd->devcd_dev.class = &devcd_class;
 291
 292        if (device_add(&devcd->devcd_dev))
 293                goto put_device;
 294
 295        if (sysfs_create_link(&devcd->devcd_dev.kobj, &dev->kobj,
 296                              "failing_device"))
 297                /* nothing - symlink will be missing */;
 298
 299        if (sysfs_create_link(&dev->kobj, &devcd->devcd_dev.kobj,
 300                              "devcoredump"))
 301                /* nothing - symlink will be missing */;
 302
 303        INIT_DELAYED_WORK(&devcd->del_wk, devcd_del);
 304        schedule_delayed_work(&devcd->del_wk, DEVCD_TIMEOUT);
 305
 306        return;
 307 put_device:
 308        put_device(&devcd->devcd_dev);
 309 put_module:
 310        module_put(owner);
 311 free:
 312        free(data);
 313}
 314EXPORT_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 */
 329void dev_coredumpsg(struct device *dev, struct scatterlist *table,
 330                    size_t datalen, gfp_t gfp)
 331{
 332        dev_coredumpm(dev, NULL, table, datalen, gfp, devcd_read_from_sgtable,
 333                      devcd_free_sgtable);
 334}
 335EXPORT_SYMBOL_GPL(dev_coredumpsg);
 336
 337static int __init devcoredump_init(void)
 338{
 339        return class_register(&devcd_class);
 340}
 341__initcall(devcoredump_init);
 342
 343static void __exit devcoredump_exit(void)
 344{
 345        class_for_each_device(&devcd_class, NULL, NULL, devcd_free);
 346        class_unregister(&devcd_class);
 347}
 348__exitcall(devcoredump_exit);
 349