Skip to contentSkip to conversation

ibmasm: fix OOB reads in command_file_write due to missing size checks

PATCH New Tyllis Xu 1 participant 1 message Mar 14

Subsystems (2)
lore
Share & tools
lore

Tyllis Xu

author
#0 lore raw

PATCH 1/1 ibmasm: fix OOB reads in command_file_write due to missing size checks

The command_file_write() handler allocates a kernel buffer of exactly count bytes and copies user data into it, but does not validate the buffer against the dot command protocol before passing it to get_dot_command_size() and get_dot_command_timeout().

Since both the allocation size (count) and the header fields (command_size, data_size) are independently user-controlled, an attacker can cause get_dot_command_size() to return a value exceeding the allocation, triggering OOB reads in get_dot_command_timeout() and an out-of-bounds memcpy_toio() that leaks kernel heap memory to the service processor.

Fix with two guards: reject writes smaller than sizeof(struct dot_command_header) before allocation, then after copying user data reject commands where the buffer is smaller than the total size declared by the header (sizeof(header) + command_size + data_size). This ensures all subsequent header and payload field accesses stay within the buffer.

Fixes 1da177e4c3f4 ("Linux-2.6.12-rc2")
---
 drivers/misc/ibmasm/ibmasmfs.c | 7 +++++++
 1 file changed, 7 insertions(+)
drivers/misc/ibmasm/ibmasmfs.c +7 -0
index f68a8957b98f..dfdfa9ba4747 100644
@@ -303,6 +303,8 @@ static ssize_t command_file_write(struct file *file, const char __user *ubuff, s
 		return -EINVAL;
 	if (count == 0 || count > IBMASM_CMD_MAX_BUFFER_SIZE)
 		return 0;
+	if (count < sizeof(struct dot_command_header))
+		return -EINVAL;
 	if (*offset != 0)
 		return 0;
 
@@ -319,6 +321,11 @@ static ssize_t command_file_write(struct file *file, const char __user *ubuff, s
 		return -EFAULT;
 	}
 
+	if (count < get_dot_command_size(cmd->buffer)) {
+		command_put(cmd);
+		return -EINVAL;
+	}
+
 	spin_lock_irqsave(&command_data->sp->lock, flags);
 	if (command_data->command) {
 		spin_unlock_irqrestore(&command_data->sp->lock, flags);
Signature · 1 line
2.43.0