-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
relabel-etc: Split remount into, remount and relabel-etc #3267
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,6 +38,7 @@ endif | |
if BUILDOPT_SYSTEMD | ||
systemdsystemunit_DATA = src/boot/ostree-prepare-root.service \ | ||
src/boot/ostree-remount.service \ | ||
src/boot/ostree-relabel-etc.service \ | ||
src/boot/ostree-boot-complete.service \ | ||
src/boot/ostree-finalize-staged.service \ | ||
src/boot/ostree-finalize-staged.path \ | ||
|
@@ -71,6 +72,7 @@ EXTRA_DIST += src/boot/dracut/module-setup.sh \ | |
src/boot/ostree-prepare-root.service \ | ||
src/boot/ostree-finalize-staged.path \ | ||
src/boot/ostree-remount.service \ | ||
src/boot/ostree-relabel-etc.service \ | ||
src/boot/ostree-finalize-staged.service \ | ||
src/boot/ostree-finalize-staged-hold.service \ | ||
src/boot/[email protected] \ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# Copyright (C) 2013 Colin Walters <[email protected]> | ||
# | ||
# This library is free software; you can redistribute it and/or | ||
# modify it under the terms of the GNU Lesser General Public | ||
# License as published by the Free Software Foundation; either | ||
# version 2 of the License, or (at your option) any later version. | ||
# | ||
# This library is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
# Lesser General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU Lesser General Public | ||
# License along with this library. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
[Unit] | ||
Description=OSTree Relabel etc | ||
Documentation=man:ostree(1) | ||
DefaultDependencies=no | ||
ConditionKernelCommandLine=ostree | ||
OnFailure=emergency.target | ||
Conflicts=umount.target | ||
# Run after core mounts | ||
After=-.mount var.mount | ||
After=systemd-remount-fs.service | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one can (and should) be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK I was thinking about this more and I think we're in a situation where actually we tell people using composefs in particular to just mount the rootfs writable in the initramfs, so the whole role of systemd-remount-fs.service is a no-op from our PoV basically. At least...I thought we enforced that, but now I can't find it. |
||
# But we run *before* most other core bootup services that need write access to /etc and /var | ||
Before=local-fs.target umount.target | ||
Before=systemd-random-seed.service plymouth-read-write.service systemd-journal-flush.service systemd-sysusers.service | ||
Before=systemd-tmpfiles-setup.service systemd-rfkill.service systemd-rfkill.socket | ||
Comment on lines
+28
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can drop all this stuff, as all of that is But I'm fine going belt-and-suspenders here with e.g. To combine all this I'd suggest:
|
||
|
||
[Service] | ||
Type=oneshot | ||
RemainAfterExit=yes | ||
ExecStart=/usr/lib/ostree/ostree-relabel-etc | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, so far we haven't introduced many new little binaries, but instead we've been tending to dispatch via hidden CLI verbs, see e.g. |
||
StandardInput=null | ||
StandardOutput=journal | ||
StandardError=journal+console | ||
|
||
[Install] | ||
WantedBy=local-fs.target |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -109,6 +109,11 @@ require_internal_units (const char *normal_dir, const char *early_dir, const cha | |
< 0) | ||
return glnx_throw_errno_prefix (error, "symlinkat"); | ||
|
||
if (symlinkat (SYSTEM_DATA_UNIT_PATH "/ostree-relabel-etc.service", normal_dir_dfd, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm OK with this as is, but just a note: I think we can change things so that the initramfs code itself acts as a generator and writes the enablement symlink into As is it's a bit silly because the initramfs writes the file in |
||
"local-fs.target.requires/ostree-relabel-etc.service") | ||
< 0) | ||
return glnx_throw_errno_prefix (error, "symlinkat"); | ||
|
||
if (!glnx_shutil_mkdir_p_at (normal_dir_dfd, "multi-user.target.wants", 0755, cancellable, error)) | ||
return FALSE; | ||
if (symlinkat (SYSTEM_DATA_UNIT_PATH "/ostree-finalize-staged.path", normal_dir_dfd, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
/* | ||
* Copyright (C) 2011 Colin Walters <[email protected]> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tangentially related, I think you can update this to be you and or/alex, or just say (C) Red Hat, Inc. |
||
* | ||
* SPDX-License-Identifier: LGPL-2.0+ | ||
* | ||
* This library is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 2 of the License, or (at your option) any later version. | ||
* | ||
* This library is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library. If not, see <https://www.gnu.org/licenses/>. | ||
* | ||
* Author: Colin Walters <[email protected]> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've been dropping this in new code BTW, "git log" is source of truth and I don't think I wrote any of this code. |
||
*/ | ||
|
||
#include "config.h" | ||
|
||
#include <err.h> | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <stdarg.h> | ||
#include <stdbool.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/mount.h> | ||
#include <sys/param.h> | ||
#include <sys/stat.h> | ||
#include <sys/statvfs.h> | ||
#include <unistd.h> | ||
#ifdef HAVE_SELINUX | ||
#include <selinux/restorecon.h> | ||
#endif | ||
|
||
#include "ostree-mount-util.h" | ||
#include "otcore.h" | ||
|
||
/* Relabel the directory $real_path, which is going to be an overlayfs mount, | ||
* based on the content of an overlayfs upperdirectory that is in use by the mount. | ||
* The goal is that we relabel in the overlay mount all the files that have been | ||
* modified (directly or via parent copyup operations) since the overlayfs was | ||
* mounted. This will be used for the /etc overlayfs mount where no selinux labels | ||
* are set before selinux policy is loaded. | ||
*/ | ||
static void | ||
relabel_dir_for_upper (const char *upper_path, const char *real_path, gboolean is_dir) | ||
{ | ||
#ifdef HAVE_SELINUX | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optional: I think this entire binary could become conditional on SELinux actually, i.e. we don't even compile or ship it if built without selinux support. |
||
/* Ignore ENOENT, because if there is no file to relabel we can continue, | ||
* systemd-sysusers runs in parallel and can create temporary files in /etc | ||
* causing failures like: | ||
* "Failed to relabel /etc/.#gshadowJzu4Rx: No such file or directory" | ||
*/ | ||
if (selinux_restorecon (real_path, 0)) | ||
{ | ||
if (errno == ENOENT) | ||
return; | ||
|
||
err (EXIT_FAILURE, "Failed to relabel %s", real_path); | ||
} | ||
|
||
if (!is_dir) | ||
return; | ||
|
||
g_auto (GLnxDirFdIterator) dfd_iter = { | ||
0, | ||
}; | ||
|
||
if (!glnx_dirfd_iterator_init_at (AT_FDCWD, upper_path, FALSE, &dfd_iter, NULL)) | ||
err (EXIT_FAILURE, "Failed to open upper directory %s for relabeling", upper_path); | ||
|
||
while (TRUE) | ||
{ | ||
struct dirent *dent; | ||
|
||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, NULL, NULL)) | ||
{ | ||
err (EXIT_FAILURE, "Failed to read upper directory %s for relabelin", upper_path); | ||
break; | ||
} | ||
|
||
if (dent == NULL) | ||
break; | ||
|
||
g_autofree char *upper_child = g_build_filename (upper_path, dent->d_name, NULL); | ||
g_autofree char *real_child = g_build_filename (real_path, dent->d_name, NULL); | ||
relabel_dir_for_upper (upper_child, real_child, dent->d_type == DT_DIR); | ||
} | ||
#endif | ||
} | ||
|
||
int | ||
main (int argc, char *argv[]) | ||
{ | ||
g_autoptr (GError) error = NULL; | ||
g_autoptr (GVariant) ostree_run_metadata_v = NULL; | ||
{ | ||
glnx_autofd int fd = open (OTCORE_RUN_BOOTED, O_RDONLY | O_CLOEXEC); | ||
if (fd < 0) | ||
{ | ||
/* We really expect that nowadays that everything is done in the initramfs, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't need this copy here. |
||
* but historically we created this file here, so we'll continue to do be | ||
* sure here it exists. This code should be removed at some point though. | ||
*/ | ||
if (errno == ENOENT) | ||
{ | ||
int subfd = open (OTCORE_RUN_BOOTED, O_EXCL | O_CREAT | O_WRONLY | O_NOCTTY | O_CLOEXEC, | ||
0640); | ||
if (subfd != -1) | ||
(void)close (subfd); | ||
} | ||
else | ||
{ | ||
err (EXIT_FAILURE, "failed to open %s", OTCORE_RUN_BOOTED); | ||
} | ||
} | ||
else | ||
{ | ||
if (!ot_variant_read_fd (fd, 0, G_VARIANT_TYPE_VARDICT, TRUE, &ostree_run_metadata_v, | ||
&error)) | ||
errx (EXIT_FAILURE, "failed to read %s: %s", OTCORE_RUN_BOOTED, error->message); | ||
} | ||
} | ||
|
||
g_autoptr (GVariantDict) ostree_run_metadata = g_variant_dict_new (ostree_run_metadata_v); | ||
const char *transient_etc = NULL; | ||
g_variant_dict_lookup (ostree_run_metadata, OTCORE_RUN_BOOTED_KEY_TRANSIENT_ETC, "&s", | ||
&transient_etc); | ||
if (transient_etc) | ||
{ | ||
/* If the initramfs created any files in /etc (directly or via overlay copy-up) they | ||
* will be unlabeled, because the selinux policy is not loaded until after the | ||
* pivot-root. So, for all files in the upper dir, relabel the corresponding overlay | ||
* file. | ||
* | ||
* Also, note that during boot systemd will create a /run/machine-id -> | ||
* /etc/machine-id bind mount (as /etc is read-only early on). It will then later | ||
* replace this mount with a real one (in systemd-machine-id-commit.service). | ||
* | ||
* We need to label the actual overlayfs file, not the temporary bind-mount. To do | ||
* this we unmount the covering mount before relabeling, but we do so in a temporary | ||
* private namespace to avoid affecting other parts of the system. | ||
*/ | ||
|
||
glnx_autofd int initial_ns_fd = -1; | ||
if (g_file_test ("/run/machine-id", G_FILE_TEST_EXISTS) | ||
&& g_file_test ("/etc/machine-id", G_FILE_TEST_EXISTS)) | ||
{ | ||
initial_ns_fd = open ("/proc/self/ns/mnt", O_RDONLY | O_NOCTTY | O_CLOEXEC); | ||
if (initial_ns_fd < 0) | ||
err (EXIT_FAILURE, "Failed to open initial namespace"); | ||
|
||
if (unshare (CLONE_NEWNS) < 0) | ||
err (EXIT_FAILURE, "Failed to unshare initial namespace"); | ||
|
||
/* Ensure unmount is not propagated */ | ||
if (mount ("none", "/etc", NULL, MS_REC | MS_PRIVATE, NULL) < 0) | ||
err (EXIT_FAILURE, "warning: While remounting /etc MS_PRIVATE"); | ||
|
||
if (umount2 ("/etc/machine-id", MNT_DETACH) < 0) | ||
err (EXIT_FAILURE, "Failed to unmount machine-id"); | ||
} | ||
|
||
g_autofree char *upper = g_build_filename (transient_etc, "upper", NULL); | ||
relabel_dir_for_upper (upper, "/etc", TRUE); | ||
|
||
if (initial_ns_fd != -1 && setns (initial_ns_fd, CLONE_NEWNS) < 0) | ||
err (EXIT_FAILURE, "Failed to join initial namespace"); | ||
} | ||
|
||
exit (EXIT_SUCCESS); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't need
var.mount
here.Actually let's just use:
RequiresMountsFor=/etc
.