tarfs: Really prevent descending into a non-directory.

The previous fix was incorrect: we need to verify that the current node, if it exists, is not a directory, but we were checking the parent node instead.  Address this, add more tests, and fix the test cleanup routines.

PR:		269519, 269561
Fixes:		ae6cff8973
Sponsored by:	Juniper Networks, Inc.
Sponsored by:	Klara, Inc.
Reviewed by:	kib
Differential Revision:	https://reviews.freebsd.org/D38645
This commit is contained in:
Dag-Erling Smørgrav 2023-02-20 21:28:53 +00:00
parent ef6fcc5e2b
commit d481dcee72
2 changed files with 85 additions and 19 deletions

View File

@ -304,8 +304,8 @@ tarfs_lookup_path(struct tarfs_mount *tmp, char *name, size_t namelen,
if (tnp == NULL)
panic("%s: root node not yet created", __func__);
TARFS_DPF(LOOKUP, "%s: Full path: %.*s\n", __func__, (int)namelen,
name);
TARFS_DPF(LOOKUP, "%s: full path: %.*s\n", __func__,
(int)namelen, name);
sep = NULL;
for (;;) {
@ -320,8 +320,10 @@ 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) {
/* we're not at the end, so we must be in a directory */
if (tnp != NULL && tnp->type != VDIR) {
TARFS_DPF(LOOKUP, "%s: %.*s is not a directory\n", __func__,
(int)tnp->namelen, tnp->name);
error = ENOTDIR;
break;
}
@ -365,8 +367,9 @@ tarfs_lookup_path(struct tarfs_mount *tmp, char *name, size_t namelen,
tnp = NULL;
cn.cn_nameptr = name;
cn.cn_namelen = len;
TARFS_DPF(LOOKUP, "%s: Search: %.*s\n", __func__,
(int)cn.cn_namelen, cn.cn_nameptr);
TARFS_DPF(LOOKUP, "%s: looking up %.*s in %.*s/\n", __func__,
(int)cn.cn_namelen, cn.cn_nameptr,
(int)parent->namelen, parent->name);
if (do_lookup) {
tnp = tarfs_lookup_node(parent, NULL, &cn);
if (tnp == NULL) {
@ -379,7 +382,7 @@ tarfs_lookup_path(struct tarfs_mount *tmp, char *name, size_t namelen,
namelen -= cn.cn_namelen;
}
TARFS_DPF(LOOKUP, "%s: Parent %p, node %p\n", __func__, parent, tnp);
TARFS_DPF(LOOKUP, "%s: parent %p node %p\n", __func__, parent, tnp);
if (retparent)
*retparent = parent;

View File

@ -27,12 +27,12 @@
#
mktar="$(dirname $(realpath "$0"))"/mktar
mnt="$(realpath ${TMPDIR:-/tmp})/mnt.$$"
mnt="$(realpath ${TMPDIR:-/tmp})/mnt"
# expected SHA256 checksum of file contained in test tarball
sum=4da2143234486307bb44eaa610375301781a577d1172f362b88bb4b1643dee62
atf_test_case tarfs_test
atf_test_case tarfs_basic cleanup
tarfs_basic_head() {
atf_set "descr" "Basic function test"
atf_set "require.user" "root"
@ -50,27 +50,90 @@ tarfs_basic_cleanup() {
umount "${mnt}"
}
atf_test_case tarfs_notdir
tarfs_notdir_head() {
atf_set "descr" "Regression test for PR 269519"
atf_test_case tarfs_notdir_device cleanup
tarfs_notdir_device_head() {
atf_set "descr" "Regression test for PR 269519 and 269561"
atf_set "require.user" "root"
}
tarfs_notdir_body() {
tarfs_notdir_device_body() {
mkdir "${mnt}"
atf_check mknod d b 0xdead 0xbeef
tar cf tarfs_notdir.tar d
rm d
mkdir d
echo "boom" >d/f
tar rf tarfs_notdir.tar d/f
atf_check -s not-exit:0 -e match:"Invalid" \
mount -rt tarfs tarfs_notdir.tar "${mnt}"
}
tarfs_notdir_device_cleanup() {
umount "${mnt}" || true
}
atf_test_case tarfs_notdir_dot cleanup
tarfs_notdir_dot_head() {
atf_set "descr" "Regression test for PR 269519 and 269561"
atf_set "require.user" "root"
}
tarfs_notdir_dot_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
mkdir d
echo "world" >d/f
tar rf tarfs_notdir.tar d/./f
atf_check -s not-exit:0 -e match:"Invalid" \
mount -rt tarfs tarfs_notdir.tar "${mnt}"
}
tarfs_notdir_cleanup() {
umount "${mnt}"
tarfs_notdir_dot_cleanup() {
umount "${mnt}" || true
}
atf_test_case tarfs_notdir_dotdot cleanup
tarfs_notdir_dotdot_head() {
atf_set "descr" "Regression test for PR 269519 and 269561"
atf_set "require.user" "root"
}
tarfs_notdir_dotdot_body() {
mkdir "${mnt}"
echo "hello" >d
tar cf tarfs_notdir.tar d
rm d
mkdir d
echo "world" >f
tar rf tarfs_notdir.tar d/../f
atf_check -s not-exit:0 -e match:"Invalid" \
mount -rt tarfs tarfs_notdir.tar "${mnt}"
}
tarfs_notdir_dotdot_cleanup() {
umount "${mnt}" || true
}
atf_test_case tarfs_notdir_file cleanup
tarfs_notdir_file_head() {
atf_set "descr" "Regression test for PR 269519 and 269561"
atf_set "require.user" "root"
}
tarfs_notdir_file_body() {
mkdir "${mnt}"
echo "hello" >d
tar cf tarfs_notdir.tar d
rm d
mkdir d
echo "world" >d/f
tar rf tarfs_notdir.tar d/f
atf_check -s not-exit:0 -e match:"Invalid" \
mount -rt tarfs tarfs_notdir.tar "${mnt}"
}
tarfs_notdir_file_cleanup() {
umount "${mnt}" || true
}
atf_init_test_cases() {
atf_add_test_case tarfs_basic
atf_add_test_case tarfs_notdir
atf_add_test_case tarfs_notdir_device
atf_add_test_case tarfs_notdir_dot
atf_add_test_case tarfs_notdir_dotdot
atf_add_test_case tarfs_notdir_file
}