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