diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2024-04-17 01:36:26 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2024-04-17 02:03:28 +0000 |
commit | 9075d4cfad5b339aabdf8033623a2164898c2786 (patch) | |
tree | a103106e7e98d5c8886b788bc6ca69ca6cc0e7c5 | |
parent | 64d6925d1901637125f9f739282e72c992657dc8 (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.c | 27 |
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 |