aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2024-04-17 01:36:26 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2024-04-17 02:03:28 +0000
commit9075d4cfad5b339aabdf8033623a2164898c2786 (patch)
treea103106e7e98d5c8886b788bc6ca69ca6cc0e7c5
parent64d6925d1901637125f9f739282e72c992657dc8 (diff)
cp: Additional sanity check.
Once we've successfully opened the file we've been asked to copy, check that it's of the same type as FTS told us it was. MFC after: 1 week Sponsored by: Klara, Inc. Reviewed by: allanjude, markj Differential Revision: https://reviews.freebsd.org/D44806
-rw-r--r--bin/cp/utils.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/bin/cp/utils.c b/bin/cp/utils.c
index 6c99d4c63f4a..d102fb076139 100644
--- a/bin/cp/utils.c
+++ b/bin/cp/utils.c
@@ -100,21 +100,34 @@ copy_fallback(int from_fd, int to_fd)
int
copy_file(const FTSENT *entp, int dne)
{
- struct stat *fs;
+ struct stat sb, *fs;
ssize_t wcount;
off_t wtotal;
int ch, checkch, from_fd, rval, to_fd;
int use_copy_file_range = 1;
+ fs = entp->fts_statp;
from_fd = to_fd = -1;
- if (!lflag && !sflag &&
- (from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
- warn("%s", entp->fts_path);
- return (1);
+ if (!lflag && !sflag) {
+ if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) < 0 ||
+ fstat(from_fd, &sb) != 0) {
+ warn("%s", entp->fts_path);
+ return (1);
+ }
+ /*
+ * Check that the file hasn't been replaced with one of a
+ * different type. This can happen if we've been asked to
+ * copy something which is actively being modified and
+ * lost the race, or if we've been asked to copy something
+ * like /proc/X/fd/Y which stat(2) reports as S_IFREG but
+ * is actually something else once you open it.
+ */
+ if ((sb.st_mode & S_IFMT) != (fs->st_mode & S_IFMT)) {
+ warnx("%s: File changed", entp->fts_path);
+ return (1);
+ }
}
- fs = entp->fts_statp;
-
/*
* If the file exists and we're interactive, verify with the user.
* If the file DNE, set the mode to be the from file, minus setuid