diff options
author | Lennart Poettering <lennart@poettering.net> | 2018-06-06 17:33:28 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2018-06-07 13:27:38 +0200 |
commit | f6a77804c9d743e8d01051d2cb0511b53a49c56e (patch) | |
tree | a9f4f8e2944c28dbf7ececdc86418e8b6c755b86 /src/basic/copy.c | |
parent | copy: only check for traversing mount points on directories (diff) | |
download | systemd-f6a77804c9d743e8d01051d2cb0511b53a49c56e.tar.xz systemd-f6a77804c9d743e8d01051d2cb0511b53a49c56e.zip |
copy: extend check for mount point crossing
We do this checks as protection against bind mount cycles on the same
file system. However, the check wasn't really effective for that, as
it would only detect cycles A → B → A this way. By using
fs_is_mount_point() we'll also detect cycles A → A.
Also, while we are at it, make these file system boundary checks
optional. This is not used anywhere, but might be eventually...
Most importantly though add a longer blurb explanation the why.
Diffstat (limited to 'src/basic/copy.c')
-rw-r--r-- | src/basic/copy.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/src/basic/copy.c b/src/basic/copy.c index 6ed46241fc..8d8f907e29 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -29,6 +29,7 @@ #include "io-util.h" #include "macro.h" #include "missing.h" +#include "mount-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -531,8 +532,34 @@ static int fd_copy_directory( } if (S_ISDIR(buf.st_mode)) { - if (buf.st_dev != original_device) - continue; + /* + * Don't descend into directories on other file systems, if this is requested. We do a simple + * .st_dev check here, which basically comes for free. Note that we do this check only on + * directories, not other kind of file system objects, for two reason: + * + * • The kernel's overlayfs pseudo file system that overlays multiple real file systems + * propagates the .st_dev field of the file system a file originates from all the way up + * through the stack to stat(). It doesn't do that for directories however. This means that + * comparing .st_dev on non-directories suggests that they all are mount points. To avoid + * confusion we hence avoid relying on this check for regular files. + * + * • The main reason we do this check at all is to protect ourselves from bind mount cycles, + * where we really want to avoid descending down in all eternity. However the .st_dev check + * is usually not sufficient for this protection anyway, as bind mount cycles from the same + * file system onto itself can't be detected that way. + */ + + if (FLAGS_SET(copy_flags, COPY_SAME_MOUNT)) { + if (buf.st_dev != original_device) + continue; + + r = fd_is_mount_point(dirfd(d), de->d_name, 0); + if (r < 0) + return r; + if (r > 0) + continue; + } + q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, override_uid, override_gid, copy_flags); } else if (S_ISREG(buf.st_mode)) q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); |