mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
Merge branch 'pci/sysfs'
- In pci_write_legacy_io(), avoid out-of-bounds reads from the user buffer and fix incorrect ioport write data (1-byte writes on little-endian powerpc, 2- and 4-byte writes on big-endian powerpc) (Krzysztof Wilczyński) - In pci_read_legacy_io(), fix incorrect ioport read data for 2- and 4-byte reads on big-endian powerpc (Krzysztof Wilczyński) - Fix I/O port accessor argument order in Alpha pci_legacy_write() (Krzysztof Wilczyński) - Avoid spurious runtime PM wakeup on config space accesses that are outside config space and fail before reaching PCI (Krzysztof Wilczyński) - Return -EINVAL, not -ENODEV, for mmap of I/O BAR that fails because the arch doesn't support it, as we do for procfs (Krzysztof Wilczyński) - Check for LOCKDOWN_PCI_ACCESS for legacy_io and legacy_mem, as we do for other config space accessors (Krzysztof Wilczyński) - Tidy static resource attribute names and macros that build them (Krzysztof Wilczyński) * pci/sysfs: PCI/sysfs: Add legacy I/O and memory attribute macros alpha/PCI: Make the suffix the first __pci_dev_resource_attr() parameter PCI/sysfs: Add pci_ prefix to static PCI resource attribute names PCI/sysfs: Add lockdown checks to legacy I/O and memory handlers PCI/sysfs: Return -EINVAL for unsupported I/O BAR mmap PCI/sysfs: Avoid spurious runtime PM wakeup on config space accesses alpha/PCI: Fix I/O port accessor argument order in pci_legacy_write() PCI/sysfs: Fix read byte order in pci_read_legacy_io() PCI/sysfs: Fix out-of-bounds read in pci_write_legacy_io()
This commit is contained in:
commit
c1a7b1aad5
|
|
@ -102,25 +102,25 @@ static int pci_mmap_resource_dense(struct file *filp, struct kobject *kobj,
|
|||
return pci_mmap_resource(kobj, attr, vma, 0);
|
||||
}
|
||||
|
||||
#define __pci_dev_resource_attr(_bar, _name, _suffix, _mmap) \
|
||||
static const struct bin_attribute \
|
||||
pci_dev_resource##_bar##_suffix##_attr = { \
|
||||
.attr = { .name = __stringify(_name), .mode = 0600 }, \
|
||||
.private = (void *)(unsigned long)(_bar), \
|
||||
.mmap = (_mmap), \
|
||||
#define __pci_dev_resource_attr(_suffix, _bar, _name, _mmap) \
|
||||
static const struct bin_attribute \
|
||||
pci_dev_resource##_bar##_suffix##_attr = { \
|
||||
.attr = { .name = __stringify(_name), .mode = 0600 }, \
|
||||
.private = (void *)(unsigned long)(_bar), \
|
||||
.mmap = (_mmap), \
|
||||
}
|
||||
|
||||
#define pci_dev_resource_attr(_bar) \
|
||||
__pci_dev_resource_attr(_bar, resource##_bar,, \
|
||||
pci_mmap_resource_dense)
|
||||
#define pci_dev_resource_attr(_bar) \
|
||||
__pci_dev_resource_attr(, _bar, resource##_bar, \
|
||||
pci_mmap_resource_dense)
|
||||
|
||||
#define pci_dev_resource_sparse_attr(_bar) \
|
||||
__pci_dev_resource_attr(_bar, resource##_bar##_sparse, _sparse, \
|
||||
pci_mmap_resource_sparse)
|
||||
__pci_dev_resource_attr(_sparse, _bar, resource##_bar##_sparse, \
|
||||
pci_mmap_resource_sparse)
|
||||
|
||||
#define pci_dev_resource_dense_attr(_bar) \
|
||||
__pci_dev_resource_attr(_bar, resource##_bar##_dense, _dense, \
|
||||
pci_mmap_resource_dense)
|
||||
__pci_dev_resource_attr(_dense, _bar, resource##_bar##_dense, \
|
||||
pci_mmap_resource_dense)
|
||||
|
||||
static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
|
||||
{
|
||||
|
|
@ -224,17 +224,17 @@ int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
|
|||
|
||||
switch(size) {
|
||||
case 1:
|
||||
outb(port, val);
|
||||
outb(val, port);
|
||||
return 1;
|
||||
case 2:
|
||||
if (port & 1)
|
||||
return -EINVAL;
|
||||
outw(port, val);
|
||||
outw(val, port);
|
||||
return 2;
|
||||
case 4:
|
||||
if (port & 3)
|
||||
return -EINVAL;
|
||||
outl(port, val);
|
||||
outl(val, port);
|
||||
return 4;
|
||||
}
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -626,19 +626,14 @@ int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
|
|||
return -ENXIO;
|
||||
addr = hose->io_base_virt + port;
|
||||
|
||||
/* WARNING: The generic code is idiotic. It gets passed a pointer
|
||||
* to what can be a 1, 2 or 4 byte quantity and always reads that
|
||||
* as a u32, which means that we have to correct the location of
|
||||
* the data read within those 32 bits for size 1 and 2
|
||||
*/
|
||||
switch(size) {
|
||||
case 1:
|
||||
out_8(addr, val >> 24);
|
||||
out_8(addr, val);
|
||||
return 1;
|
||||
case 2:
|
||||
if (port & 1)
|
||||
return -EINVAL;
|
||||
out_le16(addr, val >> 16);
|
||||
out_le16(addr, val);
|
||||
return 2;
|
||||
case 4:
|
||||
if (port & 3)
|
||||
|
|
|
|||
|
|
@ -718,7 +718,7 @@ static ssize_t pci_read_config(struct file *filp, struct kobject *kobj,
|
|||
else if (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
|
||||
size = 128;
|
||||
|
||||
if (off > size)
|
||||
if (off >= size)
|
||||
return 0;
|
||||
if (off + count > size) {
|
||||
size -= off;
|
||||
|
|
@ -799,7 +799,7 @@ static ssize_t pci_write_config(struct file *filp, struct kobject *kobj,
|
|||
add_taint(TAINT_USER, LOCKDEP_STILL_OK);
|
||||
}
|
||||
|
||||
if (off > dev->cfg_size)
|
||||
if (off >= dev->cfg_size)
|
||||
return 0;
|
||||
if (off + count > dev->cfg_size) {
|
||||
size = dev->cfg_size - off;
|
||||
|
|
@ -871,6 +871,27 @@ static const struct attribute_group pci_dev_config_attr_group = {
|
|||
};
|
||||
|
||||
#ifdef HAVE_PCI_LEGACY
|
||||
|
||||
#define pci_legacy_resource_io_attr(_suffix, _size) \
|
||||
static const struct bin_attribute pci_legacy_io##_suffix##_attr = { \
|
||||
.attr = { .name = "legacy_io" __stringify(_suffix), .mode = 0600 }, \
|
||||
.size = (_size), \
|
||||
.read = pci_read_legacy_io, \
|
||||
.write = pci_write_legacy_io, \
|
||||
.f_mapping = iomem_get_mapping, \
|
||||
.llseek = pci_llseek_resource_legacy, \
|
||||
.mmap = pci_mmap_legacy_io, \
|
||||
}
|
||||
|
||||
#define pci_legacy_resource_mem_attr(_suffix, _size) \
|
||||
static const struct bin_attribute pci_legacy_mem##_suffix##_attr = { \
|
||||
.attr = { .name = "legacy_mem" __stringify(_suffix), .mode = 0600 }, \
|
||||
.size = (_size), \
|
||||
.f_mapping = iomem_get_mapping, \
|
||||
.llseek = pci_llseek_resource_legacy, \
|
||||
.mmap = pci_mmap_legacy_mem, \
|
||||
}
|
||||
|
||||
/**
|
||||
* pci_read_legacy_io - read byte(s) from legacy I/O port space
|
||||
* @filp: open sysfs file
|
||||
|
|
@ -888,12 +909,30 @@ static ssize_t pci_read_legacy_io(struct file *filp, struct kobject *kobj,
|
|||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
||||
u32 val = 0;
|
||||
int ret;
|
||||
|
||||
/* Only support 1, 2 or 4 byte accesses */
|
||||
if (count != 1 && count != 2 && count != 4)
|
||||
return -EINVAL;
|
||||
|
||||
return pci_legacy_read(bus, off, (u32 *)buf, count);
|
||||
ret = pci_legacy_read(bus, off, &val, count);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (count) {
|
||||
case 1:
|
||||
buf[0] = *(u8 *)&val;
|
||||
break;
|
||||
case 2:
|
||||
put_unaligned_le16(*(u16 *)&val, buf);
|
||||
break;
|
||||
case 4:
|
||||
put_unaligned_le32(val, buf);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -913,12 +952,24 @@ static ssize_t pci_write_legacy_io(struct file *filp, struct kobject *kobj,
|
|||
char *buf, loff_t off, size_t count)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
||||
u32 val;
|
||||
|
||||
/* Only support 1, 2 or 4 byte accesses */
|
||||
if (count != 1 && count != 2 && count != 4)
|
||||
/* Only support 1, 2 or 4 byte accesses. */
|
||||
switch (count) {
|
||||
case 1:
|
||||
val = *(u8 *)buf;
|
||||
break;
|
||||
case 2:
|
||||
val = get_unaligned_le16(buf);
|
||||
break;
|
||||
case 4:
|
||||
val = get_unaligned_le32(buf);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return pci_legacy_write(bus, off, *(u32 *)buf, count);
|
||||
return pci_legacy_write(bus, off, val, count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -937,6 +988,11 @@ static int pci_mmap_legacy_mem(struct file *filp, struct kobject *kobj,
|
|||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
||||
int ret;
|
||||
|
||||
ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return pci_mmap_legacy_page_range(bus, vma, pci_mmap_mem);
|
||||
}
|
||||
|
|
@ -957,6 +1013,11 @@ static int pci_mmap_legacy_io(struct file *filp, struct kobject *kobj,
|
|||
struct vm_area_struct *vma)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
||||
int ret;
|
||||
|
||||
ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return pci_mmap_legacy_page_range(bus, vma, pci_mmap_io);
|
||||
}
|
||||
|
|
@ -973,6 +1034,11 @@ static inline umode_t __pci_legacy_is_visible(struct kobject *kobj,
|
|||
bool sparse)
|
||||
{
|
||||
struct pci_bus *bus = to_pci_bus(kobj_to_dev(kobj));
|
||||
int ret;
|
||||
|
||||
ret = security_locked_down(LOCKDOWN_PCI_ACCESS);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (pci_legacy_has_sparse(bus, type) != sparse)
|
||||
return 0;
|
||||
|
|
@ -1014,41 +1080,11 @@ static loff_t pci_llseek_resource_legacy(struct file *filep,
|
|||
return fixed_size_llseek(filep, offset, whence, attr->size);
|
||||
}
|
||||
|
||||
static const struct bin_attribute pci_legacy_io_attr = {
|
||||
.attr = { .name = "legacy_io", .mode = 0600 },
|
||||
.size = PCI_LEGACY_IO_SIZE,
|
||||
.read = pci_read_legacy_io,
|
||||
.write = pci_write_legacy_io,
|
||||
.mmap = pci_mmap_legacy_io,
|
||||
.llseek = pci_llseek_resource_legacy,
|
||||
.f_mapping = iomem_get_mapping,
|
||||
};
|
||||
pci_legacy_resource_io_attr(, PCI_LEGACY_IO_SIZE);
|
||||
pci_legacy_resource_io_attr(_sparse, PCI_LEGACY_IO_SIZE << 5);
|
||||
|
||||
static const struct bin_attribute pci_legacy_io_sparse_attr = {
|
||||
.attr = { .name = "legacy_io_sparse", .mode = 0600 },
|
||||
.size = PCI_LEGACY_IO_SIZE << 5,
|
||||
.read = pci_read_legacy_io,
|
||||
.write = pci_write_legacy_io,
|
||||
.mmap = pci_mmap_legacy_io,
|
||||
.llseek = pci_llseek_resource_legacy,
|
||||
.f_mapping = iomem_get_mapping,
|
||||
};
|
||||
|
||||
static const struct bin_attribute pci_legacy_mem_attr = {
|
||||
.attr = { .name = "legacy_mem", .mode = 0600 },
|
||||
.size = PCI_LEGACY_MEM_SIZE,
|
||||
.mmap = pci_mmap_legacy_mem,
|
||||
.llseek = pci_llseek_resource_legacy,
|
||||
.f_mapping = iomem_get_mapping,
|
||||
};
|
||||
|
||||
static const struct bin_attribute pci_legacy_mem_sparse_attr = {
|
||||
.attr = { .name = "legacy_mem_sparse", .mode = 0600 },
|
||||
.size = PCI_LEGACY_MEM_SIZE << 5,
|
||||
.mmap = pci_mmap_legacy_mem,
|
||||
.llseek = pci_llseek_resource_legacy,
|
||||
.f_mapping = iomem_get_mapping,
|
||||
};
|
||||
pci_legacy_resource_mem_attr(, PCI_LEGACY_MEM_SIZE);
|
||||
pci_legacy_resource_mem_attr(_sparse, PCI_LEGACY_MEM_SIZE << 5);
|
||||
|
||||
static const struct bin_attribute *const pci_legacy_io_attrs[] = {
|
||||
&pci_legacy_io_attr,
|
||||
|
|
@ -1239,16 +1275,25 @@ static loff_t pci_llseek_resource(struct file *filep,
|
|||
* attribute, it's not going to work, so override it as well.
|
||||
*/
|
||||
#if arch_can_pci_mmap_io()
|
||||
# define __PCI_RESOURCE_IO_MMAP_ATTRS \
|
||||
.f_mapping = iomem_get_mapping, \
|
||||
.llseek = pci_llseek_resource, \
|
||||
# define __PCI_RESOURCE_IO_MMAP_ATTRS \
|
||||
.f_mapping = iomem_get_mapping, \
|
||||
.llseek = pci_llseek_resource, \
|
||||
.mmap = pci_mmap_resource_uc,
|
||||
#else
|
||||
# define __PCI_RESOURCE_IO_MMAP_ATTRS
|
||||
static int pci_mmap_resource_io_unsupported(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
const struct bin_attribute *attr,
|
||||
struct vm_area_struct *vma)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
# define __PCI_RESOURCE_IO_MMAP_ATTRS \
|
||||
.mmap = pci_mmap_resource_io_unsupported,
|
||||
#endif
|
||||
|
||||
#define pci_dev_resource_io_attr(_bar) \
|
||||
static const struct bin_attribute dev_resource##_bar##_io_attr = { \
|
||||
static const struct bin_attribute pci_dev_resource##_bar##_io_attr = { \
|
||||
.attr = { .name = "resource" __stringify(_bar), .mode = 0600 }, \
|
||||
.private = (void *)(unsigned long)(_bar), \
|
||||
.read = pci_read_resource, \
|
||||
|
|
@ -1257,7 +1302,7 @@ static const struct bin_attribute dev_resource##_bar##_io_attr = { \
|
|||
}
|
||||
|
||||
#define pci_dev_resource_uc_attr(_bar) \
|
||||
static const struct bin_attribute dev_resource##_bar##_uc_attr = { \
|
||||
static const struct bin_attribute pci_dev_resource##_bar##_uc_attr = { \
|
||||
.attr = { .name = "resource" __stringify(_bar), .mode = 0600 }, \
|
||||
.private = (void *)(unsigned long)(_bar), \
|
||||
.f_mapping = iomem_get_mapping, \
|
||||
|
|
@ -1265,8 +1310,8 @@ static const struct bin_attribute dev_resource##_bar##_uc_attr = { \
|
|||
.mmap = pci_mmap_resource_uc, \
|
||||
}
|
||||
|
||||
#define pci_dev_resource_wc_attr(_bar) \
|
||||
static const struct bin_attribute dev_resource##_bar##_wc_attr = { \
|
||||
#define pci_dev_resource_wc_attr(_bar) \
|
||||
static const struct bin_attribute pci_dev_resource##_bar##_wc_attr = { \
|
||||
.attr = { .name = "resource" __stringify(_bar) "_wc", .mode = 0600 }, \
|
||||
.private = (void *)(unsigned long)(_bar), \
|
||||
.f_mapping = iomem_get_mapping, \
|
||||
|
|
@ -1352,32 +1397,32 @@ pci_dev_resource_wc_attr(4);
|
|||
pci_dev_resource_wc_attr(5);
|
||||
|
||||
static const struct bin_attribute *const pci_dev_resource_io_attrs[] = {
|
||||
&dev_resource0_io_attr,
|
||||
&dev_resource1_io_attr,
|
||||
&dev_resource2_io_attr,
|
||||
&dev_resource3_io_attr,
|
||||
&dev_resource4_io_attr,
|
||||
&dev_resource5_io_attr,
|
||||
&pci_dev_resource0_io_attr,
|
||||
&pci_dev_resource1_io_attr,
|
||||
&pci_dev_resource2_io_attr,
|
||||
&pci_dev_resource3_io_attr,
|
||||
&pci_dev_resource4_io_attr,
|
||||
&pci_dev_resource5_io_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct bin_attribute *const pci_dev_resource_uc_attrs[] = {
|
||||
&dev_resource0_uc_attr,
|
||||
&dev_resource1_uc_attr,
|
||||
&dev_resource2_uc_attr,
|
||||
&dev_resource3_uc_attr,
|
||||
&dev_resource4_uc_attr,
|
||||
&dev_resource5_uc_attr,
|
||||
&pci_dev_resource0_uc_attr,
|
||||
&pci_dev_resource1_uc_attr,
|
||||
&pci_dev_resource2_uc_attr,
|
||||
&pci_dev_resource3_uc_attr,
|
||||
&pci_dev_resource4_uc_attr,
|
||||
&pci_dev_resource5_uc_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct bin_attribute *const pci_dev_resource_wc_attrs[] = {
|
||||
&dev_resource0_wc_attr,
|
||||
&dev_resource1_wc_attr,
|
||||
&dev_resource2_wc_attr,
|
||||
&dev_resource3_wc_attr,
|
||||
&dev_resource4_wc_attr,
|
||||
&dev_resource5_wc_attr,
|
||||
&pci_dev_resource0_wc_attr,
|
||||
&pci_dev_resource1_wc_attr,
|
||||
&pci_dev_resource2_wc_attr,
|
||||
&pci_dev_resource3_wc_attr,
|
||||
&pci_dev_resource4_wc_attr,
|
||||
&pci_dev_resource5_wc_attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user