commit 906c123b76844b1bba457451f3571b64afa77006 from: Stefan Sperling date: Thu Jul 23 14:21:29 2020 UTC do not allow symlinks pointing into the .got directory; noticed by semarie commit - b15bc87b1884e0d5a69df4536d29a8a8af8a745b commit + 906c123b76844b1bba457451f3571b64afa77006 blob - be2544b20e495c1e8e6ec3d59412f2024401e94a blob + 879e8cb6f14e7b6c5f1c156dc33f16a2e9710324 --- lib/worktree.c +++ lib/worktree.c @@ -954,6 +954,7 @@ install_symlink(struct got_worktree *worktree, const c char target_path[PATH_MAX]; size_t len, target_len = 0; char *resolved_path = NULL, *abspath = NULL; + char *path_got = NULL; const uint8_t *buf = got_object_blob_get_read_buf(blob); size_t hdrlen = got_object_blob_get_hdrlen(blob); @@ -1025,6 +1026,23 @@ install_symlink(struct got_worktree *worktree, const c goto done; } + /* Do not allow symlinks pointing into the .got directory. */ + if (asprintf(&path_got, "%s/%s", worktree->root_path, + GOT_WORKTREE_GOT_DIR) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + if (got_path_is_child(resolved_path ? resolved_path : (abspath ? + abspath : target_path), path_got, strlen(path_got))) { + /* install as a regular file */ + got_object_blob_rewind(blob); + err = install_blob(worktree, ondisk_path, path, + GOT_DEFAULT_FILE_MODE, st_mode, blob, + restoring_missing_file, reverting_versioned_file, + repo, progress_cb, progress_arg); + goto done; + } + if (symlink(target_path, ondisk_path) == -1) { if (errno == EEXIST) { struct stat sb; @@ -1108,6 +1126,7 @@ install_symlink(struct got_worktree *worktree, const c done: free(resolved_path); free(abspath); + free(path_got); return err; } blob - 6cde66bae40dff4c5b2cb46b31fe7b2ca5f1df13 blob + a7cf8346fb69dcd9589570531e799d90564c3ee0 --- regress/cmdline/checkout.sh +++ regress/cmdline/checkout.sh @@ -511,6 +511,7 @@ function test_checkout_symlink { (cd $testroot/repo && ln -s /etc/passwd passwd.link) (cd $testroot/repo && ln -s ../beta epsilon/beta.link) (cd $testroot/repo && ln -s nonexistent nonexistent.link) + (cd $testroot/repo && ln -s .got/foo dotgotfoo.link) (cd $testroot/repo && git add .) git_commit $testroot/repo -m "add symlinks" @@ -587,6 +588,23 @@ function test_checkout_symlink { ret="$?" if [ "$ret" != "0" ]; then diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + fi + + if [ -h $testroot/wt/dotgotfoo.link ]; then + echo -n "dotgotfoo.link symlink points into .got dir: " >&2 + readlink $testroot/wt/dotgotfoo.link >&2 + test_done "$testroot" "1" + return 1 + fi + + echo -n ".got/foo" > $testroot/content.expected + cp $testroot/wt/dotgotfoo.link $testroot/content + + cmp -s $testroot/content.expected $testroot/content + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/content.expected $testroot/content fi test_done "$testroot" "$ret" }