summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorse <se@FreeBSD.org>2003-10-11 22:20:34 +0000
committerse <se@FreeBSD.org>2003-10-11 22:20:34 +0000
commit6a55ff3777d67df18d8d315cd2f925b3722db494 (patch)
treeab158dd9e3d330995e61b587d399b5263231a54c
parent5b9cc4b22e6e819a64dfbf8705d2602d2bab874a (diff)
downloadFreeBSD-src-6a55ff3777d67df18d8d315cd2f925b3722db494.zip
FreeBSD-src-6a55ff3777d67df18d8d315cd2f925b3722db494.tar.gz
The code that was meant to test alignment of the register offset
parameter in the read and write case dereferenced an unitialized pointer and can't possibly ever have catched an actual invalid argument. This was apparently true for the read/write and getconf cases. The latter does not even receive the paramter that is to be verified. I'm surprised that this did not cause kernel panics, but it seems that the uninitialized local variable happens to contain data that may be used as a pointer to memory that satisfies the test condition. Make the code work as intended by moving the test inside the switch case where the pointer has been properly initialized. Since the read and write case shared just about all code (except for the single call to PCIB_READ_CONFIG resp. PCIB_WRITE_CONFIG) I have merged both cases. Noticed by: trhodes@FreeBSD.org (Tom Rhodes)
-rw-r--r--sys/dev/pci/pci_user.c70
1 files changed, 24 insertions, 46 deletions
diff --git a/sys/dev/pci/pci_user.c b/sys/dev/pci/pci_user.c
index 80832b2..b816779 100644
--- a/sys/dev/pci/pci_user.c
+++ b/sys/dev/pci/pci_user.c
@@ -179,12 +179,6 @@ pci_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
if (!(flag & FWRITE) && cmd != PCIOCGETCONF)
return EPERM;
- /* make sure register is in bounds and aligned */
- if (cmd == PCIOCREAD || cmd == PCIOCWRITE)
- if (io->pi_reg < 0 || io->pi_reg + io->pi_width > PCI_REGMAX ||
- io->pi_reg & (io->pi_width - 1))
- error = EINVAL;
-
switch(cmd) {
case PCIOCGETCONF:
{
@@ -376,46 +370,21 @@ getconfexit:
break;
}
- case PCIOCREAD:
- io = (struct pci_io *)data;
- switch(io->pi_width) {
- case 4:
- case 2:
- case 1:
- /*
- * Assume that the user-level bus number is
- * actually the pciN instance number. We map
- * from that to the real pcib+bus combination.
- */
- pci = devclass_get_device(devclass_find("pci"),
- io->pi_sel.pc_bus);
- if (pci) {
- int b = pcib_get_bus(pci);
- pcib = device_get_parent(pci);
- io->pi_data =
- PCIB_READ_CONFIG(pcib,
- b,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func,
- io->pi_reg,
- io->pi_width);
- error = 0;
- } else {
- error = ENODEV;
- }
- break;
- default:
- error = EINVAL;
- break;
- }
- break;
+ case PCIOCREAD:
case PCIOCWRITE:
io = (struct pci_io *)data;
switch(io->pi_width) {
case 4:
case 2:
case 1:
+ /* make sure register is in bounds and aligned */
+ if (cmd == PCIOCREAD || cmd == PCIOCWRITE)
+ if (io->pi_reg < 0 ||
+ io->pi_reg + io->pi_width > PCI_REGMAX ||
+ io->pi_reg & (io->pi_width - 1))
+ error = EINVAL;
+
/*
* Assume that the user-level bus number is
* actually the pciN instance number. We map
@@ -426,13 +395,22 @@ getconfexit:
if (pci) {
int b = pcib_get_bus(pci);
pcib = device_get_parent(pci);
- PCIB_WRITE_CONFIG(pcib,
- b,
- io->pi_sel.pc_dev,
- io->pi_sel.pc_func,
- io->pi_reg,
- io->pi_data,
- io->pi_width);
+ if (cmd == PCIOCWRITE)
+ PCIB_WRITE_CONFIG(pcib,
+ b,
+ io->pi_sel.pc_dev,
+ io->pi_sel.pc_func,
+ io->pi_reg,
+ io->pi_data,
+ io->pi_width);
+ else
+ io->pi_data =
+ PCIB_READ_CONFIG(pcib,
+ b,
+ io->pi_sel.pc_dev,
+ io->pi_sel.pc_func,
+ io->pi_reg,
+ io->pi_width);
error = 0;
} else {
error = ENODEV;
OpenPOWER on IntegriCloud