PCI: hotplug: Constify hotplug_slot_ops
authorLukas Wunner <lukas@wunner.de>
Sat, 8 Sep 2018 07:59:01 +0000 (09:59 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 18 Sep 2018 22:52:15 +0000 (17:52 -0500)
Hotplug drivers cannot declare their hotplug_slot_ops const, making them
attractive targets for attackers, because upon registration of a hotplug
slot, __pci_hp_initialize() writes to the "owner" and "mod_name" members
in that struct.

Fix by moving these members to struct hotplug_slot and constify every
driver's hotplug_slot_ops except for pciehp.

pciehp constructs its hotplug_slot_ops at runtime based on the PCIe
port's capabilities, hence cannot declare them const.  It can be
converted to __write_rarely once that's mainlined:
http://www.openwall.com/lists/kernel-hardening/2016/11/16/3

Signed-off-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Tyrel Datwyler <tyreld@linux.vnet.ibm.com> # drivers/pci/hotplug/rpa*
Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com> # drivers/platform/x86
Cc: Len Brown <lenb@kernel.org>
Cc: Scott Murray <scott@spiteful.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Oliver OHalloran <oliveroh@au1.ibm.com>
Cc: Gavin Shan <gwshan@linux.vnet.ibm.com>
Cc: Sebastian Ott <sebott@linux.vnet.ibm.com>
Cc: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Cc: Corentin Chary <corentin.chary@gmail.com>
Cc: Darren Hart <dvhart@infradead.org>
17 files changed:
drivers/pci/hotplug/acpiphp_core.c
drivers/pci/hotplug/cpci_hotplug_core.c
drivers/pci/hotplug/cpqphp_core.c
drivers/pci/hotplug/ibmphp.h
drivers/pci/hotplug/ibmphp_core.c
drivers/pci/hotplug/pci_hotplug_core.c
drivers/pci/hotplug/pnv_php.c
drivers/pci/hotplug/rpaphp.h
drivers/pci/hotplug/rpaphp_core.c
drivers/pci/hotplug/s390_pci_hpc.c
drivers/pci/hotplug/sgi_hotplug.c
drivers/pci/hotplug/shpchp_core.c
drivers/pci/pci.c
drivers/pci/slot.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/eeepc-laptop.c
include/linux/pci_hotplug.h

index ad32ffb..e883cef 100644 (file)
@@ -57,7 +57,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
 
-static struct hotplug_slot_ops acpi_hotplug_slot_ops = {
+static const struct hotplug_slot_ops acpi_hotplug_slot_ops = {
        .enable_slot            = enable_slot,
        .disable_slot           = disable_slot,
        .set_attention_status   = set_attention_status,
index 52a339b..97c32e4 100644 (file)
@@ -57,7 +57,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
 
-static struct hotplug_slot_ops cpci_hotplug_slot_ops = {
+static const struct hotplug_slot_ops cpci_hotplug_slot_ops = {
        .enable_slot = enable_slot,
        .disable_slot = disable_slot,
        .set_attention_status = set_attention_status,
index 5a06636..3409b62 100644 (file)
@@ -560,7 +560,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
        return 0;
 }
 
-static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
+static const struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {
        .set_attention_status = set_attention_status,
        .enable_slot =          process_SI,
        .disable_slot =         process_SS,
index fddb786..db387e1 100644 (file)
@@ -740,7 +740,7 @@ int ibmphp_do_disable_slot(struct slot *slot_cur);
 int ibmphp_update_slot_info(struct slot *);    /* This function is called from HPC, so we need it to not be be static */
 int ibmphp_configure_card(struct pci_func *, u8);
 int ibmphp_unconfigure_card(struct slot **, int);
-extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops;
+extern const struct hotplug_slot_ops ibmphp_hotplug_slot_ops;
 
 #endif                         //__IBMPHP_H
 
index 4ea57e9..b82fdc1 100644 (file)
@@ -1259,7 +1259,7 @@ error:
        goto exit;
 }
 
-struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
+const struct hotplug_slot_ops ibmphp_hotplug_slot_ops = {
        .set_attention_status =         set_attention_status,
        .enable_slot =                  enable_slot,
        .disable_slot =                 ibmphp_disable_slot,
index 90fde5f..ede2ed6 100644 (file)
@@ -49,15 +49,15 @@ static DEFINE_MUTEX(pci_hp_mutex);
 #define GET_STATUS(name, type) \
 static int get_##name(struct hotplug_slot *slot, type *value)          \
 {                                                                      \
-       struct hotplug_slot_ops *ops = slot->ops;                       \
+       const struct hotplug_slot_ops *ops = slot->ops;                 \
        int retval = 0;                                                 \
-       if (!try_module_get(ops->owner))                                \
+       if (!try_module_get(slot->owner))                               \
                return -ENODEV;                                         \
        if (ops->get_##name)                                            \
                retval = ops->get_##name(slot, value);                  \
        else                                                            \
                *value = slot->info->name;                              \
-       module_put(ops->owner);                                         \
+       module_put(slot->owner);                                        \
        return retval;                                                  \
 }
 
@@ -90,7 +90,7 @@ static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
        power = (u8)(lpower & 0xff);
        dbg("power = %d\n", power);
 
-       if (!try_module_get(slot->ops->owner)) {
+       if (!try_module_get(slot->owner)) {
                retval = -ENODEV;
                goto exit;
        }
@@ -109,7 +109,7 @@ static ssize_t power_write_file(struct pci_slot *pci_slot, const char *buf,
                err("Illegal value specified for power\n");
                retval = -EINVAL;
        }
-       module_put(slot->ops->owner);
+       module_put(slot->owner);
 
 exit:
        if (retval)
@@ -138,7 +138,8 @@ static ssize_t attention_read_file(struct pci_slot *pci_slot, char *buf)
 static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
                                    size_t count)
 {
-       struct hotplug_slot_ops *ops = pci_slot->hotplug->ops;
+       struct hotplug_slot *slot = pci_slot->hotplug;
+       const struct hotplug_slot_ops *ops = slot->ops;
        unsigned long lattention;
        u8 attention;
        int retval = 0;
@@ -147,13 +148,13 @@ static ssize_t attention_write_file(struct pci_slot *pci_slot, const char *buf,
        attention = (u8)(lattention & 0xff);
        dbg(" - attention = %d\n", attention);
 
-       if (!try_module_get(ops->owner)) {
+       if (!try_module_get(slot->owner)) {
                retval = -ENODEV;
                goto exit;
        }
        if (ops->set_attention_status)
-               retval = ops->set_attention_status(pci_slot->hotplug, attention);
-       module_put(ops->owner);
+               retval = ops->set_attention_status(slot, attention);
+       module_put(slot->owner);
 
 exit:
        if (retval)
@@ -213,13 +214,13 @@ static ssize_t test_write_file(struct pci_slot *pci_slot, const char *buf,
        test = (u32)(ltest & 0xffffffff);
        dbg("test = %d\n", test);
 
-       if (!try_module_get(slot->ops->owner)) {
+       if (!try_module_get(slot->owner)) {
                retval = -ENODEV;
                goto exit;
        }
        if (slot->ops->hardware_test)
                retval = slot->ops->hardware_test(slot, test);
-       module_put(slot->ops->owner);
+       module_put(slot->owner);
 
 exit:
        if (retval)
@@ -447,8 +448,8 @@ int __pci_hp_initialize(struct hotplug_slot *slot, struct pci_bus *bus,
        if ((slot->info == NULL) || (slot->ops == NULL))
                return -EINVAL;
 
-       slot->ops->owner = owner;
-       slot->ops->mod_name = mod_name;
+       slot->owner = owner;
+       slot->mod_name = mod_name;
 
        /*
         * No problems if we call this interface from both ACPI_PCI_SLOT
index 3276a5e..12b92a0 100644 (file)
@@ -530,7 +530,7 @@ static int pnv_php_disable_slot(struct hotplug_slot *slot)
        return ret;
 }
 
-static struct hotplug_slot_ops php_slot_ops = {
+static const struct hotplug_slot_ops php_slot_ops = {
        .get_power_status       = pnv_php_get_power_state,
        .get_adapter_status     = pnv_php_get_adapter_state,
        .set_attention_status   = pnv_php_set_attention_state,
index c831172..f833478 100644 (file)
@@ -70,7 +70,7 @@ struct slot {
        struct hotplug_slot *hotplug_slot;
 };
 
-extern struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
+extern const struct hotplug_slot_ops rpaphp_hotplug_slot_ops;
 extern struct list_head rpaphp_slot_head;
 
 /* function prototypes */
index 857c358..8620a3f 100644 (file)
@@ -477,7 +477,7 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)
        return 0;
 }
 
-struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
+const struct hotplug_slot_ops rpaphp_hotplug_slot_ops = {
        .enable_slot = enable_slot,
        .disable_slot = disable_slot,
        .set_attention_status = set_attention_status,
index 93b5341..5bd45fd 100644 (file)
@@ -130,7 +130,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
        return 0;
 }
 
-static struct hotplug_slot_ops s390_hotplug_slot_ops = {
+static const struct hotplug_slot_ops s390_hotplug_slot_ops = {
        .enable_slot =          enable_slot,
        .disable_slot =         disable_slot,
        .get_power_status =     get_power_status,
index babd234..af4c28c 100644 (file)
@@ -80,7 +80,7 @@ static int enable_slot(struct hotplug_slot *slot);
 static int disable_slot(struct hotplug_slot *slot);
 static inline int get_power_status(struct hotplug_slot *slot, u8 *value);
 
-static struct hotplug_slot_ops sn_hotplug_slot_ops = {
+static const struct hotplug_slot_ops sn_hotplug_slot_ops = {
        .enable_slot            = enable_slot,
        .disable_slot           = disable_slot,
        .get_power_status       = get_power_status,
index 97cee23..26cbea0 100644 (file)
@@ -51,7 +51,7 @@ static int get_attention_status(struct hotplug_slot *slot, u8 *value);
 static int get_latch_status(struct hotplug_slot *slot, u8 *value);
 static int get_adapter_status(struct hotplug_slot *slot, u8 *value);
 
-static struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
+static const struct hotplug_slot_ops shpchp_hotplug_slot_ops = {
        .set_attention_status = set_attention_status,
        .enable_slot =          enable_slot,
        .disable_slot =         disable_slot,
index 1835f3a..0e54588 100644 (file)
@@ -4571,13 +4571,13 @@ static int pci_reset_hotplug_slot(struct hotplug_slot *hotplug, int probe)
 {
        int rc = -ENOTTY;
 
-       if (!hotplug || !try_module_get(hotplug->ops->owner))
+       if (!hotplug || !try_module_get(hotplug->owner))
                return rc;
 
        if (hotplug->ops->reset_slot)
                rc = hotplug->ops->reset_slot(hotplug, probe);
 
-       module_put(hotplug->ops->owner);
+       module_put(hotplug->owner);
 
        return rc;
 }
index e634229..145cd95 100644 (file)
@@ -371,7 +371,7 @@ void pci_hp_create_module_link(struct pci_slot *pci_slot)
 
        if (!slot || !slot->ops)
                return;
-       kobj = kset_find_obj(module_kset, slot->ops->mod_name);
+       kobj = kset_find_obj(module_kset, slot->mod_name);
        if (!kobj)
                return;
        ret = sysfs_create_link(&pci_slot->kobj, kobj, "module");
index 2d6e272..a8aa2ea 100644 (file)
@@ -868,8 +868,7 @@ static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot,
        return 0;
 }
 
-static struct hotplug_slot_ops asus_hotplug_slot_ops = {
-       .owner = THIS_MODULE,
+static const struct hotplug_slot_ops asus_hotplug_slot_ops = {
        .get_adapter_status = asus_get_adapter_status,
        .get_power_status = asus_get_adapter_status,
 };
index a4bbf6e..41a3643 100644 (file)
@@ -726,8 +726,7 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
        return 0;
 }
 
-static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
-       .owner = THIS_MODULE,
+static const struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
        .get_adapter_status = eeepc_get_adapter_status,
        .get_power_status = eeepc_get_adapter_status,
 };
index a6d6650..372dbe9 100644 (file)
@@ -16,8 +16,6 @@
 
 /**
  * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use
- * @owner: The module owner of this structure
- * @mod_name: The module name (KBUILD_MODNAME) of this structure
  * @enable_slot: Called when the user wants to enable a specific pci slot
  * @disable_slot: Called when the user wants to disable a specific pci slot
  * @set_attention_status: Called to set the specific slot's attention LED to
@@ -46,8 +44,6 @@
  * set an LED, enable / disable power, etc.)
  */
 struct hotplug_slot_ops {
-       struct module *owner;
-       const char *mod_name;
        int (*enable_slot)              (struct hotplug_slot *slot);
        int (*disable_slot)             (struct hotplug_slot *slot);
        int (*set_attention_status)     (struct hotplug_slot *slot, u8 value);
@@ -82,15 +78,19 @@ struct hotplug_slot_info {
  * this slot.
  * @private: used by the hotplug pci controller driver to store whatever it
  * needs.
+ * @owner: The module owner of this structure
+ * @mod_name: The module name (KBUILD_MODNAME) of this structure
  */
 struct hotplug_slot {
-       struct hotplug_slot_ops         *ops;
+       const struct hotplug_slot_ops   *ops;
        struct hotplug_slot_info        *info;
        void                            *private;
 
        /* Variables below this are for use only by the hotplug pci core. */
        struct list_head                slot_list;
        struct pci_slot                 *pci_slot;
+       struct module                   *owner;
+       const char                      *mod_name;
 };
 
 static inline const char *hotplug_slot_name(const struct hotplug_slot *slot)