diff options
author | Jim Meyering <jim@meyering.net> | 2002-03-02 08:38:47 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2002-03-02 08:38:47 +0000 |
commit | dea4262fa6c807468ebc92128bb1005394813ac5 (patch) | |
tree | 59d55876c6f6e12708eb52aad5f9d9e9a74668f1 | |
parent | 17e6a0e4bb47c942fbba4a218a7a16ad2385262b (diff) | |
download | coreutils-dea4262fa6c807468ebc92128bb1005394813ac5.tar.xz |
(copy_reg): Detect abuse of a race condition
whereby an unprivileged user could gain read access to otherwise-
inaccessible files when root uses cp or mv to copy a hierarchy
belonging to that user.
-rw-r--r-- | src/copy.c | 34 |
1 files changed, 31 insertions, 3 deletions
diff --git a/src/copy.c b/src/copy.c index 4dc09b870..4da2b2190 100644 --- a/src/copy.c +++ b/src/copy.c @@ -195,17 +195,20 @@ copy_dir (const char *src_path_in, const char *dst_path_in, int new_dst, Use DST_MODE as the 3rd argument in the call to open. X provides many option settings. Return 0 if successful, -1 if an error occurred. - *NEW_DST is as in copy_internal. */ + *NEW_DST is as in copy_internal. SRC_SB is the result + of calling xstat (aka stat in this case) on SRC_PATH. */ static int copy_reg (const char *src_path, const char *dst_path, - const struct cp_options *x, mode_t dst_mode, int *new_dst) + const struct cp_options *x, mode_t dst_mode, int *new_dst, + struct stat const *src_sb) { char *buf; int buf_size; int dest_desc; int source_desc; struct stat sb; + struct stat src_open_sb; char *cp; int *ip; int return_val = 0; @@ -220,6 +223,31 @@ copy_reg (const char *src_path, const char *dst_path, return -1; } + if (fstat (source_desc, &src_open_sb)) + { + error (0, errno, _("cannot fstat %s"), quote (src_path)); + return_val = -1; + goto close_src_desc; + } + + /* Compare the source dev/ino from the open file to the incoming, + saved ones obtained via a previous call to stat. */ + if (! SAME_INODE (*src_sb, src_open_sb)) + { + error (EXIT_FAILURE, 0, + _("ERROR: the source file %s initially had device/inode\n\ +numbers %lu/%lu, but now (after opening it), the numbers\n\ +are %lu/%lu. That means that while this program was running,\n\ +the file was replaced with another one. Skipping this file."), + quote (src_path), + (unsigned long)(src_sb->st_dev), + (unsigned long)(src_sb->st_ino), + (unsigned long)(src_open_sb.st_dev), + (unsigned long)(src_open_sb.st_ino)); + return_val = -1; + goto close_src_desc; + } + /* These semantics are required for cp. The if-block will be taken in move_mode. */ if (*new_dst) @@ -1339,7 +1367,7 @@ copy_internal (const char *src_path, const char *dst_path, used as the 3rd argument in the open call, but that's not consistent with historical practice. */ if (copy_reg (src_path, dst_path, x, - get_dest_mode (x, src_mode), &new_dst)) + get_dest_mode (x, src_mode), &new_dst, &src_sb)) goto un_backup; } else |