summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJorgen Lundman <[email protected]>2020-06-18 06:30:03 +0900
committerGitHub <[email protected]>2020-06-17 14:30:03 -0700
commit4458157beecdf892a596bf8a61a958ebc492f0b3 (patch)
tree73fba19d7546bd38cfb202ada9e8140a3575bd9c
parent17ca30185af139588b9617ca0bdbf57027bd3303 (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.c25
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);
}