mirror of
https://github.com/RsyncProject/rsync.git
synced 2026-09-12 21:28:25 -04:00
util1: confine operator paths in the robust_rename EXDEV fallback
The cross-filesystem fallback copied to the dest and unlinked the source without operator-path confinement, so an absolute --temp-dir/--partial-dir on another filesystem was opened/unlinked via plain libc -- a raced parent symlink could redirect the dest-write or source-unlink out of the module. The source READ was already confined; flip operator_path_resolve for an absolute (operator) path around the copy_file dest-open and the do_unlink_at, leaving relative in-module paths on the secure_relative_open arm. This is the EXDEV-fallback backstop for the same absolute --partial-dir / foreign-owned-parent-symlink escape that operator-path-partial-dir_test.py already exercises at the handle_partial_dir() layer (which confines the staging dir before this code runs). A dedicated test for the EXDEV copy_file path itself would need the main tmp->final rename to fail first and then hit EXDEV on a foreign-owned raced parent -- a nested, timing-dependent trigger. Reported-by: Leonid Bugaev
This commit is contained in:
1 parent
ad64e99590
commit
fd4c75116b
1 file changed
+19
-2
@@ -628,16 +628,33 @@ int robust_rename(const char *from, const char *to, const char *partialptr,
|
||||
errno = ETXTBSY;
|
||||
break;
|
||||
#endif
|
||||
case EXDEV:
|
||||
case EXDEV: {
|
||||
int save = operator_path_resolve, rc;
|
||||
if (partialptr) {
|
||||
if (!handle_partial_dir(partialptr,PDIR_CREATE))
|
||||
return -2;
|
||||
to = partialptr;
|
||||
}
|
||||
if (copy_file(from, to, -1, mode) != 0)
|
||||
/* Cross-fs fallback: copy then unlink. An absolute --temp-dir
|
||||
* source / --partial-dir dest is an operator path whose parents
|
||||
* do_open_at()/do_unlink_at() would otherwise follow via plain libc
|
||||
* -- confine them through the ownership walk so a raced parent
|
||||
* symlink can't redirect the dest-write or the source-unlink out of
|
||||
* the module. copy_file already confines the source READ; a
|
||||
* relative in-module path stays on the secure_relative_open arm, so
|
||||
* only flip the flag for an absolute (operator) path. */
|
||||
if (to && *to == '/')
|
||||
operator_path_resolve = 1;
|
||||
rc = copy_file(from, to, -1, mode);
|
||||
operator_path_resolve = save;
|
||||
if (rc != 0)
|
||||
return -2;
|
||||
if (from && *from == '/')
|
||||
operator_path_resolve = 1;
|
||||
do_unlink_at(from);
|
||||
operator_path_resolve = save;
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user