diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2023-02-15 02:12:45 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2023-02-15 02:13:11 +0000 |
commit | ae6cff89738bab9a4a956c230fb9dc6c4d5e113f (patch) | |
tree | e6439ff954281df55965364142f9a215bf372060 | |
parent | b918ee2ce4850253ddd884e39dabecd6e96bf474 (diff) | |
download | src-ae6cff89738bab9a4a956c230fb9dc6c4d5e113f.tar.gz src-ae6cff89738bab9a4a956c230fb9dc6c4d5e113f.zip |
tarfs: Don't panic if the parent of a new node is not a directory.
PR: 269519
Sponsored by: Juniper Networks, Inc.
Sponsored by: Klara, Inc.
Reviewed by: kib
Differential Revision: https://reviews.freebsd.org/D38587
-rw-r--r-- | sys/fs/tarfs/tarfs_subr.c | 3 | ||||
-rw-r--r-- | sys/fs/tarfs/tarfs_vfsops.c | 12 | ||||
-rw-r--r-- | tests/sys/fs/tarfs/tarfs_test.sh | 30 |
3 files changed, 39 insertions, 6 deletions
diff --git a/sys/fs/tarfs/tarfs_subr.c b/sys/fs/tarfs/tarfs_subr.c index fc2955b44606..0cba43a8c21b 100644 --- a/sys/fs/tarfs/tarfs_subr.c +++ b/sys/fs/tarfs/tarfs_subr.c @@ -171,6 +171,8 @@ tarfs_alloc_node(struct tarfs_mount *tmp, const char *name, size_t namelen, TARFS_DPF(ALLOC, "%s(%.*s)\n", __func__, (int)namelen, name); + if (parent != NULL && parent->type != VDIR) + return (ENOTDIR); tnp = malloc(sizeof(struct tarfs_node), M_TARFSNODE, M_WAITOK | M_ZERO); mtx_init(&tnp->lock, "tarfs node lock", NULL, MTX_DEF); tnp->gen = arc4random(); @@ -233,7 +235,6 @@ tarfs_alloc_node(struct tarfs_mount *tmp, const char *name, size_t namelen, panic("%s: type %d not allowed", __func__, type); } if (parent != NULL) { - MPASS(parent->type == VDIR); TARFS_NODE_LOCK(parent); TAILQ_INSERT_TAIL(&parent->dir.dirhead, tnp, dirents); parent->size += sizeof(struct tarfs_node); diff --git a/sys/fs/tarfs/tarfs_vfsops.c b/sys/fs/tarfs/tarfs_vfsops.c index 138a57c22e7f..b3c30e884a9d 100644 --- a/sys/fs/tarfs/tarfs_vfsops.c +++ b/sys/fs/tarfs/tarfs_vfsops.c @@ -320,6 +320,12 @@ tarfs_lookup_path(struct tarfs_mount *tmp, char *name, size_t namelen, break; } + /* we're not at the end, so parent must be a directory */ + if (parent->type != VDIR) { + error = ENOTDIR; + break; + } + /* locate the next separator */ for (sep = name, len = 0; *sep != '\0' && *sep != '/' && len < namelen; @@ -685,8 +691,12 @@ again: error = tarfs_lookup_path(tmp, name, namelen, &namep, &sep, &parent, &tnp, true); - if (error != 0) + if (error != 0) { + TARFS_DPF(ALLOC, "%s: failed to look up %.*s\n", __func__, + (int)namelen, name); + error = EINVAL; goto bad; + } if (tnp != NULL) { if (hdrp->typeflag[0] == TAR_TYPE_DIRECTORY) { /* XXX set attributes? */ diff --git a/tests/sys/fs/tarfs/tarfs_test.sh b/tests/sys/fs/tarfs/tarfs_test.sh index d812ced80bbb..634b6be3dd08 100644 --- a/tests/sys/fs/tarfs/tarfs_test.sh +++ b/tests/sys/fs/tarfs/tarfs_test.sh @@ -33,10 +33,11 @@ mnt="$(realpath ${TMPDIR:-/tmp})/mnt.$$" sum=4da2143234486307bb44eaa610375301781a577d1172f362b88bb4b1643dee62 atf_test_case tarfs_test -tarfs_test_head() { +tarfs_basic_head() { + atf_set "descr" "Basic function test" atf_set "require.user" "root" } -tarfs_test_body() { +tarfs_basic_body() { mkdir "${mnt}" "${mktar}" tarfs_test.tar.zst atf_check mount -rt tarfs tarfs_test.tar.zst "${mnt}" @@ -45,10 +46,31 @@ tarfs_test_body() { atf_check_equal "$(stat -f%d,%i "${mnt}"/sparse_file)" "$(stat -L -f%d,%i "${mnt}"/long_link)" atf_check_equal "$(sha256 -q "${mnt}"/sparse_file)" ${sum} } -tarfs_test_cleanup() { +tarfs_basic_cleanup() { + umount "${mnt}" +} + +atf_test_case tarfs_notdir +tarfs_notdir_head() { + atf_set "descr" "Regression test for PR 269519" + atf_set "require.user" "root" +} +tarfs_notdir_body() { + mkdir "${mnt}" + echo "hello" >d + tar cf tarfs_notdir.tar d + rm d + mkdir -p d/s + echo "world" >d/s/f + tar rf tarfs_notdir.tar d/s/f + atf_check -s not-exit:0 -e match:"Invalid" \ + mount -rt tarfs tarfs_notdir.tar "${mnt}" +} +tarfs_notdir_cleanup() { umount "${mnt}" } atf_init_test_cases() { - atf_add_test_case tarfs_test + atf_add_test_case tarfs_basic + atf_add_test_case tarfs_notdir } |