Skip to content

Commit a4ae499

Browse files
Fix memleak in cmd/mount_zfs.c
Convert dynamic allocation to static buffer, simplify parse_dataset function return path. Add tests specific to the mount helper. Reviewed-by: Mateusz Guzik <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Sterling Jensen <[email protected]> Closes #11098
1 parent b60ae3a commit a4ae499

File tree

6 files changed

+177
-43
lines changed

6 files changed

+177
-43
lines changed

cmd/mount_zfs/mount_zfs.c

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -47,63 +47,49 @@ libzfs_handle_t *g_zfs;
4747
* is expected to be of the form pool/dataset, however may also refer to
4848
* a block device if that device contains a valid zfs label.
4949
*/
50-
static char *
51-
parse_dataset(char *dataset)
50+
static void
51+
parse_dataset(const char *target, char **dataset)
5252
{
53-
char cwd[PATH_MAX];
54-
struct stat64 statbuf;
55-
int error;
56-
int len;
57-
5853
/*
5954
* We expect a pool/dataset to be provided, however if we're
6055
* given a device which is a member of a zpool we attempt to
6156
* extract the pool name stored in the label. Given the pool
6257
* name we can mount the root dataset.
6358
*/
64-
error = stat64(dataset, &statbuf);
65-
if (error == 0) {
66-
nvlist_t *config;
67-
char *name;
68-
int fd;
69-
70-
fd = open(dataset, O_RDONLY);
71-
if (fd < 0)
72-
goto out;
73-
74-
error = zpool_read_label(fd, &config, NULL);
75-
(void) close(fd);
76-
if (error)
77-
goto out;
78-
79-
error = nvlist_lookup_string(config,
80-
ZPOOL_CONFIG_POOL_NAME, &name);
81-
if (error) {
82-
nvlist_free(config);
83-
} else {
84-
dataset = strdup(name);
59+
int fd = open(target, O_RDONLY);
60+
if (fd >= 0) {
61+
nvlist_t *config = NULL;
62+
if (zpool_read_label(fd, &config, NULL) != 0)
63+
config = NULL;
64+
if (close(fd))
65+
perror("close");
66+
67+
if (config) {
68+
char *name = NULL;
69+
if (!nvlist_lookup_string(config,
70+
ZPOOL_CONFIG_POOL_NAME, &name))
71+
(void) strlcpy(*dataset, name, PATH_MAX);
8572
nvlist_free(config);
86-
return (dataset);
73+
if (name)
74+
return;
8775
}
8876
}
89-
out:
77+
9078
/*
9179
* If a file or directory in your current working directory is
9280
* named 'dataset' then mount(8) will prepend your current working
9381
* directory to the dataset. There is no way to prevent this
9482
* behavior so we simply check for it and strip the prepended
9583
* patch when it is added.
9684
*/
97-
if (getcwd(cwd, PATH_MAX) == NULL)
98-
return (dataset);
99-
100-
len = strlen(cwd);
101-
102-
/* Do not add one when cwd already ends in a trailing '/' */
103-
if (strncmp(cwd, dataset, len) == 0)
104-
return (dataset + len + (cwd[len-1] != '/'));
105-
106-
return (dataset);
85+
char cwd[PATH_MAX];
86+
if (getcwd(cwd, PATH_MAX) != NULL) {
87+
int len = strlen(cwd);
88+
/* Do not add one when cwd already ends in a trailing '/' */
89+
if (strncmp(cwd, target, len) == 0)
90+
target += len + (cwd[len-1] != '/');
91+
}
92+
strlcpy(*dataset, target, PATH_MAX);
10793
}
10894

10995
/*
@@ -176,7 +162,7 @@ main(int argc, char **argv)
176162
char badopt[MNT_LINE_MAX] = { '\0' };
177163
char mtabopt[MNT_LINE_MAX] = { '\0' };
178164
char mntpoint[PATH_MAX];
179-
char *dataset;
165+
char dataset[PATH_MAX], *pdataset = dataset;
180166
unsigned long mntflags = 0, zfsflags = 0, remount = 0;
181167
int sloppy = 0, fake = 0, verbose = 0, nomtab = 0, zfsutil = 0;
182168
int error, c;
@@ -232,7 +218,7 @@ main(int argc, char **argv)
232218
return (MOUNT_USAGE);
233219
}
234220

235-
dataset = parse_dataset(argv[0]);
221+
parse_dataset(argv[0], &pdataset);
236222

237223
/* canonicalize the mount point */
238224
if (realpath(argv[1], mntpoint) == NULL) {

tests/runfiles/linux.run

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ tests = ['zfs_003_neg']
4747
tags = ['functional', 'cli_root', 'zfs']
4848

4949
[tests/functional/cli_root/zfs_mount:Linux]
50-
tests = ['zfs_mount_006_pos', 'zfs_mount_008_pos', 'zfs_multi_mount']
50+
tests = ['zfs_mount_006_pos', 'zfs_mount_008_pos', 'zfs_mount_013_pos',
51+
'zfs_mount_014_neg', 'zfs_multi_mount']
5152
tags = ['functional', 'cli_root', 'zfs_mount']
5253

5354
[tests/functional/cli_root/zfs_share:Linux]

tests/zfs-tests/include/commands.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ export ZFS_FILES='zdb
184184
arc_summary
185185
arcstat
186186
dbufstat
187+
mount.zfs
187188
zed
188189
zgenhostid
189190
zstream

tests/zfs-tests/tests/functional/cli_root/zfs_mount/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ dist_pkgdata_SCRIPTS = \
1414
zfs_mount_010_neg.ksh \
1515
zfs_mount_011_neg.ksh \
1616
zfs_mount_012_pos.ksh \
17+
zfs_mount_013_pos.ksh \
18+
zfs_mount_014_neg.ksh \
1719
zfs_mount_all_001_pos.ksh \
1820
zfs_mount_all_fail.ksh \
1921
zfs_mount_all_mountpoints.ksh \
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#!/bin/ksh -p
2+
#
3+
# CDDL HEADER START
4+
#
5+
# This file and its contents are supplied under the terms of the
6+
# Common Development and Distribution License ("CDDL"), version 1.0.
7+
# You may only use this file in accordance with the terms of version
8+
# 1.0 of the CDDL.
9+
#
10+
# A full copy of the text of the CDDL should have accompanied this
11+
# source. A copy of the CDDL is also available via the Internet at
12+
# http://www.illumos.org/license/CDDL.
13+
#
14+
# CDDL HEADER END
15+
#
16+
17+
. $STF_SUITE/include/libtest.shlib
18+
. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
19+
20+
#
21+
# DESCRIPTION:
22+
# Verify zfs mount helper functions for both devices and pools.
23+
#
24+
25+
verify_runnable "both"
26+
27+
set -A vdevs $(get_disklist_fullpath $TESTPOOL)
28+
vdev=${vdevs[0]}
29+
mntpoint=$TESTDIR/$TESTPOOL
30+
helper="mount.zfs -o zfsutil"
31+
fs=$TESTPOOL/$TESTFS
32+
33+
function cleanup
34+
{
35+
log_must force_unmount $vdev
36+
[[ -d $mntpoint ]] && log_must rm -rf $mntpoint
37+
return 0
38+
}
39+
log_onexit cleanup
40+
41+
log_note "Verify zfs mount helper functions for both devices and pools"
42+
43+
# Ensure that the ZFS filesystem is unmounted
44+
force_unmount $fs
45+
log_must mkdir -p $mntpoint
46+
47+
log_note "Verify '<dataset> <path>'"
48+
log_must $helper $fs $mntpoint
49+
log_must ismounted $fs
50+
force_unmount $fs
51+
52+
log_note "Verify '\$PWD/<pool> <path>' prefix workaround"
53+
log_must $helper $PWD/$fs $mntpoint
54+
log_must ismounted $fs
55+
force_unmount $fs
56+
57+
log_note "Verify '-f <dataset> <path>' fakemount"
58+
log_must $helper -f $fs $mntpoint
59+
log_mustnot ismounted $fs
60+
61+
log_note "Verify '-o ro -v <dataset> <path>' verbose RO"
62+
log_must ${helper},ro -v $fs $mntpoint
63+
log_must ismounted $fs
64+
force_unmount $fs
65+
66+
log_note "Verify '<device> <path>'"
67+
log_must $helper $vdev $mntpoint
68+
log_must ismounted $mntpoint
69+
log_must umount $TESTPOOL
70+
71+
log_note "Verify '-o abc -s <device> <path>' sloppy option"
72+
log_must ${helper},abc -s $vdev $mntpoint
73+
log_must ismounted $mntpoint
74+
log_must umount $TESTPOOL
75+
76+
log_pass "zfs mount helper correctly handles both device and pool strings"
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/bin/ksh -p
2+
#
3+
# CDDL HEADER START
4+
#
5+
# This file and its contents are supplied under the terms of the
6+
# Common Development and Distribution License ("CDDL"), version 1.0.
7+
# You may only use this file in accordance with the terms of version
8+
# 1.0 of the CDDL.
9+
#
10+
# A full copy of the text of the CDDL should have accompanied this
11+
# source. A copy of the CDDL is also available via the Internet at
12+
# http://www.illumos.org/license/CDDL.
13+
#
14+
# CDDL HEADER END
15+
#
16+
17+
. $STF_SUITE/include/libtest.shlib
18+
. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
19+
20+
#
21+
# DESCRIPTION:
22+
# Verify zfs mount helper failure on known bad parameters
23+
#
24+
25+
verify_runnable "both"
26+
27+
set -A vdevs $(get_disklist_fullpath $TESTPOOL)
28+
vdev=${vdevs[0]}
29+
30+
mntpoint="$(get_prop mountpoint $TESTPOOL)"
31+
helper="mount.zfs -o zfsutil"
32+
fs=$TESTPOOL/$TESTFS
33+
34+
function cleanup
35+
{
36+
log_must force_unmount $vdev
37+
return 0
38+
}
39+
log_onexit cleanup
40+
41+
log_note "Verify zfs mount helper failure on known bad parameters"
42+
43+
# Ensure that the ZFS filesystem is unmounted.
44+
force_unmount $fs
45+
46+
log_note "Verify failure without '-o zfsutil'"
47+
log_mustnot mount.zfs $fs $mntpoint
48+
49+
log_note "Verify '-o abc <device> <path>' bad option fails"
50+
log_mustnot ${helper},abc $vdev $mntpoint
51+
52+
log_note "Verify '\$NONEXISTFSNAME <path>' fails"
53+
log_mustnot $helper $NONEXISTFSNAME $mntpoint
54+
55+
log_note "Verify '<dataset> (\$NONEXISTFSNAME|/dev/null)' fails"
56+
log_mustnot $helper $fs $NONEXISTFSNAME
57+
log_mustnot $helper $fs /dev/null
58+
59+
log_note "Verify '/dev/null <path>' fails"
60+
log_mustnot $helper /dev/null $mntpoint
61+
62+
log_note "Verify '[device|pool]' fails"
63+
log_mustnot mount.zfs
64+
log_mustnot $helper
65+
log_mustnot $helper $vdev
66+
log_mustnot $helper $TESTPOOL
67+
68+
log_pass "zfs mount helper fails when expected"

0 commit comments

Comments
 (0)