summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2002-03-02 08:38:47 +0000
committerJim Meyering <jim@meyering.net>2002-03-02 08:38:47 +0000
commitdea4262fa6c807468ebc92128bb1005394813ac5 (patch)
tree59d55876c6f6e12708eb52aad5f9d9e9a74668f1
parent17e6a0e4bb47c942fbba4a218a7a16ad2385262b (diff)
downloadcoreutils-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.c34
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