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:
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:
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, done in fs/vfs code to cover multiple code paths.
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
Description / Steps to reproduce the issue
Impact
If user passes
NULLas 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. TheI2C_TRANSFERoperation is called withmsgs[1].bufferthat could beNULL:For brevity the call stack (which is quite complex) is not presented in this finding. The
I2C_TRANSFERcall maps to different functions, depending on the hardware device. We were able to identify 15 such instances:Looking at the last example, function
imxrt_lpi2c_transfer(), we can see that an invalid pointer can cause of crash:Subsequently,
up_invalidate_dcache()callsxcache_op_by_range()which will write at destination address0, likely causing a crash due to segmentation fault.Recommendation
Verify that the
buffervalue passed by the user in the read() operation is not NULL, done in fs/vfs code to cover multiple code paths.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