Skip to content

Commit 249bed8

Browse files
DemiMarieMike Snitzer
authored andcommitted
dm ioctl: Avoid double-fetch of version
The version is fetched once in check_version(), which then does some validation and then overwrites the version in userspace with the API version supported by the kernel. copy_params() then fetches the version from userspace *again*, and this time no validation is done. The result is that the kernel's version number is completely controllable by userspace, provided that userspace can win a race condition. Fix this flaw by not copying the version back to the kernel the second time. This is not exploitable as the version is not further used in the kernel. However, it could become a problem if future patches start relying on the version field. Cc: [email protected] Signed-off-by: Demi Marie Obenour <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent 10655c7 commit 249bed8

File tree

1 file changed

+21
-12
lines changed

1 file changed

+21
-12
lines changed

drivers/md/dm-ioctl.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,30 +1872,36 @@ static ioctl_fn lookup_ioctl(unsigned int cmd, int *ioctl_flags)
18721872
* As well as checking the version compatibility this always
18731873
* copies the kernel interface version out.
18741874
*/
1875-
static int check_version(unsigned int cmd, struct dm_ioctl __user *user)
1875+
static int check_version(unsigned int cmd, struct dm_ioctl __user *user,
1876+
struct dm_ioctl *kernel_params)
18761877
{
1877-
uint32_t version[3];
18781878
int r = 0;
18791879

1880-
if (copy_from_user(version, user->version, sizeof(version)))
1880+
/* Make certain version is first member of dm_ioctl struct */
1881+
BUILD_BUG_ON(offsetof(struct dm_ioctl, version) != 0);
1882+
1883+
if (copy_from_user(kernel_params->version, user->version, sizeof(kernel_params->version)))
18811884
return -EFAULT;
18821885

1883-
if ((version[0] != DM_VERSION_MAJOR) ||
1884-
(version[1] > DM_VERSION_MINOR)) {
1886+
if ((kernel_params->version[0] != DM_VERSION_MAJOR) ||
1887+
(kernel_params->version[1] > DM_VERSION_MINOR)) {
18851888
DMERR("ioctl interface mismatch: kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
18861889
DM_VERSION_MAJOR, DM_VERSION_MINOR,
18871890
DM_VERSION_PATCHLEVEL,
1888-
version[0], version[1], version[2], cmd);
1891+
kernel_params->version[0],
1892+
kernel_params->version[1],
1893+
kernel_params->version[2],
1894+
cmd);
18891895
r = -EINVAL;
18901896
}
18911897

18921898
/*
18931899
* Fill in the kernel version.
18941900
*/
1895-
version[0] = DM_VERSION_MAJOR;
1896-
version[1] = DM_VERSION_MINOR;
1897-
version[2] = DM_VERSION_PATCHLEVEL;
1898-
if (copy_to_user(user->version, version, sizeof(version)))
1901+
kernel_params->version[0] = DM_VERSION_MAJOR;
1902+
kernel_params->version[1] = DM_VERSION_MINOR;
1903+
kernel_params->version[2] = DM_VERSION_PATCHLEVEL;
1904+
if (copy_to_user(user->version, kernel_params->version, sizeof(kernel_params->version)))
18991905
return -EFAULT;
19001906

19011907
return r;
@@ -1921,7 +1927,10 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl *param_kern
19211927
const size_t minimum_data_size = offsetof(struct dm_ioctl, data);
19221928
unsigned int noio_flag;
19231929

1924-
if (copy_from_user(param_kernel, user, minimum_data_size))
1930+
/* check_version() already copied version from userspace, avoid TOCTOU */
1931+
if (copy_from_user((char *)param_kernel + sizeof(param_kernel->version),
1932+
(char __user *)user + sizeof(param_kernel->version),
1933+
minimum_data_size - sizeof(param_kernel->version)))
19251934
return -EFAULT;
19261935

19271936
if (param_kernel->data_size < minimum_data_size) {
@@ -2033,7 +2042,7 @@ static int ctl_ioctl(struct file *file, uint command, struct dm_ioctl __user *us
20332042
* Check the interface version passed in. This also
20342043
* writes out the kernel's interface version.
20352044
*/
2036-
r = check_version(cmd, user);
2045+
r = check_version(cmd, user, &param_kernel);
20372046
if (r)
20382047
return r;
20392048

0 commit comments

Comments
 (0)