Skip to content

Commit

Permalink
zfs_ioctl: saved_poolname can be truncated
Browse files Browse the repository at this point in the history
As it uses kmem_strdup() and kmem_strfree() which both rely on
strlen() being the same, but saved_poolname can be truncated causing:

SPL: kernel memory allocator:
buffer freed to wrong cache
SPL: buffer was allocated from kmem_alloc_16,
SPL: caller attempting free to kmem_alloc_8.
SPL: buffer=0xffffff90acc66a38  bufctl=0x0  cache: kmem_alloc_8

Reviewed-by: Matthew Ahrens <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Jorgen Lundman <[email protected]>
Closes #10469
  • Loading branch information
lundman authored Jun 17, 2020
1 parent 17ca301 commit 4458157
Showing 1 changed file with 14 additions and 11 deletions.
25 changes: 14 additions & 11 deletions module/zfs/zfs_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -7380,6 +7380,7 @@ zfsdev_ioctl_common(uint_t vecnum, zfs_cmd_t *zc, int flag)
int error, cmd;
const zfs_ioc_vec_t *vec;
char *saved_poolname = NULL;
size_t saved_poolname_len = 0;
nvlist_t *innvl = NULL;
fstrans_cookie_t cookie;

Expand Down Expand Up @@ -7479,13 +7480,15 @@ zfsdev_ioctl_common(uint_t vecnum, zfs_cmd_t *zc, int flag)
goto out;

/* legacy ioctls can modify zc_name */
saved_poolname = kmem_strdup(zc->zc_name);
if (saved_poolname == NULL) {
error = SET_ERROR(ENOMEM);
goto out;
} else {
saved_poolname[strcspn(saved_poolname, "/@#")] = '\0';
}
/*
* Can't use kmem_strdup() as we might truncate the string and
* kmem_strfree() would then free with incorrect size.
*/
saved_poolname_len = strlen(zc->zc_name) + 1;
saved_poolname = kmem_alloc(saved_poolname_len, KM_SLEEP);

strlcpy(saved_poolname, zc->zc_name, saved_poolname_len);
saved_poolname[strcspn(saved_poolname, "/@#")] = '\0';

if (vec->zvec_func != NULL) {
nvlist_t *outnvl;
Expand Down Expand Up @@ -7562,11 +7565,11 @@ zfsdev_ioctl_common(uint_t vecnum, zfs_cmd_t *zc, int flag)
char *s = tsd_get(zfs_allow_log_key);
if (s != NULL)
kmem_strfree(s);
(void) tsd_set(zfs_allow_log_key, saved_poolname);
} else {
if (saved_poolname != NULL)
kmem_strfree(saved_poolname);
(void) tsd_set(zfs_allow_log_key, kmem_strdup(saved_poolname));
}
if (saved_poolname != NULL)
kmem_free(saved_poolname, saved_poolname_len);

return (error);
}

Expand Down

0 comments on commit 4458157

Please sign in to comment.