mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
Introduce ERRNO_IS_FS_WRITE_REFUSED(), and use it in binfmt_mounted() (#38117)
- This introduces ERRNO_IS_FS_WRITE_REFUSED(), and apply it where usable. - This makes unexpected errors in access_fd() called by binfmt_mounted() propagated to the caller. - Renames binfmt_mounted() to binfmt_mounted_and_writable(), as it also checks the fs is writable. - Voidifies one disable_binfmt() call in shutdown.c.
This commit is contained in:
@@ -188,6 +188,12 @@ static inline bool ERRNO_IS_NEG_PRIVILEGE(intmax_t r) {
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(PRIVILEGE);
|
||||
|
||||
/* Three different errors for writing on a filesystem */
|
||||
static inline bool ERRNO_IS_NEG_FS_WRITE_REFUSED(intmax_t r) {
|
||||
return r == -EROFS || ERRNO_IS_NEG_PRIVILEGE(r);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(FS_WRITE_REFUSED);
|
||||
|
||||
/* Three different errors for "not enough disk space" */
|
||||
static inline bool ERRNO_IS_NEG_DISK_SPACE(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
|
||||
@@ -193,10 +193,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int binfmt_mounted_warn(void) {
|
||||
static int binfmt_mounted_and_writable_warn(void) {
|
||||
int r;
|
||||
|
||||
r = binfmt_mounted();
|
||||
r = binfmt_mounted_and_writable();
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to check if /proc/sys/fs/binfmt_misc is mounted: %m");
|
||||
if (r == 0)
|
||||
@@ -222,7 +222,7 @@ static int run(int argc, char *argv[]) {
|
||||
return disable_binfmt();
|
||||
|
||||
if (argc > optind) {
|
||||
r = binfmt_mounted_warn();
|
||||
r = binfmt_mounted_and_writable_warn();
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
@@ -239,7 +239,7 @@ static int run(int argc, char *argv[]) {
|
||||
if (arg_cat_flags != CAT_CONFIG_OFF)
|
||||
return cat_config(files);
|
||||
|
||||
r = binfmt_mounted_warn();
|
||||
r = binfmt_mounted_and_writable_warn();
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
/* Returns the log level to use when cgroup attribute writes fail. When an attribute is missing or we have access
|
||||
* problems we downgrade to LOG_DEBUG. This is supposed to be nice to container managers and kernels which want to mask
|
||||
* out specific attributes from us. */
|
||||
#define LOG_LEVEL_CGROUP_WRITE(r) (IN_SET(ABS(r), ENOENT, EROFS, EACCES, EPERM) ? LOG_DEBUG : LOG_WARNING)
|
||||
#define LOG_LEVEL_CGROUP_WRITE(r) ((ABS(r) == ENOENT || ERRNO_IS_FS_WRITE_REFUSED(r)) ? LOG_DEBUG : LOG_WARNING)
|
||||
|
||||
static void unit_remove_from_cgroup_empty_queue(Unit *u);
|
||||
|
||||
|
||||
@@ -1271,8 +1271,8 @@ static void bump_file_max_and_nr_open(void) {
|
||||
* different, but the operation would fail silently.) */
|
||||
r = sysctl_write("fs/file-max", LONG_MAX_STR);
|
||||
if (r < 0)
|
||||
log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING,
|
||||
r, "Failed to bump fs.file-max, ignoring: %m");
|
||||
log_full_errno(ERRNO_IS_NEG_FS_WRITE_REFUSED(r) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to bump fs.file-max, ignoring: %m");
|
||||
#endif
|
||||
|
||||
#if BUMP_PROC_SYS_FS_NR_OPEN
|
||||
@@ -1293,7 +1293,8 @@ static void bump_file_max_and_nr_open(void) {
|
||||
continue;
|
||||
}
|
||||
if (r < 0) {
|
||||
log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to bump fs.nr_open, ignoring: %m");
|
||||
log_full_errno(ERRNO_IS_NEG_FS_WRITE_REFUSED(r) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to bump fs.nr_open, ignoring: %m");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1534,7 +1535,7 @@ static int bump_unix_max_dgram_qlen(void) {
|
||||
|
||||
r = sysctl_write("net/unix/max_dgram_qlen", STRINGIFY(DEFAULT_UNIX_MAX_DGRAM_QLEN));
|
||||
if (r < 0)
|
||||
return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
return log_full_errno(ERRNO_IS_NEG_FS_WRITE_REFUSED(r) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to bump AF_UNIX datagram queue length, ignoring: %m");
|
||||
|
||||
return 1;
|
||||
|
||||
@@ -1269,7 +1269,7 @@ static void mount_enter_mounting(Mount *m) {
|
||||
* when the path is on NFS. See issue #24120. All such errors will be logged in the debug level. */
|
||||
if (r < 0 && r != -EEXIST)
|
||||
log_unit_full_errno(UNIT(m),
|
||||
(r == -EROFS || ERRNO_IS_PRIVILEGE(r)) ? LOG_DEBUG : LOG_WARNING,
|
||||
ERRNO_IS_NEG_FS_WRITE_REFUSED(r) ? LOG_DEBUG : LOG_WARNING,
|
||||
r, "Failed to make bind mount source '%s', ignoring: %m", p->what);
|
||||
}
|
||||
|
||||
|
||||
@@ -1907,14 +1907,14 @@ static int setup_timezone(const char *dest) {
|
||||
log_debug_errno(r, "Timezone %s does not exist (or is not accessible) in container, not creating symlink: %m", z);
|
||||
else {
|
||||
if (unlink(where) < 0 && errno != ENOENT) {
|
||||
log_full_errno(IN_SET(errno, EROFS, EACCES, EPERM) ? LOG_DEBUG : LOG_WARNING, /* Don't complain on read-only images */
|
||||
log_full_errno(ERRNO_IS_FS_WRITE_REFUSED(errno) ? LOG_DEBUG : LOG_WARNING, /* Don't complain on read-only images */
|
||||
errno, "Failed to remove existing timezone info %s in container, ignoring: %m", where);
|
||||
return 0;
|
||||
}
|
||||
|
||||
what = strjoina("../usr/share/zoneinfo/", z);
|
||||
if (symlink(what, where) < 0) {
|
||||
log_full_errno(IN_SET(errno, EROFS, EACCES, EPERM) ? LOG_DEBUG : LOG_WARNING,
|
||||
log_full_errno(ERRNO_IS_FS_WRITE_REFUSED(errno) ? LOG_DEBUG : LOG_WARNING,
|
||||
errno, "Failed to correct timezone of container, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
@@ -1949,7 +1949,7 @@ static int setup_timezone(const char *dest) {
|
||||
/* If mounting failed, try to copy */
|
||||
r = copy_file_atomic("/etc/localtime", where, 0644, COPY_REFLINK|COPY_REPLACE);
|
||||
if (r < 0) {
|
||||
log_full_errno(IN_SET(r, -EROFS, -EACCES, -EPERM) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
log_full_errno(ERRNO_IS_NEG_FS_WRITE_REFUSED(r) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to copy /etc/localtime to %s, ignoring: %m", where);
|
||||
return 0;
|
||||
}
|
||||
@@ -2085,7 +2085,7 @@ static int setup_resolv_conf(const char *dest) {
|
||||
* If the disk image is read-only, there's also no point in complaining.
|
||||
*/
|
||||
log_full_errno(!IN_SET(RESOLV_CONF_COPY_HOST, RESOLV_CONF_COPY_STATIC, RESOLV_CONF_COPY_UPLINK, RESOLV_CONF_COPY_STUB) &&
|
||||
IN_SET(r, -ELOOP, -EROFS, -EACCES, -EPERM) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
(r == -ELOOP || ERRNO_IS_NEG_FS_WRITE_REFUSED(r)) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to copy /etc/resolv.conf to %s, ignoring: %m", where);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "missing_magic.h"
|
||||
#include "stat-util.h"
|
||||
|
||||
int binfmt_mounted(void) {
|
||||
int binfmt_mounted_and_writable(void) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
@@ -25,7 +25,13 @@ int binfmt_mounted(void) {
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
return access_fd(fd, W_OK) >= 0;
|
||||
r = access_fd(fd, W_OK);
|
||||
if (ERRNO_IS_NEG_FS_WRITE_REFUSED(r))
|
||||
return false;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int disable_binfmt(void) {
|
||||
@@ -37,7 +43,7 @@ int disable_binfmt(void) {
|
||||
* We are a bit careful here, since binfmt_misc might still be an autofs which we don't want to
|
||||
* trigger. */
|
||||
|
||||
r = binfmt_mounted();
|
||||
r = binfmt_mounted_and_writable();
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "Failed to determine whether binfmt_misc is mounted: %m");
|
||||
if (r == 0) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
int binfmt_mounted(void);
|
||||
int binfmt_mounted_and_writable(void);
|
||||
int disable_binfmt(void);
|
||||
|
||||
@@ -660,7 +660,7 @@ int loop_device_make_by_path_at(
|
||||
r = fd;
|
||||
|
||||
/* Retry read-only? */
|
||||
if (open_flags >= 0 || !(ERRNO_IS_PRIVILEGE(r) || r == -EROFS))
|
||||
if (open_flags >= 0 || !ERRNO_IS_NEG_FS_WRITE_REFUSED(r))
|
||||
return r;
|
||||
|
||||
fd = xopenat(dir_fd, path, basic_flags|direct_flags|O_RDONLY);
|
||||
|
||||
@@ -447,7 +447,7 @@ int main(int argc, char *argv[]) {
|
||||
(void) sync_with_progress(-EBADF);
|
||||
|
||||
disable_coredumps();
|
||||
disable_binfmt();
|
||||
(void) disable_binfmt();
|
||||
|
||||
log_info("Sending SIGTERM to remaining processes...");
|
||||
broadcast_signal(SIGTERM, true, true, arg_timeout);
|
||||
|
||||
@@ -321,7 +321,7 @@ static int add_export_unix_socket(
|
||||
log_debug("Container manager does not provide /run/host/unix-export/ mount, not binding AF_UNIX socket there.");
|
||||
return 0;
|
||||
}
|
||||
if (errno == EROFS || ERRNO_IS_PRIVILEGE(errno)) {
|
||||
if (ERRNO_IS_FS_WRITE_REFUSED(errno)) {
|
||||
log_debug("Container manager does not provide write access to /run/host/unix-export/, not binding AF_UNIX socket there.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ static int sysctl_write_or_warn(const char *key, const char *value, bool ignore_
|
||||
* permission problem here, since that's how container managers usually protected their
|
||||
* sysctls.)
|
||||
* In all other cases log an error and make the tool fail. */
|
||||
if (ignore_failure || (!arg_strict && (r == -EROFS || ERRNO_IS_PRIVILEGE(r))))
|
||||
if (ignore_failure || (!arg_strict && ERRNO_IS_NEG_FS_WRITE_REFUSED(r)))
|
||||
log_debug_errno(r, "Couldn't write '%s' to '%s', ignoring: %m", value, key);
|
||||
else if (ignore_enoent && r == -ENOENT)
|
||||
log_warning_errno(r, "Couldn't write '%s' to '%s', ignoring: %m", value, key);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include "binfmt-util.h"
|
||||
#include "tests.h"
|
||||
|
||||
TEST(binfmt_mounted) {
|
||||
ASSERT_OK(binfmt_mounted());
|
||||
TEST(binfmt_mounted_and_writable) {
|
||||
ASSERT_OK(binfmt_mounted_and_writable());
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
|
||||
@@ -64,10 +64,8 @@ TEST(cg_create) {
|
||||
(void) cg_trim(test_b, /* delete_root= */ true);
|
||||
|
||||
r = cg_create(test_a);
|
||||
if (IN_SET(r, -EPERM, -EACCES, -EROFS)) {
|
||||
log_info_errno(r, "Skipping %s: %m", __func__);
|
||||
return;
|
||||
}
|
||||
if (ERRNO_IS_NEG_FS_WRITE_REFUSED(r))
|
||||
return (void) log_tests_skipped_errno(r, "%s: Failed to create cgroup %s", __func__, test_a);
|
||||
|
||||
ASSERT_OK_EQ(r, 1);
|
||||
ASSERT_OK_ZERO(cg_create(test_a));
|
||||
|
||||
@@ -51,7 +51,7 @@ int main(int argc, char *argv[]) {
|
||||
log_info("Reducing limit by one to %"PRIu64"…", limit-1);
|
||||
|
||||
r = procfs_tasks_set_limit(limit-1);
|
||||
if (IN_SET(r, -ENOENT, -EROFS) || ERRNO_IS_PRIVILEGE(r))
|
||||
if (r == -ENOENT || ERRNO_IS_NEG_FS_WRITE_REFUSED(r))
|
||||
return log_tests_skipped_errno(r, "can't set tasks limit");
|
||||
assert_se(r >= 0);
|
||||
|
||||
|
||||
@@ -54,14 +54,14 @@ TEST(sysctl_read) {
|
||||
assert_se(STR_IN_SET(s, "0", "1"));
|
||||
|
||||
r = sysctl_write_ip_property(AF_INET, "lo", "forwarding", s, NULL);
|
||||
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || r == -EROFS);
|
||||
assert_se(r >= 0 || ERRNO_IS_NEG_FS_WRITE_REFUSED(r));
|
||||
s = mfree(s);
|
||||
|
||||
assert_se(sysctl_read_ip_property(AF_INET, NULL, "ip_forward", &s));
|
||||
assert_se(STR_IN_SET(s, "0", "1"));
|
||||
|
||||
r = sysctl_write_ip_property(AF_INET, NULL, "ip_forward", s, NULL);
|
||||
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || r == -EROFS);
|
||||
assert_se(r >= 0 || ERRNO_IS_NEG_FS_WRITE_REFUSED(r));
|
||||
s = mfree(s);
|
||||
|
||||
assert_se(sysctl_read("kernel/hostname", &s) >= 0);
|
||||
@@ -69,7 +69,7 @@ TEST(sysctl_read) {
|
||||
ASSERT_STREQ(s, u.nodename);
|
||||
|
||||
r = sysctl_write("kernel/hostname", s);
|
||||
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || r == -EROFS);
|
||||
assert_se(r >= 0 || ERRNO_IS_NEG_FS_WRITE_REFUSED(r));
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_INFO);
|
||||
|
||||
Reference in New Issue
Block a user