catalinv-ncc opened a new issue, #19473:
URL: https://github.com/apache/nuttx/issues/19473
### Description / Steps to reproduce the issue
# Impact
If user passes `NULL` as buffer, the driver may crash. This is problematic
for NuttX protected and kernel builds.
# Description
The attacker from user space can pass a null pointer (or a pointer that is
not in user space) to the EEPROM read operation. As seen from the code below,
there are no checks for `buffer`. The `I2C_TRANSFER` operation is called with
`msgs[1].buffer` that could be `NULL`:
~~~c
static ssize_t ee24xx_read(FAR struct file *filep, [[[[FAR char *buffer]]]],
size_t len)
{
FAR struct ee24xx_dev_s *eedev;
FAR struct inode *inode = filep->f_inode;
[[[[struct i2c_msg_s msgs[2];]]]]
uint8_t addr[2];
uint32_t addr_hi;
int ret;
....
/* Write data address */
finfo("READ %zu bytes at pos %" PRIdOFF "\n", len, filep->f_pos);
addr_hi = (filep->f_pos >> (eedev->addrlen << 3));
addr[0] = (filep->f_pos) >> 8;
addr[1] = (filep->f_pos) & 0xff;
msgs[0].frequency = eedev->freq;
msgs[0].addr = eedev->addr |
(addr_hi & ((1 << eedev->haddrbits) - 1));
msgs[0].flags = 0;
msgs[0].buffer = eedev->addrlen == 2 ? &addr[0] : &addr[1];
msgs[0].length = eedev->addrlen;
/* Read data */
msgs[1].frequency = msgs[0].frequency;
msgs[1].addr = msgs[0].addr;
msgs[1].flags = I2C_M_READ;
[[[[msgs[1].buffer = (FAR uint8_t *)buffer;]]]]
msgs[1].length = len;
ret = I2C_TRANSFER(eedev->i2c, [[[[msgs]]]], 2);
if (ret < 0)
{
goto done;
}
...
}
~~~
For brevity the call stack (which is quite complex) is not presented in this
finding. The `I2C_TRANSFER` call maps to different functions, depending on the
hardware device. We were able to identify 15 such instances:
| Filename | Function Name |
| :-: | :--- |
| arch/arm/src/stm32/stm32_i2c.c | stm32_i2c_transfer()|
| arch/arm/src/stm32f7/stm32_i2c.c | stm32_i2c_transfer() |
| arch/arm/src/stm32h7/stm32_i2c.c | stm32_i2c_transfer() |
| arch/arm/src/stm32l4/stm32_i2c.c | stm32_i2c_transfer() |
| arch/arm/src/rp2040/rp2040_i2c.c | rp2040_i2c_transfer() |
| arch/arm/src/nrf52/nrf52_i2c.c | nrf52_i2c_transfer() |
| arch/sparc/src/cxd56xx/cxd56_i2c.c | cxd56_i2c_transfer() |
| arch/riscv/src/bl602/bl602_i2c.c | bl602_i2c_transfer() |
| arch/arm/src/efm32/efm32_i2c.c | efm32_i2c_transfer() |
| arch/arm/src/lpc17xx_40xx/lpc17_40_i2c.c | lpc17_40_i2c_transfer() |
| arch/arm/src/tiva/tiva_i2c.c | tiva_i2c_transfer() |
| arch/arm/src/max326xx/max326_i2c.c | max326_i2c_transfer() |
| arch/arm/src/s32k1xx/s32k1xx_lpi2c.c | s32k1xx_lpi2c_transfer() |
| arch/arm/src/samv7/sam_twi.c | sam_twi_transfer() |
| arch/arm/src/sam34/sam_twi.c | sam_twi_transfer() |
| arch/arm/src/imxrt/imxrt_lpi2c.c | imxrt_lpi2c_transfer() |
Looking at the last example, function `imxrt_lpi2c_transfer()`, we can see
that an invalid pointer can cause of crash:
~~~c
struct stm32_i2c_priv_s
{
...
uint8_t msgc; /* Message count */
[[[[struct i2c_msg_s *msgv; /* Message list */]]]]
...
uint32_t status; /* End of transfer SR2|SR1 status */
};
static int imxrt_lpi2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s
*[[[[msgs]]]], int count)
{
...
priv->msgv = [[[[msgs]]]];
...
for (m = 0; m < count; m++)
{
if (msgs[m].flags & I2C_M_READ)
{
up_invalidate_dcache([[[[(uintptr_t)msgs[m].buffer]]]],
[[[[(uintptr_t)msgs[m].buffer +
msgs[m].length]]]]);
}
}
...
}
~~~
Subsequently, `up_invalidate_dcache()` calls `xcache_op_by_range()` which
will write at destination address `0`, likely causing a crash due to
segmentation fault.
# Recommendation
Verify that the `buffer` value passed by the user in the read() operation is
not NULL, and the pointer resides in user space.
### On which OS does this issue occur?
[OS: Linux]
### What is the version of your OS?
Ubuntu 24.04
### NuttX Version
master
### Issue Architecture
[Arch: all]
### Issue Area
[Area: Drivers]
### Host information
_No response_
### Verification
- [x] I have verified before submitting the report.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]