Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Leap:15.4:Update
tar
tar-fix-race-condition.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File tar-fix-race-condition.patch of Package tar
From 79a442d7b0e92622794bfa41dee18a28e450a0dc Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Thu, 9 Jun 2022 22:09:34 -0700 Subject: tar: fix race condition Problem reported by James Abbatiello in: https://lists.gnu.org/r/bug-tar/2022-03/msg00000.html * src/extract.c (make_directories): Do not assume that when mkdirat fails with errno == EEXIST that there is an existing file that can be statted. It could be a dangling symlink. Instead, wait until the end and stat it. --- src/extract.c | 61 ++++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/extract.c b/src/extract.c index e7be463..0753dec 100644 --- a/src/extract.c +++ b/src/extract.c @@ -636,8 +636,7 @@ fixup_delayed_set_stat (char const *src, char const *dst) } } -/* After a file/link/directory creation has failed, see if - it's because some required directory was not present, and if so, +/* After a file/link/directory creation has failed due to ENOENT, create all required directories. Return zero if all the required directories were created, nonzero (issuing a diagnostic) otherwise. Set *INTERDIR_MADE if at least one directory was created. */ @@ -646,6 +645,8 @@ make_directories (char *file_name, bool *interdir_made) { char *cursor0 = file_name + FILE_SYSTEM_PREFIX_LEN (file_name); char *cursor; /* points into the file name */ + char *parent_end = NULL; + int parent_errno; for (cursor = cursor0; *cursor; cursor++) { @@ -685,31 +686,47 @@ make_directories (char *file_name, bool *interdir_made) print_for_mkdir (file_name, cursor - file_name, desired_mode); *interdir_made = true; + parent_end = NULL; } - else if (errno == EEXIST) - status = 0; else - { - /* Check whether the desired file exists. Even when the - file exists, mkdir can fail with some errno value E other - than EEXIST, so long as E describes an error condition - that also applies. */ - int e = errno; - struct stat st; - status = fstatat (chdir_fd, file_name, &st, 0); - if (status) - { - errno = e; - mkdir_error (file_name); - } - } + switch (errno) + { + case ELOOP: case ENAMETOOLONG: case ENOENT: case ENOTDIR: + /* FILE_NAME doesn't exist and couldn't be created; fail now. */ + mkdir_error (file_name); + *cursor = '/'; + return status; + + default: + /* FILE_NAME may be an existing directory so do not fail now. + Instead, arrange to check at loop exit, assuming this is + the last loop iteration. */ + parent_end = cursor; + parent_errno = errno; + break; + } *cursor = '/'; - if (status) - return status; } - return 0; + if (!parent_end) + return 0; + + /* Although we did not create the parent directory, some other + process may have created it, so check whether it exists now. */ + *parent_end = '\0'; + struct stat st; + int stat_status = fstatat (chdir_fd, file_name, &st, 0); + if (!stat_status && !S_ISDIR (st.st_mode)) + stat_status = -1; + if (stat_status) + { + errno = parent_errno; + mkdir_error (file_name); + } + *parent_end = '/'; + + return stat_status; } /* Return true if FILE_NAME (with status *STP, if STP) is not a @@ -824,7 +841,7 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made) case ENOENT: /* Attempt creating missing intermediate directories. */ - if (make_directories (file_name, interdir_made) == 0 && *interdir_made) + if (make_directories (file_name, interdir_made) == 0) return RECOVER_OK; break; -- cgit v1.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor