summaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-09-05 11:08:17 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-05 11:08:17 -0700
commitbafb0762cb6a906eb4105cccfb3bcd90be7f40d2 (patch)
tree14ecb87c33bcf909e5b95c27cd694ded4ac1478c /drivers/misc
parent44b1671fae88ce95b8c7b53acbc6ba71ca67db00 (diff)
parent3a6430ce462172caac7c73f4afd550ab0f105737 (diff)
Merge tag 'char-misc-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH: "Here is the big char/misc driver update for 4.14-rc1. Lots of different stuff in here, it's been an active development cycle for some reason. Highlights are: - updated binder driver, this brings binder up to date with what shipped in the Android O release, plus some more changes that happened since then that are in the Android development trees. - coresight updates and fixes - mux driver file renames to be a bit "nicer" - intel_th driver updates - normal set of hyper-v updates and changes - small fpga subsystem and driver updates - lots of const code changes all over the driver trees - extcon driver updates - fmc driver subsystem upadates - w1 subsystem minor reworks and new features and drivers added - spmi driver updates Plus a smattering of other minor driver updates and fixes. All of these have been in linux-next with no reported issues for a while" * tag 'char-misc-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (244 commits) ANDROID: binder: don't queue async transactions to thread. ANDROID: binder: don't enqueue death notifications to thread todo. ANDROID: binder: Don't BUG_ON(!spin_is_locked()). ANDROID: binder: Add BINDER_GET_NODE_DEBUG_INFO ioctl ANDROID: binder: push new transactions to waiting threads. ANDROID: binder: remove proc waitqueue android: binder: Add page usage in binder stats android: binder: fixup crash introduced by moving buffer hdr drivers: w1: add hwmon temp support for w1_therm drivers: w1: refactor w1_slave_show to make the temp reading functionality separate drivers: w1: add hwmon support structures eeprom: idt_89hpesx: Support both ACPI and OF probing mcb: Fix an error handling path in 'chameleon_parse_cells()' MCB: add support for SC31 to mcb-lpc mux: make device_type const char: virtio: constify attribute_group structures. Documentation/ABI: document the nvmem sysfs files lkdtm: fix spelling mistake: "incremeted" -> "incremented" perf: cs-etm: Fix ETMv4 CONFIGR entry in perf.data file nvmem: include linux/err.h from header ...
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/apds9802als.c4
-rw-r--r--drivers/misc/apds990x.c2
-rw-r--r--drivers/misc/aspeed-lpc-snoop.c34
-rw-r--r--drivers/misc/bh1770glc.c2
-rw-r--r--drivers/misc/ds1682.c2
-rw-r--r--drivers/misc/eeprom/eeprom.c2
-rw-r--r--drivers/misc/eeprom/eeprom_93xx46.c24
-rw-r--r--drivers/misc/eeprom/idt_89hpesx.c126
-rw-r--r--drivers/misc/eeprom/max6875.c2
-rw-r--r--drivers/misc/hmc6352.c2
-rw-r--r--drivers/misc/hpilo.c2
-rw-r--r--drivers/misc/ioc4.c2
-rw-r--r--drivers/misc/isl29020.c4
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d.c2
-rw-r--r--drivers/misc/lkdtm.h30
-rw-r--r--drivers/misc/lkdtm_bugs.c134
-rw-r--r--drivers/misc/lkdtm_core.c28
-rw-r--r--drivers/misc/lkdtm_refcount.c400
-rw-r--r--drivers/misc/mei/bus.c2
-rw-r--r--drivers/misc/mei/hw-me.c45
-rw-r--r--drivers/misc/mei/hw-me.h39
-rw-r--r--drivers/misc/mei/pci-me.c109
-rw-r--r--drivers/misc/pch_phub.c4
-rw-r--r--drivers/misc/sram.c12
-rw-r--r--drivers/misc/ti-st/st_kim.c2
-rw-r--r--drivers/misc/tifm_7xx1.c2
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c10
28 files changed, 734 insertions, 294 deletions
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index b0b766416306..d84819dc2468 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -60,6 +60,7 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_heap.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o
+lkdtm-$(CONFIG_LKDTM) += lkdtm_refcount.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o
lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o
diff --git a/drivers/misc/apds9802als.c b/drivers/misc/apds9802als.c
index c6cc3dc8ae1f..d8ac036f01ab 100644
--- a/drivers/misc/apds9802als.c
+++ b/drivers/misc/apds9802als.c
@@ -197,7 +197,7 @@ static struct attribute *mid_att_als[] = {
NULL
};
-static struct attribute_group m_als_gr = {
+static const struct attribute_group m_als_gr = {
.name = "apds9802als",
.attrs = mid_att_als
};
@@ -298,7 +298,7 @@ static UNIVERSAL_DEV_PM_OPS(apds9802als_pm_ops, apds9802als_suspend,
#define APDS9802ALS_PM_OPS NULL
#endif /* CONFIG_PM */
-static struct i2c_device_id apds9802als_id[] = {
+static const struct i2c_device_id apds9802als_id[] = {
{ DRIVER_NAME, 0 },
{ }
};
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c
index 84e5b949399e..c9f07032c2fc 100644
--- a/drivers/misc/apds990x.c
+++ b/drivers/misc/apds990x.c
@@ -1051,7 +1051,7 @@ static struct attribute *sysfs_attrs_ctrl[] = {
NULL
};
-static struct attribute_group apds990x_attribute_group[] = {
+static const struct attribute_group apds990x_attribute_group[] = {
{.attrs = sysfs_attrs_ctrl },
};
diff --git a/drivers/misc/aspeed-lpc-snoop.c b/drivers/misc/aspeed-lpc-snoop.c
index 593905565b74..cb78c98bc78d 100644
--- a/drivers/misc/aspeed-lpc-snoop.c
+++ b/drivers/misc/aspeed-lpc-snoop.c
@@ -20,6 +20,7 @@
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
@@ -51,6 +52,13 @@
#define HICRB_ENSNP0D BIT(14)
#define HICRB_ENSNP1D BIT(15)
+struct aspeed_lpc_snoop_model_data {
+ /* The ast2400 has bits 14 and 15 as reserved, whereas the ast2500
+ * can use them.
+ */
+ unsigned int has_hicrb_ensnp;
+};
+
struct aspeed_lpc_snoop {
struct regmap *regmap;
int irq;
@@ -123,10 +131,13 @@ static int aspeed_lpc_snoop_config_irq(struct aspeed_lpc_snoop *lpc_snoop,
}
static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
- int channel, u16 lpc_port)
+ struct device *dev,
+ int channel, u16 lpc_port)
{
int rc = 0;
u32 hicr5_en, snpwadr_mask, snpwadr_shift, hicrb_en;
+ const struct aspeed_lpc_snoop_model_data *model_data =
+ of_device_get_match_data(dev);
/* Create FIFO datastructure */
rc = kfifo_alloc(&lpc_snoop->snoop_fifo[channel],
@@ -155,7 +166,9 @@ static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop,
regmap_update_bits(lpc_snoop->regmap, HICR5, hicr5_en, hicr5_en);
regmap_update_bits(lpc_snoop->regmap, SNPWADR, snpwadr_mask,
lpc_port << snpwadr_shift);
- regmap_update_bits(lpc_snoop->regmap, HICRB, hicrb_en, hicrb_en);
+ if (model_data->has_hicrb_ensnp)
+ regmap_update_bits(lpc_snoop->regmap, HICRB,
+ hicrb_en, hicrb_en);
return rc;
}
@@ -213,14 +226,14 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
if (rc)
return rc;
- rc = aspeed_lpc_enable_snoop(lpc_snoop, 0, port);
+ rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port);
if (rc)
return rc;
/* Configuration of 2nd snoop channel port is optional */
if (of_property_read_u32_index(dev->of_node, "snoop-ports",
1, &port) == 0) {
- rc = aspeed_lpc_enable_snoop(lpc_snoop, 1, port);
+ rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port);
if (rc)
aspeed_lpc_disable_snoop(lpc_snoop, 0);
}
@@ -239,8 +252,19 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev)
return 0;
}
+static const struct aspeed_lpc_snoop_model_data ast2400_model_data = {
+ .has_hicrb_ensnp = 0,
+};
+
+static const struct aspeed_lpc_snoop_model_data ast2500_model_data = {
+ .has_hicrb_ensnp = 1,
+};
+
static const struct of_device_id aspeed_lpc_snoop_match[] = {
- { .compatible = "aspeed,ast2500-lpc-snoop" },
+ { .compatible = "aspeed,ast2400-lpc-snoop",
+ .data = &ast2400_model_data },
+ { .compatible = "aspeed,ast2500-lpc-snoop",
+ .data = &ast2500_model_data },
{ },
};
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
index 38fcfe219d1c..9c62bf064f77 100644
--- a/drivers/misc/bh1770glc.c
+++ b/drivers/misc/bh1770glc.c
@@ -1175,7 +1175,7 @@ static struct attribute *sysfs_attrs[] = {
NULL
};
-static struct attribute_group bh1770_attribute_group = {
+static const struct attribute_group bh1770_attribute_group = {
.attrs = sysfs_attrs
};
diff --git a/drivers/misc/ds1682.c b/drivers/misc/ds1682.c
index 28bb495f0cf1..7231260ac287 100644
--- a/drivers/misc/ds1682.c
+++ b/drivers/misc/ds1682.c
@@ -173,7 +173,7 @@ static ssize_t ds1682_eeprom_write(struct file *filp, struct kobject *kobj,
return count;
}
-static struct bin_attribute ds1682_eeprom_attr = {
+static const struct bin_attribute ds1682_eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO | S_IWUSR,
diff --git a/drivers/misc/eeprom/eeprom.c b/drivers/misc/eeprom/eeprom.c
index 2fad790db3bf..60e3d91b5e03 100644
--- a/drivers/misc/eeprom/eeprom.c
+++ b/drivers/misc/eeprom/eeprom.c
@@ -114,7 +114,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj,
return count;
}
-static struct bin_attribute eeprom_attr = {
+static const struct bin_attribute eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO,
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c
index 94cc035aa841..38766968bfa2 100644
--- a/drivers/misc/eeprom/eeprom_93xx46.c
+++ b/drivers/misc/eeprom/eeprom_93xx46.c
@@ -377,8 +377,6 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi)
struct device_node *np = spi->dev.of_node;
struct eeprom_93xx46_platform_data *pd;
u32 tmp;
- int gpio;
- enum of_gpio_flags of_flags;
int ret;
pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL);
@@ -403,22 +401,14 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi)
if (of_property_read_bool(np, "read-only"))
pd->flags |= EE_READONLY;
- gpio = of_get_named_gpio_flags(np, "select-gpios", 0, &of_flags);
- if (gpio_is_valid(gpio)) {
- unsigned long flags =
- of_flags == OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0;
+ pd->select = devm_gpiod_get_optional(&spi->dev, "select",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(pd->select))
+ return PTR_ERR(pd->select);
- ret = devm_gpio_request_one(&spi->dev, gpio, flags,
- "eeprom_93xx46_select");
- if (ret)
- return ret;
-
- pd->select = gpio_to_desc(gpio);
- pd->prepare = select_assert;
- pd->finish = select_deassert;
-
- gpiod_direction_output(pd->select, 0);
- }
+ pd->prepare = select_assert;
+ pd->finish = select_deassert;
+ gpiod_direction_output(pd->select, 0);
if (of_id->data) {
const struct eeprom_93xx46_devtype_data *data = of_id->data;
diff --git a/drivers/misc/eeprom/idt_89hpesx.c b/drivers/misc/eeprom/idt_89hpesx.c
index ab0df6a17690..34a5a41578d7 100644
--- a/drivers/misc/eeprom/idt_89hpesx.c
+++ b/drivers/misc/eeprom/idt_89hpesx.c
@@ -77,7 +77,7 @@
#include <linux/sysfs.h>
#include <linux/debugfs.h>
#include <linux/mod_devicetable.h>
-#include <linux/of.h>
+#include <linux/property.h>
#include <linux/i2c.h>
#include <linux/pci_ids.h>
#include <linux/delay.h>
@@ -1089,101 +1089,85 @@ static void idt_set_defval(struct idt_89hpesx_dev *pdev)
pdev->eeaddr = 0;
}
-#ifdef CONFIG_OF
static const struct i2c_device_id ee_ids[];
+
/*
* idt_ee_match_id() - check whether the node belongs to compatible EEPROMs
*/
-static const struct i2c_device_id *idt_ee_match_id(struct device_node *node)
+static const struct i2c_device_id *idt_ee_match_id(struct fwnode_handle *fwnode)
{
const struct i2c_device_id *id = ee_ids;
+ const char *compatible, *p;
char devname[I2C_NAME_SIZE];
+ int ret;
- /* Retrieve the device name without manufacturer name */
- if (of_modalias_node(node, devname, sizeof(devname)))
+ ret = fwnode_property_read_string(fwnode, "compatible", &compatible);
+ if (ret)
return NULL;
+ p = strchr(compatible, ',');
+ strlcpy(devname, p ? p + 1 : compatible, sizeof(devname));
/* Search through the device name */
- while (id->name[0]) {
- if (strcmp(devname, id->name) == 0)
- return id;
- id++;
- }
- return NULL;
+ while (id->name[0]) {
+ if (strcmp(devname, id->name) == 0)
+ return id;
+ id++;
+ }
+ return NULL;
}
/*
- * idt_get_ofdata() - get IDT i2c-device parameters from device tree
+ * idt_get_fw_data() - get IDT i2c-device parameters from device tree
* @pdev: Pointer to the driver data
*/
-static void idt_get_ofdata(struct idt_89hpesx_dev *pdev)
+static void idt_get_fw_data(struct idt_89hpesx_dev *pdev)
{
- const struct device_node *node = pdev->client->dev.of_node;
struct device *dev = &pdev->client->dev;
+ struct fwnode_handle *fwnode;
+ const struct i2c_device_id *ee_id = NULL;
+ u32 eeprom_addr;
+ int ret;
- /* Read dts node parameters */
- if (node) {
- const struct i2c_device_id *ee_id = NULL;
- struct device_node *child;
- const __be32 *addr_be;
- int len;
-
- /* Walk through all child nodes looking for compatible one */
- for_each_available_child_of_node(node, child) {
- ee_id = idt_ee_match_id(child);
- if (IS_ERR_OR_NULL(ee_id)) {
- dev_warn(dev, "Skip unsupported child node %s",
- child->full_name);
- continue;
- } else
- break;
- }
-
- /* If there is no child EEPROM device, then set zero size */
- if (!ee_id) {
- idt_set_defval(pdev);
- return;
- }
+ device_for_each_child_node(dev, fwnode) {
+ ee_id = idt_ee_match_id(fwnode);
+ if (IS_ERR_OR_NULL(ee_id)) {
+ dev_warn(dev, "Skip unsupported EEPROM device");
+ continue;
+ } else
+ break;
+ }
- /* Retrieve EEPROM size */
- pdev->eesize = (u32)ee_id->driver_data;
-
- /* Get custom EEPROM address from 'reg' attribute */
- addr_be = of_get_property(child, "reg", &len);
- if (!addr_be || (len < sizeof(*addr_be))) {
- dev_warn(dev, "No reg on %s, use default address %d",
- child->full_name, EEPROM_DEF_ADDR);
- pdev->inieecmd = 0;
- pdev->eeaddr = EEPROM_DEF_ADDR << 1;
- } else {
- pdev->inieecmd = EEPROM_USA;
- pdev->eeaddr = be32_to_cpup(addr_be) << 1;
- }
+ /* If there is no fwnode EEPROM device, then set zero size */
+ if (!ee_id) {
+ dev_warn(dev, "No fwnode, EEPROM access disabled");
+ idt_set_defval(pdev);
+ return;
+ }
- /* Check EEPROM 'read-only' flag */
- if (of_get_property(child, "read-only", NULL))
- pdev->eero = true;
- else /* if (!of_get_property(node, "read-only", NULL)) */
- pdev->eero = false;
+ /* Retrieve EEPROM size */
+ pdev->eesize = (u32)ee_id->driver_data;
- dev_dbg(dev, "EEPROM of %u bytes found by %hhu",
- pdev->eesize, pdev->eeaddr);
+ /* Get custom EEPROM address from 'reg' attribute */
+ ret = fwnode_property_read_u32(fwnode, "reg", &eeprom_addr);
+ if (ret || (eeprom_addr == 0)) {
+ dev_warn(dev, "No EEPROM reg found, use default address 0x%x",
+ EEPROM_DEF_ADDR);
+ pdev->inieecmd = 0;
+ pdev->eeaddr = EEPROM_DEF_ADDR << 1;
} else {
- dev_warn(dev, "No dts node, EEPROM access disabled");
- idt_set_defval(pdev);
+ pdev->inieecmd = EEPROM_USA;
+ pdev->eeaddr = eeprom_addr << 1;
}
-}
-#else
-static void idt_get_ofdata(struct idt_89hpesx_dev *pdev)
-{
- struct device *dev = &pdev->client->dev;
- dev_warn(dev, "OF table is unsupported, EEPROM access disabled");
+ /* Check EEPROM 'read-only' flag */
+ if (fwnode_property_read_bool(fwnode, "read-only"))
+ pdev->eero = true;
+ else /* if (!fwnode_property_read_bool(node, "read-only")) */
+ pdev->eero = false;
- /* Nothing we can do, just set the default values */
- idt_set_defval(pdev);
+ dev_info(dev, "EEPROM of %d bytes found by 0x%x",
+ pdev->eesize, pdev->eeaddr);
}
-#endif /* CONFIG_OF */
/*
* idt_create_pdev() - create and init data structure of the driver
@@ -1203,8 +1187,8 @@ static struct idt_89hpesx_dev *idt_create_pdev(struct i2c_client *client)
pdev->client = client;
i2c_set_clientdata(client, pdev);
- /* Read OF nodes information */
- idt_get_ofdata(pdev);
+ /* Read firmware nodes information */
+ idt_get_fw_data(pdev);
/* Initialize basic CSR CMD field - use full DWORD-sized r/w ops */
pdev->inicsrcmd = CSR_DWE;
diff --git a/drivers/misc/eeprom/max6875.c b/drivers/misc/eeprom/max6875.c
index e4dd93b2518c..0e32709d1022 100644
--- a/drivers/misc/eeprom/max6875.c
+++ b/drivers/misc/eeprom/max6875.c
@@ -124,7 +124,7 @@ static ssize_t max6875_read(struct file *filp, struct kobject *kobj,
return count;
}
-static struct bin_attribute user_eeprom_attr = {
+static const struct bin_attribute user_eeprom_attr = {
.attr = {
.name = "eeprom",
.mode = S_IRUGO,
diff --git a/drivers/misc/hmc6352.c b/drivers/misc/hmc6352.c
index 90520d76633f..eeb7eef62174 100644
--- a/drivers/misc/hmc6352.c
+++ b/drivers/misc/hmc6352.c
@@ -132,7 +132,7 @@ static int hmc6352_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id hmc6352_id[] = {
+static const struct i2c_device_id hmc6352_id[] = {
{ "hmc6352", 0 },
{ }
};
diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c
index fea8ff40440f..097e3092c158 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -857,7 +857,7 @@ out:
return error;
}
-static struct pci_device_id ilo_devices[] = {
+static const struct pci_device_id ilo_devices[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB204) },
{ PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3307) },
{ }
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index 8758d033db23..ec0832278170 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -454,7 +454,7 @@ ioc4_remove(struct pci_dev *pdev)
kfree(idd);
}
-static struct pci_device_id ioc4_id_table[] = {
+static const struct pci_device_id ioc4_id_table[] = {
{PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
{0}
diff --git a/drivers/misc/isl29020.c b/drivers/misc/isl29020.c
index 4a9c50a43afb..e3bd3c1d2574 100644
--- a/drivers/misc/isl29020.c
+++ b/drivers/misc/isl29020.c
@@ -145,7 +145,7 @@ static struct attribute *mid_att_als[] = {
NULL
};
-static struct attribute_group m_als_gr = {
+static const struct attribute_group m_als_gr = {
.name = "isl29020",
.attrs = mid_att_als
};
@@ -188,7 +188,7 @@ static int isl29020_remove(struct i2c_client *client)
return 0;
}
-static struct i2c_device_id isl29020_id[] = {
+static const struct i2c_device_id isl29020_id[] = {
{ "isl29020", 0 },
{ }
};
diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c
index e389b0b5278d..8d53609861d8 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d.c
@@ -856,7 +856,7 @@ static struct attribute *lis3lv02d_attributes[] = {
NULL
};
-static struct attribute_group lis3lv02d_attribute_group = {
+static const struct attribute_group lis3lv02d_attribute_group = {
.attrs = lis3lv02d_attributes
};
diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h
index 3b4976396ec4..bfb6c45b6130 100644
--- a/drivers/misc/lkdtm.h
+++ b/drivers/misc/lkdtm.h
@@ -14,20 +14,17 @@ void lkdtm_EXCEPTION(void);
void lkdtm_LOOP(void);
void lkdtm_OVERFLOW(void);
void lkdtm_CORRUPT_STACK(void);
+void lkdtm_CORRUPT_STACK_STRONG(void);
void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void);
void lkdtm_SOFTLOCKUP(void);
void lkdtm_HARDLOCKUP(void);
void lkdtm_SPINLOCKUP(void);
void lkdtm_HUNG_TASK(void);
-void lkdtm_REFCOUNT_SATURATE_INC(void);
-void lkdtm_REFCOUNT_SATURATE_ADD(void);
-void lkdtm_REFCOUNT_ZERO_DEC(void);
-void lkdtm_REFCOUNT_ZERO_INC(void);
-void lkdtm_REFCOUNT_ZERO_SUB(void);
-void lkdtm_REFCOUNT_ZERO_ADD(void);
void lkdtm_CORRUPT_LIST_ADD(void);
void lkdtm_CORRUPT_LIST_DEL(void);
void lkdtm_CORRUPT_USER_DS(void);
+void lkdtm_STACK_GUARD_PAGE_LEADING(void);
+void lkdtm_STACK_GUARD_PAGE_TRAILING(void);
/* lkdtm_heap.c */
void lkdtm_OVERWRITE_ALLOCATION(void);
@@ -49,6 +46,27 @@ void lkdtm_EXEC_RODATA(void);
void lkdtm_EXEC_USERSPACE(void);
void lkdtm_ACCESS_USERSPACE(void);
+/* lkdtm_refcount.c */
+void lkdtm_REFCOUNT_INC_OVERFLOW(void);
+void lkdtm_REFCOUNT_ADD_OVERFLOW(void);
+void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void);
+void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void);
+void lkdtm_REFCOUNT_DEC_ZERO(void);
+void lkdtm_REFCOUNT_DEC_NEGATIVE(void);
+void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void);
+void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void);
+void lkdtm_REFCOUNT_INC_ZERO(void);
+void lkdtm_REFCOUNT_ADD_ZERO(void);
+void lkdtm_REFCOUNT_INC_SATURATED(void);
+void lkdtm_REFCOUNT_DEC_SATURATED(void);
+void lkdtm_REFCOUNT_ADD_SATURATED(void);
+void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void);
+void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void);
+void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void);
+void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void);
+void lkdtm_REFCOUNT_TIMING(void);
+void lkdtm_ATOMIC_TIMING(void);
+
/* lkdtm_rodata.c */
void lkdtm_rodata_do_nothing(void);
diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c
index d9028ef50fbe..9e0b4f959987 100644
--- a/drivers/misc/lkdtm_bugs.c
+++ b/drivers/misc/lkdtm_bugs.c
@@ -6,9 +6,9 @@
*/
#include "lkdtm.h"
#include <linux/list.h>
-#include <linux/refcount.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
+#include <linux/sched/task_stack.h>
#include <linux/uaccess.h>
struct lkdtm_list {
@@ -85,16 +85,31 @@ void lkdtm_OVERFLOW(void)
static noinline void __lkdtm_CORRUPT_STACK(void *stack)
{
- memset(stack, 'a', 64);
+ memset(stack, '\xff', 64);
}
+/* This should trip the stack canary, not corrupt the return address. */
noinline void lkdtm_CORRUPT_STACK(void)
{
/* Use default char array length that triggers stack protection. */
- char data[8];
+ char data[8] __aligned(sizeof(void *));
+
+ __lkdtm_CORRUPT_STACK(&data);
+
+ pr_info("Corrupted stack containing char array ...\n");
+}
+
+/* Same as above but will only get a canary with -fstack-protector-strong */
+noinline void lkdtm_CORRUPT_STACK_STRONG(void)
+{
+ union {
+ unsigned short shorts[4];
+ unsigned long *ptr;
+ } data __aligned(sizeof(void *));
+
__lkdtm_CORRUPT_STACK(&data);
- pr_info("Corrupted stack with '%16s'...\n", data);
+ pr_info("Corrupted stack containing union ...\n");
}
void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void)
@@ -137,88 +152,6 @@ void lkdtm_HUNG_TASK(void)
schedule();
}
-void lkdtm_REFCOUNT_SATURATE_INC(void)
-{
- refcount_t over = REFCOUNT_INIT(UINT_MAX - 1);
-
- pr_info("attempting good refcount decrement\n");
- refcount_dec(&over);
- refcount_inc(&over);
-
- pr_info("attempting bad refcount inc overflow\n");
- refcount_inc(&over);
- refcount_inc(&over);
- if (refcount_read(&over) == UINT_MAX)
- pr_err("Correctly stayed saturated, but no BUG?!\n");
- else
- pr_err("Fail: refcount wrapped\n");
-}
-
-void lkdtm_REFCOUNT_SATURATE_ADD(void)
-{
- refcount_t over = REFCOUNT_INIT(UINT_MAX - 1);
-
- pr_info("attempting good refcount decrement\n");
- refcount_dec(&over);
- refcount_inc(&over);
-
- pr_info("attempting bad refcount add overflow\n");
- refcount_add(2, &over);
- if (refcount_read(&over) == UINT_MAX)
- pr_err("Correctly stayed saturated, but no BUG?!\n");
- else
- pr_err("Fail: refcount wrapped\n");
-}
-
-void lkdtm_REFCOUNT_ZERO_DEC(void)
-{
- refcount_t zero = REFCOUNT_INIT(1);
-
- pr_info("attempting bad refcount decrement to zero\n");
- refcount_dec(&zero);
- if (refcount_read(&zero) == 0)
- pr_err("Stayed at zero, but no BUG?!\n");
- else
- pr_err("Fail: refcount went crazy\n");
-}
-
-void lkdtm_REFCOUNT_ZERO_SUB(void)
-{
- refcount_t zero = REFCOUNT_INIT(1);
-
- pr_info("attempting bad refcount subtract past zero\n");
- if (!refcount_sub_and_test(2, &zero))
- pr_info("wrap attempt was noticed\n");
- if (refcount_read(&zero) == 1)
- pr_err("Correctly stayed above 0, but no BUG?!\n");
- else
- pr_err("Fail: refcount wrapped\n");
-}
-
-void lkdtm_REFCOUNT_ZERO_INC(void)
-{
- refcount_t zero = REFCOUNT_INIT(0);
-
- pr_info("attempting bad refcount increment from zero\n");
- refcount_inc(&zero);
- if (refcount_read(&zero) == 0)
- pr_err("Stayed at zero, but no BUG?!\n");
- else
- pr_err("Fail: refcount went past zero\n");
-}
-
-void lkdtm_REFCOUNT_ZERO_ADD(void)
-{
- refcount_t zero = REFCOUNT_INIT(0);
-
- pr_info("attempting bad refcount addition from zero\n");
- refcount_add(2, &zero);
- if (refcount_read(&zero) == 0)
- pr_err("Stayed at zero, but no BUG?!\n");
- else
- pr_err("Fail: refcount went past zero\n");
-}
-
void lkdtm_CORRUPT_LIST_ADD(void)
{
/*
@@ -282,6 +215,7 @@ void lkdtm_CORRUPT_LIST_DEL(void)
pr_err("list_del() corruption not detected!\n");
}
+/* Test if unbalanced set_fs(KERNEL_DS)/set_fs(USER_DS) check exists. */
void lkdtm_CORRUPT_USER_DS(void)
{
pr_info("setting bad task size limit\n");
@@ -290,3 +224,31 @@ void lkdtm_CORRUPT_USER_DS(void)
/* Make sure we do not keep running with a KERNEL_DS! */
force_sig(SIGKILL, current);
}
+
+/* Test that VMAP_STACK is actually allocating with a leading guard page */
+void lkdtm_STACK_GUARD_PAGE_LEADING(void)
+{
+ const unsigned char *stack = task_stack_page(current);
+ const unsigned char *ptr = stack - 1;
+ volatile unsigned char byte;
+
+ pr_info("attempting bad read from page below current stack\n");
+
+ byte = *ptr;
+
+ pr_err("FAIL: accessed page before stack!\n");
+}
+
+/* Test that VMAP_STACK is actually allocating with a trailing guard page */
+void lkdtm_STACK_GUARD_PAGE_TRAILING(void)
+{
+ const unsigned char *stack = task_stack_page(current);
+ const unsigned char *ptr = stack + THREAD_SIZE;
+ volatile unsigned char byte;
+
+ pr_info("attempting bad read from page above current stack\n");
+
+ byte = *ptr;
+
+ pr_err("FAIL: accessed page after stack!\n");
+}
diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c
index 42d2b8e31e6b..981b3ef71e47 100644
--- a/drivers/misc/lkdtm_core.c
+++ b/drivers/misc/lkdtm_core.c
@@ -201,6 +201,9 @@ struct crashtype crashtypes[] = {
CRASHTYPE(CORRUPT_LIST_DEL),
CRASHTYPE(CORRUPT_USER_DS),
CRASHTYPE(CORRUPT_STACK),
+ CRASHTYPE(CORRUPT_STACK_STRONG),
+ CRASHTYPE(STACK_GUARD_PAGE_LEADING),
+ CRASHTYPE(STACK_GUARD_PAGE_TRAILING),
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
CRASHTYPE(OVERWRITE_ALLOCATION),
CRASHTYPE(WRITE_AFTER_FREE),
@@ -221,12 +224,25 @@ struct crashtype crashtypes[] = {
CRASHTYPE(WRITE_RO),
CRASHTYPE(WRITE_RO_AFTER_INIT),
CRASHTYPE(WRITE_KERN),
- CRASHTYPE(REFCOUNT_SATURATE_INC),
- CRASHTYPE(REFCOUNT_SATURATE_ADD),
- CRASHTYPE(REFCOUNT_ZERO_DEC),
- CRASHTYPE(REFCOUNT_ZERO_INC),
- CRASHTYPE(REFCOUNT_ZERO_SUB),
- CRASHTYPE(REFCOUNT_ZERO_ADD),
+ CRASHTYPE(REFCOUNT_INC_OVERFLOW),
+ CRASHTYPE(REFCOUNT_ADD_OVERFLOW),
+ CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW),
+ CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_OVERFLOW),
+ CRASHTYPE(REFCOUNT_DEC_ZERO),
+ CRASHTYPE(REFCOUNT_DEC_NEGATIVE),
+ CRASHTYPE(REFCOUNT_DEC_AND_TEST_NEGATIVE),
+ CRASHTYPE(REFCOUNT_SUB_AND_TEST_NEGATIVE),
+ CRASHTYPE(REFCOUNT_INC_ZERO),
+ CRASHTYPE(REFCOUNT_ADD_ZERO),
+ CRASHTYPE(REFCOUNT_INC_SATURATED),
+ CRASHTYPE(REFCOUNT_DEC_SATURATED),
+ CRASHTYPE(REFCOUNT_ADD_SATURATED),
+ CRASHTYPE(REFCOUNT_INC_NOT_ZERO_SATURATED),
+ CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_SATURATED),
+ CRASHTYPE(REFCOUNT_DEC_AND_TEST_SATURATED),
+ CRASHTYPE(REFCOUNT_SUB_AND_TEST_SATURATED),
+ CRASHTYPE(REFCOUNT_TIMING),
+ CRASHTYPE(ATOMIC_TIMING),
CRASHTYPE(USERCOPY_HEAP_SIZE_TO),
CRASHTYPE(USERCOPY_HEAP_SIZE_FROM),
CRASHTYPE(USERCOPY_HEAP_FLAG_TO),
diff --git a/drivers/misc/lkdtm_refcount.c b/drivers/misc/lkdtm_refcount.c
new file mode 100644
index 000000000000..2b99d448e7fd
--- /dev/null
+++ b/drivers/misc/lkdtm_refcount.c
@@ -0,0 +1,400 @@
+/*
+ * This is for all the tests related to refcount bugs (e.g. overflow,
+ * underflow, reaching zero untested, etc).
+ */
+#include "lkdtm.h"
+#include <linux/refcount.h>
+
+#ifdef CONFIG_REFCOUNT_FULL
+#define REFCOUNT_MAX (UINT_MAX - 1)
+#define REFCOUNT_SATURATED UINT_MAX
+#else
+#define REFCOUNT_MAX INT_MAX
+#define REFCOUNT_SATURATED (INT_MIN / 2)
+#endif
+
+static void overflow_check(refcount_t *ref)
+{
+ switch (refcount_read(ref)) {
+ case REFCOUNT_SATURATED:
+ pr_info("Overflow detected: saturated\n");
+ break;
+ case REFCOUNT_MAX:
+ pr_warn("Overflow detected: unsafely reset to max\n");
+ break;
+ default:
+ pr_err("Fail: refcount wrapped to %d\n", refcount_read(ref));
+ }
+}
+
+/*
+ * A refcount_inc() above the maximum value of the refcount implementation,
+ * should at least saturate, and at most also WARN.