Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9cac00b8 authored by Stefan Richter's avatar Stefan Richter
Browse files

firewire: cdev: fix information leak



A userspace client got to see uninitialized stack-allocated memory if it
specified an _IOC_READ type of ioctl and an argument size larger than
expected by firewire-core's ioctl handlers (but not larger than the
core's union ioctl_arg).

Fix this by clearing the requested buffer size to zero, but only at _IOR
ioctls.  This way, there is almost no runtime penalty to legitimate
ioctls.  The only legitimate _IOR is FW_CDEV_IOC_GET_CYCLE_TIMER with 12
or 16 bytes to memset.

[Another way to fix this would be strict checking of argument size (and
possibly direction) vs. command number.  However, we then need a lookup
table, and we need to allow for slight size deviations in case of 32bit
userland on 64bit kernel.]

Reported-by: default avatarClemens Ladisch <clemens@ladisch.de>
Signed-off-by: default avatarStefan Richter <stefanr@s5r6.in-berlin.de>
parent 385ab5bc
Loading
Loading
Loading
Loading
+9 −9
Original line number Diff line number Diff line
@@ -1356,24 +1356,24 @@ static int dispatch_ioctl(struct client *client,
		return -ENODEV;

	if (_IOC_TYPE(cmd) != '#' ||
	    _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers))
	    _IOC_NR(cmd) >= ARRAY_SIZE(ioctl_handlers) ||
	    _IOC_SIZE(cmd) > sizeof(buffer))
		return -EINVAL;

	if (_IOC_DIR(cmd) & _IOC_WRITE) {
		if (_IOC_SIZE(cmd) > sizeof(buffer) ||
		    copy_from_user(&buffer, arg, _IOC_SIZE(cmd)))
	if (_IOC_DIR(cmd) == _IOC_READ)
		memset(&buffer, 0, _IOC_SIZE(cmd));

	if (_IOC_DIR(cmd) & _IOC_WRITE)
		if (copy_from_user(&buffer, arg, _IOC_SIZE(cmd)))
			return -EFAULT;
	}

	ret = ioctl_handlers[_IOC_NR(cmd)](client, &buffer);
	if (ret < 0)
		return ret;

	if (_IOC_DIR(cmd) & _IOC_READ) {
		if (_IOC_SIZE(cmd) > sizeof(buffer) ||
		    copy_to_user(arg, &buffer, _IOC_SIZE(cmd)))
	if (_IOC_DIR(cmd) & _IOC_READ)
		if (copy_to_user(arg, &buffer, _IOC_SIZE(cmd)))
			return -EFAULT;
	}

	return ret;
}