mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-04-26 03:20:40 +00:00
Use openat2 to jailify the extraction directory
This addresses CVE-2025-45582. * gnulib.modules: Add openat2. * src/misc.c (open_subdir): New static function. (fdbase_opendir): Use it. * src/tar.c (open_searchdir_how): New var, replacing and augmenting open_searchdir_flags. All uses changed. * tests/extrac31.at: New file. * tests/Makefile (TESTSUITE_AT), tests/testuite.at: Add it.
This commit is contained in:
@@ -376,7 +376,7 @@ struct name
|
||||
|
||||
/* Flags for reading, searching, and fstatatting files. */
|
||||
extern int open_read_flags;
|
||||
extern int open_searchdir_flags;
|
||||
extern struct open_how open_searchdir_how;
|
||||
extern int fstatat_flags;
|
||||
|
||||
extern int seek_option;
|
||||
|
||||
@@ -1344,7 +1344,7 @@ create_archive (void)
|
||||
struct fdbase f = fdbase (p->name);
|
||||
int fd = (f.fd == BADFD ? -1
|
||||
: openat (f.fd, f.base,
|
||||
open_searchdir_flags));
|
||||
open_searchdir_how.flags));
|
||||
if (fd < 0)
|
||||
{
|
||||
file_removed_diag (p->name, !p->parent,
|
||||
@@ -1569,7 +1569,7 @@ restore_parent_fd (struct tar_stat_info const *st)
|
||||
struct tar_stat_info *parent = st->parent;
|
||||
if (parent && ! parent->fd)
|
||||
{
|
||||
int parentfd = openat (st->fd, "..", open_searchdir_flags);
|
||||
int parentfd = openat (st->fd, "..", open_searchdir_how.flags);
|
||||
struct stat parentstat;
|
||||
|
||||
if (parentfd < 0)
|
||||
@@ -1585,7 +1585,7 @@ restore_parent_fd (struct tar_stat_info const *st)
|
||||
{
|
||||
struct fdbase f = fdbase (parent->orig_file_name);
|
||||
int origfd = (f.fd == BADFD ? -1
|
||||
: openat (f.fd, f.base, open_searchdir_flags));
|
||||
: openat (f.fd, f.base, open_searchdir_how.flags));
|
||||
if (0 <= origfd)
|
||||
{
|
||||
if (fstat (parentfd, &parentstat) < 0
|
||||
|
||||
16
src/misc.c
16
src/misc.c
@@ -1070,7 +1070,7 @@ chdir_do (idx_t i)
|
||||
if (! IS_ABSOLUTE_FILE_NAME (curr->name))
|
||||
chdir_do (i - 1);
|
||||
fd = openat (chdir_fd, curr->name,
|
||||
open_searchdir_flags & ~ O_NOFOLLOW);
|
||||
open_searchdir_how.flags & ~O_NOFOLLOW);
|
||||
if (fd < 0)
|
||||
open_fatal (curr->name);
|
||||
|
||||
@@ -1173,6 +1173,16 @@ fdbase_clear (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Starting from the directory FD, open a subdirectory SUBDIR for search.
|
||||
If extracting or diffing and --absolute-names (-P) is not in effect,
|
||||
do not let the subdirectory escape FD, i.e., the subdirectory must
|
||||
be at or under FD in the directory hierarchy. */
|
||||
static int
|
||||
open_subdir (int fd, char const *subdir)
|
||||
{
|
||||
return openat2 (fd, subdir, &open_searchdir_how, sizeof open_searchdir_how);
|
||||
}
|
||||
|
||||
/* Return an fd open to FILE_NAME's parent directory,
|
||||
along with the base name of FILE_NAME.
|
||||
Use the alternate cache if ALTERNATE, the main cache otherwise.
|
||||
@@ -1224,7 +1234,7 @@ fdbase_opendir (char const *file_name, bool alternate)
|
||||
{
|
||||
/* The new directory is a subdirectory of the old,
|
||||
so open relative to FD rather than to chdir_fd. */
|
||||
int subfd = openat (fd, &subdir[c->subdirlen], open_searchdir_flags);
|
||||
int subfd = open_subdir (fd, &subdir[c->subdirlen]);
|
||||
if (subfd < 0)
|
||||
{
|
||||
/* Keep the old directory cached and report open failure,
|
||||
@@ -1251,7 +1261,7 @@ fdbase_opendir (char const *file_name, bool alternate)
|
||||
and add new info if the new directory can be opened. */
|
||||
if (0 < c->subdirlen)
|
||||
close (fd);
|
||||
fd = openat (chdir_fd, c->subdir, open_searchdir_flags);
|
||||
fd = open_subdir (chdir_fd, c->subdir);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (BADFD != -1 && fd < 0)
|
||||
|
||||
10
src/tar.c
10
src/tar.c
@@ -111,7 +111,7 @@ idx_t archive_names;
|
||||
const char **archive_name_cursor;
|
||||
char const *index_file_name;
|
||||
int open_read_flags;
|
||||
int open_searchdir_flags;
|
||||
struct open_how open_searchdir_how;
|
||||
int fstatat_flags;
|
||||
int seek_option;
|
||||
bool unquote_option;
|
||||
@@ -2709,8 +2709,12 @@ decode_options (int argc, char **argv)
|
||||
#else
|
||||
int search_flags = O_SEARCH | noatime_flag;
|
||||
#endif
|
||||
open_searchdir_flags = (search_flags | O_BINARY | O_CLOEXEC | O_DIRECTORY
|
||||
| nofollow_flag);
|
||||
open_searchdir_how.flags = (search_flags | nofollow_flag
|
||||
| O_BINARY | O_CLOEXEC | O_DIRECTORY);
|
||||
if (!absolute_names_option
|
||||
&& (subcommand_option == EXTRACT_SUBCOMMAND
|
||||
|| subcommand_option == DIFF_SUBCOMMAND))
|
||||
open_searchdir_how.resolve = RESOLVE_BENEATH;
|
||||
}
|
||||
fstatat_flags = dereference_option ? 0 : AT_SYMLINK_NOFOLLOW;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user