1
0
mirror of https://github.com/systemd/systemd synced 2026-03-25 16:25:04 +01:00

Compare commits

..

4 Commits

Author SHA1 Message Date
Mike Yuan
7524671f74
core/execute-serialize: do not gracefully skip unknown image policies in executor (#40062) 2025-12-12 16:20:14 +01:00
Daan De Meyer
0859fe3f32 discover-image: Rework image_make()
Currently, image_new() will calculate the image
path as the combination of dir_path and filename,
which is completely broken if filename is absolute
and dir_path is set.

Let's fix this by thoroughly cleaning up the
image_make() interface. Instead of having four
different arguments to pass in the image path,
let's reduce that to two, a file descriptor and a
path. If no file descriptor is provided, we create
own ourselves by opening the given path.

The callsites are updated to pass in an existing file
descriptor when available. Path calculation is moved
to callers instead of image_make().
2025-12-12 12:25:57 +01:00
Mike Yuan
cc317bb82f
core/execute-serialize: do not gracefully skip unknown image policies in executor
Follow-up for 7c0afcdde22d3d94fd23bfd0e473c263aaf54e8a

Addresses https://github.com/systemd/systemd/pull/40060#issuecomment-3641288267

As commented, the unknown values should have been filtered out
in pid1's initial parsing already, and the communication between
pid1 and executor is entirely internal which makes the graceful
practice counterproductive.
2025-12-11 16:32:35 +01:00
Mike Yuan
f98520690c
shared/image-policy: format ", ignoring" + value msg in our usual style 2025-12-11 16:31:38 +01:00
3 changed files with 50 additions and 57 deletions

View File

@ -3740,21 +3740,21 @@ static int exec_context_deserialize(ExecContext *c, FILE *f) {
if (c->root_image_policy) if (c->root_image_policy)
return -EINVAL; /* duplicated */ return -EINVAL; /* duplicated */
r = image_policy_from_string(val, /* graceful= */ true, &c->root_image_policy); r = image_policy_from_string(val, /* graceful= */ false, &c->root_image_policy);
if (r < 0) if (r < 0)
return r; return r;
} else if ((val = startswith(l, "exec-context-mount-image-policy="))) { } else if ((val = startswith(l, "exec-context-mount-image-policy="))) {
if (c->mount_image_policy) if (c->mount_image_policy)
return -EINVAL; /* duplicated */ return -EINVAL; /* duplicated */
r = image_policy_from_string(val, /* graceful= */ true, &c->mount_image_policy); r = image_policy_from_string(val, /* graceful= */ false, &c->mount_image_policy);
if (r < 0) if (r < 0)
return r; return r;
} else if ((val = startswith(l, "exec-context-extension-image-policy="))) { } else if ((val = startswith(l, "exec-context-extension-image-policy="))) {
if (c->extension_image_policy) if (c->extension_image_policy)
return -EINVAL; /* duplicated */ return -EINVAL; /* duplicated */
r = image_policy_from_string(val, /* graceful= */ true, &c->extension_image_policy); r = image_policy_from_string(val, /* graceful= */ false, &c->extension_image_policy);
if (r < 0) if (r < 0)
return r; return r;
} else } else

View File

