739e7477f9
- allow spaces in user/group names (#2049665) - Fall back to semanage_copy_dir when rename() fails (#2068085) Resolves: rhbz#2049665, rhbz#2068085
136 lines
5.0 KiB
Diff
136 lines
5.0 KiB
Diff
From b05fd4edd27fae3d00cc31e9d24910ef4925f8c1 Mon Sep 17 00:00:00 2001
|
|
From: Petr Lautrbach <plautrba@redhat.com>
|
|
Date: Thu, 24 Mar 2022 13:00:34 +0100
|
|
Subject: [PATCH] libsemanage: Fall back to semanage_copy_dir when rename()
|
|
fails
|
|
Content-type: text/plain
|
|
|
|
In some circumstances, like semanage-store being on overlayfs, rename()
|
|
could fail with EXDEV - Invalid cross-device link. This is due to the
|
|
fact that overlays doesn't support rename() if source and target are not
|
|
on the same layer, e.g. in containers built from several layers. Even
|
|
though it's not atomic operation, it's better to try to copy files from
|
|
src to dst on our own in this case. Next rebuild will probably not fail
|
|
as the new directories will be on the same layer.
|
|
|
|
Fixes: https://github.com/SELinuxProject/selinux/issues/343
|
|
|
|
Reproducer:
|
|
|
|
$ cd selinux1
|
|
|
|
$ cat Dockerfile
|
|
FROM fedora:35
|
|
RUN dnf install -y selinux-policy selinux-policy-targeted
|
|
|
|
$ podman build -t localhost/selinux . --no-cache
|
|
|
|
$ cd ../selinux2
|
|
|
|
$ cat Dockerfile
|
|
FROM localhost/selinux
|
|
RUN semodule -B
|
|
|
|
$ podman build -t localhost/selinux2 . --no-cache
|
|
STEP 2/2: RUN semodule -B
|
|
libsemanage.semanage_commit_sandbox: Error while renaming /var/lib/selinux/targeted/active to /var/lib/selinux/targeted/previous. (Invalid cross-device link).
|
|
semodule: Failed!
|
|
Error: error building at STEP "RUN semodule -B": error while running runtime: exit status 1
|
|
|
|
With the fix:
|
|
|
|
$ podman build -t localhost/selinux2 . --no-cache
|
|
STEP 2/2: RUN semodule -B
|
|
libsemanage.semanage_rename: Warning: rename(/var/lib/selinux/targeted/active, /var/lib/selinux/targeted/previous) failed: Invalid cross-device link, fall back to non-atomic semanage_copy_dir_flags()
|
|
|
|
COMMIT localhost/selinux2
|
|
--> d2cfcebc1a1
|
|
Successfully tagged localhost/selinux2:latest
|
|
d2cfcebc1a1b34f1c2cd661ac18292b0612c3e5fa71d6fa1441be244da91b1af
|
|
|
|
Reported-by: Joseph Marrero Corchado <jmarrero@redhat.com>
|
|
Signed-off-by: Petr Lautrbach <plautrba@redhat.com>
|
|
Acked-by: Ondrej Mosnacek <omosnace@redhat.com>
|
|
---
|
|
libsemanage/src/semanage_store.c | 30 ++++++++++++++++++++++++------
|
|
1 file changed, 24 insertions(+), 6 deletions(-)
|
|
|
|
diff --git a/libsemanage/src/semanage_store.c b/libsemanage/src/semanage_store.c
|
|
index 767f05cb2853..c6d2c5e72709 100644
|
|
--- a/libsemanage/src/semanage_store.c
|
|
+++ b/libsemanage/src/semanage_store.c
|
|
@@ -697,6 +697,10 @@ int semanage_store_access_check(void)
|
|
|
|
/********************* other I/O functions *********************/
|
|
|
|
+static int semanage_rename(semanage_handle_t * sh, const char *tmp, const char *dst);
|
|
+int semanage_remove_directory(const char *path);
|
|
+static int semanage_copy_dir_flags(const char *src, const char *dst, int flag);
|
|
+
|
|
/* Callback used by scandir() to select files. */
|
|
static int semanage_filename_select(const struct dirent *d)
|
|
{
|
|
@@ -768,7 +772,21 @@ out:
|
|
return retval;
|
|
}
|
|
|
|
-static int semanage_copy_dir_flags(const char *src, const char *dst, int flag);
|
|
+static int semanage_rename(semanage_handle_t * sh, const char *src, const char *dst) {
|
|
+ int retval;
|
|
+
|
|
+ retval = rename(src, dst);
|
|
+ if (retval == 0 || errno != EXDEV)
|
|
+ return retval;
|
|
+
|
|
+ /* we can't use rename() due to filesystem limitation, lets try to copy files manually */
|
|
+ WARN(sh, "WARNING: rename(%s, %s) failed: %s, fall back to non-atomic semanage_copy_dir_flags()",
|
|
+ src, dst, strerror(errno));
|
|
+ if (semanage_copy_dir_flags(src, dst, 1) == -1) {
|
|
+ return -1;
|
|
+ }
|
|
+ return semanage_remove_directory(src);
|
|
+}
|
|
|
|
/* Copies all of the files from src to dst, recursing into
|
|
* subdirectories. Returns 0 on success, -1 on error. */
|
|
@@ -1770,7 +1788,7 @@ static int semanage_commit_sandbox(semanage_handle_t * sh)
|
|
goto cleanup;
|
|
}
|
|
|
|
- if (rename(active, backup) == -1) {
|
|
+ if (semanage_rename(sh, active, backup) == -1) {
|
|
ERR(sh, "Error while renaming %s to %s.", active, backup);
|
|
retval = -1;
|
|
goto cleanup;
|
|
@@ -1779,12 +1797,12 @@ static int semanage_commit_sandbox(semanage_handle_t * sh)
|
|
/* clean up some files from the sandbox before install */
|
|
/* remove homedir_template from sandbox */
|
|
|
|
- if (rename(sandbox, active) == -1) {
|
|
+ if (semanage_rename(sh, sandbox, active) == -1) {
|
|
ERR(sh, "Error while renaming %s to %s.", sandbox, active);
|
|
/* note that if an error occurs during the next
|
|
* function then the store will be left in an
|
|
* inconsistent state */
|
|
- if (rename(backup, active) < 0)
|
|
+ if (semanage_rename(sh, backup, active) < 0)
|
|
ERR(sh, "Error while renaming %s back to %s.", backup,
|
|
active);
|
|
retval = -1;
|
|
@@ -1795,10 +1813,10 @@ static int semanage_commit_sandbox(semanage_handle_t * sh)
|
|
* function then the store will be left in an
|
|
* inconsistent state */
|
|
int errsv = errno;
|
|
- if (rename(active, sandbox) < 0)
|
|
+ if (semanage_rename(sh, active, sandbox) < 0)
|
|
ERR(sh, "Error while renaming %s back to %s.", active,
|
|
sandbox);
|
|
- else if (rename(backup, active) < 0)
|
|
+ else if (semanage_rename(sh, backup, active) < 0)
|
|
ERR(sh, "Error while renaming %s back to %s.", backup,
|
|
active);
|
|
else
|
|
--
|
|
2.36.0
|
|
|