diff options
author | Jorgen Lundman <[email protected]> | 2020-06-18 06:30:03 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2020-06-17 14:30:03 -0700 |
commit | 4458157beecdf892a596bf8a61a958ebc492f0b3 (patch) | |
tree | 73fba19d7546bd38cfb202ada9e8140a3575bd9c | |
parent | 17ca30185af139588b9617ca0bdbf57027bd3303 (diff) |
zfs_ioctl: saved_poolname can be truncated
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
-rw-r--r-- | module/zfs/zfs_ioctl.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 33e1620ec..e98e7af15 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -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; @@ -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; @@ -7562,11 +7565,11 @@ out: 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); } |