@ -238,7 +238,6 @@ static int image_new(
ImageClass c, ImageClass c,
const char *pretty, const char *pretty,
const char *path, const char *path,
const char *filename,
bool read_only, bool read_only,
usec_t crtime, usec_t crtime,
usec_t mtime, usec_t mtime,
@ -249,7 +248,7 @@ static int image_new(
assert(t >= 0); assert(t >= 0);
assert(t < _IMAGE_TYPE_MAX); assert(t < _IMAGE_TYPE_MAX);
assert(pretty); assert(pretty);
assert(filename); assert(path);
assert(ret); assert(ret);
i = new(Image, 1); i = new(Image, 1);
@ -273,7 +272,7 @@ static int image_new(
if (!i->name) if (!i->name)
return -ENOMEM; return -ENOMEM;
i->path = path_join(path, filename); i->path = strdup(path);
if (!i->path) if (!i->path)
return -ENOMEM; return -ENOMEM;
@ -387,10 +386,8 @@ static int image_update_quota(Image *i, int fd) {
static int image_make( static int image_make(
ImageClass c, ImageClass c,
const char *pretty, const char *pretty,
int dir_fd,
const char *dir_path,
const char *filename,
int fd, /* O_PATH fd */ int fd, /* O_PATH fd */
const char *path,
const struct stat *st, const struct stat *st,
Image **ret) { Image **ret) {
@ -398,9 +395,8 @@ static int image_make(
bool read_only; bool read_only;
int r; int r;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(path);
assert(dir_path || dir_fd == AT_FDCWD); assert(path_is_absolute(path));
assert(filename);
/* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block /* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block
* devices into /var/lib/machines/, and treat them normally. * devices into /var/lib/machines/, and treat them normally.
@ -411,7 +407,7 @@ static int image_make(
_cleanup_close_ int _fd = -EBADF; _cleanup_close_ int _fd = -EBADF;
if (fd < 0) { if (fd < 0) {
/* If we didn't get an fd passed in, then let's pin it via O_PATH now */ /* If we didn't get an fd passed in, then let's pin it via O_PATH now */
_fd = openat(dir_fd, filename, O_PATH|O_CLOEXEC); _fd = open(path, O_PATH|O_CLOEXEC);
if (_fd < 0) if (_fd < 0)
return -errno; return -errno;
@ -427,14 +423,8 @@ static int image_make(
st = &stbuf; st = &stbuf;
} }
_cleanup_free_ char *parent = NULL;
if (!dir_path) {
(void) fd_get_path(dir_fd, &parent);
dir_path = parent;
}
read_only = read_only =
(dir_path && path_startswith(dir_path, "/usr")) || path_startswith(path, "/usr") ||
(faccessat(fd, "", W_OK, AT_EACCESS|AT_EMPTY_PATH) < 0 && errno == EROFS); (faccessat(fd, "", W_OK, AT_EACCESS|AT_EMPTY_PATH) < 0 && errno == EROFS);
if (S_ISDIR(st->st_mode)) { if (S_ISDIR(st->st_mode)) {
@ -446,7 +436,7 @@ static int image_make(
if (!pretty) { if (!pretty) {
r = extract_image_basename( r = extract_image_basename(
filename, path,
image_class_suffix_to_string(c), image_class_suffix_to_string(c),
/* format_suffixes= */ NULL, /* format_suffixes= */ NULL,
&pretty_buffer, &pretty_buffer,
@ -474,8 +464,7 @@ static int image_make(
r = image_new(IMAGE_SUBVOLUME, r = image_new(IMAGE_SUBVOLUME,
c, c,
pretty, pretty,
dir_path, path,
filename,
info.read_only || read_only, info.read_only || read_only,
info.otime, info.otime,
info.ctime, info.ctime,
@ -500,8 +489,7 @@ static int image_make(
r = image_new(IMAGE_DIRECTORY, r = image_new(IMAGE_DIRECTORY,
c, c,
pretty, pretty,
dir_path, path,
filename,
read_only || (file_attr & FS_IMMUTABLE_FL), read_only || (file_attr & FS_IMMUTABLE_FL),
crtime, crtime,
0, /* we don't use mtime of stat() here, since it's not the time of last change of the tree, but only of the top-level dir */ 0, /* we don't use mtime of stat() here, since it's not the time of last change of the tree, but only of the top-level dir */
@ -512,7 +500,7 @@ static int image_make(
(*ret)->foreign_uid_owned = uid_is_foreign(st->st_uid); (*ret)->foreign_uid_owned = uid_is_foreign(st->st_uid);
return 0; return 0;
} else if (S_ISREG(st->st_mode) && endswith(filename, ".raw")) { } else if (S_ISREG(st->st_mode) && endswith(path, ".raw")) {
usec_t crtime = 0; usec_t crtime = 0;
/* It's a RAW disk image */ /* It's a RAW disk image */
@ -524,7 +512,7 @@ static int image_make(
if (!pretty) { if (!pretty) {
r = extract_image_basename( r = extract_image_basename(
filename, path,
image_class_suffix_to_string(c), image_class_suffix_to_string(c),
STRV_MAKE(".raw"), STRV_MAKE(".raw"),
&pretty_buffer, &pretty_buffer,
@ -538,8 +526,7 @@ static int image_make(
r = image_new(IMAGE_RAW, r = image_new(IMAGE_RAW,
c, c,
pretty, pretty,
dir_path, path,
filename,
!(st->st_mode & 0222) || read_only, !(st->st_mode & 0222) || read_only,
crtime, crtime,
timespec_load(&st->st_mtim), timespec_load(&st->st_mtim),
@ -562,7 +549,7 @@ static int image_make(
if (!pretty) { if (!pretty) {
r = extract_image_basename( r = extract_image_basename(
filename, path,
/* class_suffix= */ NULL, /* class_suffix= */ NULL,
/* format_suffix= */ NULL, /* format_suffix= */ NULL,
&pretty_buffer, &pretty_buffer,
@ -575,20 +562,20 @@ static int image_make(
_cleanup_close_ int block_fd = fd_reopen(fd, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY); _cleanup_close_ int block_fd = fd_reopen(fd, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
if (block_fd < 0) if (block_fd < 0)
log_debug_errno(errno, "Failed to open block device %s/%s, ignoring: %m", strnull(dir_path), filename); log_debug_errno(errno, "Failed to open block device '%s', ignoring: %m", path);
else { else {
if (!read_only) { if (!read_only) {
int state = 0; int state = 0;
if (ioctl(block_fd, BLKROGET, &state) < 0) if (ioctl(block_fd, BLKROGET, &state) < 0)
log_debug_errno(errno, "Failed to issue BLKROGET on device %s/%s, ignoring: %m", strnull(dir_path), filename); log_debug_errno(errno, "Failed to issue BLKROGET on device '%s', ignoring: %m", path);
else if (state) else if (state)
read_only = true; read_only = true;
} }
r = blockdev_get_device_size(block_fd, &size); r = blockdev_get_device_size(block_fd, &size);
if (r < 0) if (r < 0)
log_debug_errno(r, "Failed to issue BLKGETSIZE64 on device %s/%s, ignoring: %m", strnull(dir_path), filename); log_debug_errno(r, "Failed to issue BLKGETSIZE64 on device '%s', ignoring: %m", path);
block_fd = safe_close(block_fd); block_fd = safe_close(block_fd);
} }
@ -596,8 +583,7 @@ static int image_make(
r = image_new(IMAGE_BLOCK, r = image_new(IMAGE_BLOCK,
c, c,
pretty, pretty,
dir_path, path,
filename,
!(st->st_mode & 0222) || read_only, !(st->st_mode & 0222) || read_only,
0, 0,
0, 0,
@ -773,11 +759,11 @@ int image_find(RuntimeScope scope,
if (r < 0) if (r < 0)
return r; return r;
STRV_FOREACH(path, search) { STRV_FOREACH(s, search) {
_cleanup_free_ char *resolved = NULL; _cleanup_free_ char *resolved = NULL;
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d); r = chase_and_opendir(*s, root, CHASE_PREFIX_ROOT, &resolved, &d);
if (r == -ENOENT) if (r == -ENOENT)
continue; continue;
if (r < 0) if (r < 0)
@ -848,7 +834,7 @@ int image_find(RuntimeScope scope,
/* Refresh the stat data for the discovered target */ /* Refresh the stat data for the discovered target */
st = result.st; st = result.st;
fd = safe_close(fd); close_and_replace(fd, result.fd);
_cleanup_free_ char *bn = NULL; _cleanup_free_ char *bn = NULL;
r = path_extract_filename(result.path, &bn); r = path_extract_filename(result.path, &bn);
@ -868,7 +854,11 @@ int image_find(RuntimeScope scope,
continue; continue;
} }
r = image_make(class, name, dirfd(d), resolved, fname, fd, &st, ret); _cleanup_free_ char *path = path_join(resolved, fname);
if (!path)
return -ENOMEM;
r = image_make(class, name, fd, path, &st, ret);
if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
continue; continue;
if (r < 0) if (r < 0)
@ -884,10 +874,8 @@ int image_find(RuntimeScope scope,
if (scope == RUNTIME_SCOPE_SYSTEM && class == IMAGE_MACHINE && streq(name, ".host")) { if (scope == RUNTIME_SCOPE_SYSTEM && class == IMAGE_MACHINE && streq(name, ".host")) {
r = image_make(class, r = image_make(class,
".host", ".host",
/* dir_fd= */ AT_FDCWD,
/* dir_path= */ NULL,
/* filename= */ empty_to_root(root),
/* fd= */ -EBADF, /* fd= */ -EBADF,
/* path= */ empty_to_root(root),
/* st= */ NULL, /* st= */ NULL,
ret); ret);
if (r < 0) if (r < 0)
@ -903,6 +891,7 @@ int image_find(RuntimeScope scope,
}; };
int image_from_path(const char *path, Image **ret) { int image_from_path(const char *path, Image **ret) {
int r;
/* Note that we don't set the 'discoverable' field of the returned object, because we don't check here whether /* Note that we don't set the 'discoverable' field of the returned object, because we don't check here whether
* the image is in the image search path. And if it is we don't know if the path we used is actually not * the image is in the image search path. And if it is we don't know if the path we used is actually not
@ -912,20 +901,21 @@ int image_from_path(const char *path, Image **ret) {
return image_make( return image_make(
IMAGE_MACHINE, IMAGE_MACHINE,
".host", ".host",
/* dir_fd= */ AT_FDCWD,
/* dir_path= */ NULL,
/* filename= */ "/",
/* fd= */ -EBADF, /* fd= */ -EBADF,
/* path= */ "/",
/* st= */ NULL, /* st= */ NULL,
ret); ret);
_cleanup_free_ char *absolute = NULL;
r = path_make_absolute_cwd(path, &absolute);
if (r < 0)
return r;
return image_make( return image_make(
_IMAGE_CLASS_INVALID, _IMAGE_CLASS_INVALID,
/* pretty= */ NULL, /* pretty= */ NULL,
/* dir_fd= */ AT_FDCWD,
/* dir_path= */ NULL,
/* filename= */ path,
/* fd= */ -EBADF, /* fd= */ -EBADF,
absolute,
/* st= */ NULL, /* st= */ NULL,
ret); ret);
} }
@ -964,11 +954,11 @@ int image_discover(
if (r < 0) if (r < 0)
return r; return r;
STRV_FOREACH(path, search) { STRV_FOREACH(s, search) {
_cleanup_free_ char *resolved = NULL; _cleanup_free_ char *resolved = NULL;
_cleanup_closedir_ DIR *d = NULL; _cleanup_closedir_ DIR *d = NULL;
r = chase_and_opendir(*path, root, CHASE_PREFIX_ROOT, &resolved, &d); r = chase_and_opendir(*s, root, CHASE_PREFIX_ROOT, &resolved, &d);
if (r == -ENOENT) if (r == -ENOENT)
continue; continue;
if (r < 0) if (r < 0)
@ -1056,7 +1046,7 @@ int image_discover(
/* Refresh the stat data for the discovered target */ /* Refresh the stat data for the discovered target */
st = result.st; st = result.st;
fd = safe_close(fd); close_and_replace(fd, result.fd);
_cleanup_free_ char *bn = NULL; _cleanup_free_ char *bn = NULL;
r = path_extract_filename(result.path, &bn); r = path_extract_filename(result.path, &bn);
@ -1070,6 +1060,7 @@ int image_discover(
return log_oom(); return log_oom();
fname = fname_buf; fname = fname_buf;
} else { } else {
r = extract_image_basename( r = extract_image_basename(
fname, fname,
@ -1102,7 +1093,11 @@ int image_discover(
if (hashmap_contains(*images, pretty)) if (hashmap_contains(*images, pretty))
continue; continue;
r = image_make(class, pretty, dirfd(d), resolved, fname, fd, &st, &image); _cleanup_free_ char *path = path_join(resolved, fname);
if (!path)
return -ENOMEM;
r = image_make(class, pretty, fd, path, &st, &image);
if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) if (IN_SET(r, -ENOENT, -EMEDIUMTYPE))
continue; continue;
if (r < 0) if (r < 0)
@ -1123,10 +1118,8 @@ int image_discover(
r = image_make(IMAGE_MACHINE, r = image_make(IMAGE_MACHINE,
".host", ".host",
/* dir_fd= */ AT_FDCWD,
/* dir_path= */ NULL,
empty_to_root(root),
/* fd= */ -EBADF, /* fd= */ -EBADF,
/* path= */ empty_to_root(root),
/* st= */ NULL, /* st= */ NULL,
&image); &image);
if (r < 0) if (r < 0)

View File

@ -231,7 +231,7 @@ PartitionPolicyFlags partition_policy_flags_from_string(const char *s, bool grac
ff = policy_flag_from_string_one(strstrip(f)); ff = policy_flag_from_string_one(strstrip(f));
if (ff < 0) { if (ff < 0) {
if (graceful) { if (graceful) {
log_debug("Unknown partition policy flag: %s, ignoring", f); log_debug("Unknown partition policy flag, ignoring: %s", f);
continue; continue;
} }
return -EBADRQC; /* recognizable error */ return -EBADRQC; /* recognizable error */
@ -345,7 +345,7 @@ int image_policy_from_string(const char *s, bool graceful, ImagePolicy **ret) {
if (!graceful) if (!graceful)
return log_debug_errno(SYNTHETIC_ERRNO(EBADSLT), "Unknown partition designator: %s", ds); /* recognizable error */ return log_debug_errno(SYNTHETIC_ERRNO(EBADSLT), "Unknown partition designator: %s", ds); /* recognizable error */
log_debug("Unknown partition designator: %s, ignoring", ds); log_debug("Unknown partition designator, ignoring: %s", ds);
continue; continue;
} }
if (dmask & (UINT64_C(1) << designator)) if (dmask & (UINT64_C(1) << designator))