1
0
mirror of https://github.com/systemd/systemd synced 2025-11-21 01:34:44 +01:00

Compare commits

..

No commits in common. "de2276cdcd34e8932483e66331e0ecb12f177145" and "aad0d11e7c6f1f7dcc7b00173140c74b8abf88cc" have entirely different histories.

33 changed files with 80 additions and 1154 deletions

View File

@ -3992,34 +3992,6 @@ ServerAddress=192.168.0.1/24</programlisting>
<xi:include href="version-info.xml" xpointer="v226"/></listitem> <xi:include href="version-info.xml" xpointer="v226"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>EmitDomain=</varname></term>
<listitem><para>Takes a boolean. Configures whether the DHCP leases handed out
to clients shall contain domain name information (DHCP option 15). Defaults to
<literal>no</literal>.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<varlistentry>
<term><varname>Domain=</varname></term>
<listitem><para>Takes a domain name (such as <literal>example.com</literal>)
to pass to DHCP clients. This configures the DNS default domain for DHCP clients.
When set, DHCP clients will use this as their DNS search domain.</para>
<para>When <varname>EmitDomain=yes</varname> is set but <varname>Domain=</varname>
is not configured, the domain name will be automatically derived from the system's
fully qualified hostname. For example, if the system's hostname is
<literal>host.example.com</literal>, the domain <literal>example.com</literal>
will be sent to clients. If the system's hostname does not contain a domain part
(e.g., hostname is just <literal>host</literal>), no domain name will be sent to
DHCP clients. When empty or unset, defaults to no domain name.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>BootServerAddress=</varname></term> <term><varname>BootServerAddress=</varname></term>

View File

@ -1438,10 +1438,6 @@ libarchive = dependency('libarchive',
version : '>= 3.0', version : '>= 3.0',
required : get_option('libarchive')) required : get_option('libarchive'))
conf.set10('HAVE_LIBARCHIVE', libarchive.found()) conf.set10('HAVE_LIBARCHIVE', libarchive.found())
conf.set10('HAVE_LIBARCHIVE_UID_IS_SET',
libblkid.found() and cc.has_function('archive_entry_uid_is_set', dependencies : libarchive))
conf.set10('HAVE_LIBARCHIVE_HARDLINK_IS_SET',
libblkid.found() and cc.has_function('archive_entry_hardlink_is_set', dependencies : libarchive))
libxkbcommon = dependency('xkbcommon', libxkbcommon = dependency('xkbcommon',
version : '>= 0.3.0', version : '>= 0.3.0',

View File

@ -108,10 +108,6 @@ int stat_verify_symlink(const struct stat *st) {
return 0; return 0;
} }
int fd_verify_symlink(int fd) {
return verify_stat_at(fd, /* path= */ NULL, /* follow= */ false, stat_verify_symlink, /* verify= */ true);
}
int is_symlink(const char *path) { int is_symlink(const char *path) {
assert(!isempty(path)); assert(!isempty(path));
return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false); return verify_stat_at(AT_FDCWD, path, false, stat_verify_symlink, false);

View File

@ -16,7 +16,6 @@ int is_dir_at(int fd, const char *path, bool follow);
int is_dir(const char *path, bool follow); int is_dir(const char *path, bool follow);
int stat_verify_symlink(const struct stat *st); int stat_verify_symlink(const struct stat *st);
int fd_verify_symlink(int fd);
int is_symlink(const char *path); int is_symlink(const char *path);
int stat_verify_linked(const struct stat *st); int stat_verify_linked(const struct stat *st);
@ -111,10 +110,3 @@ static inline bool stat_is_set(const struct stat *st) {
static inline bool statx_is_set(const struct statx *sx) { static inline bool statx_is_set(const struct statx *sx) {
return sx && sx->stx_mask != 0; return sx && sx->stx_mask != 0;
} }
static inline bool inode_type_can_hardlink(mode_t m) {
/* returns true for all inode types that support hardlinks on linux. Note this is effectively all
* inode types except for directories (and those weird misc fds such as eventfds() that have no inode
* type). */
return IN_SET(m & S_IFMT, S_IFSOCK, S_IFLNK, S_IFREG, S_IFBLK, S_IFCHR, S_IFIFO);
}

View File

@ -477,14 +477,3 @@ int fd_setcrtime(int fd, usec_t usec) {
"user.crtime_usec", (const char*) &le, sizeof(le), "user.crtime_usec", (const char*) &le, sizeof(le),
/* xattr_flags = */ 0); /* xattr_flags = */ 0);
} }
bool xattr_is_acl(const char *name) {
return STR_IN_SET(
ASSERT_PTR(name),
"system.posix_acl_access",
"system.posix_acl_default");
}
bool xattr_is_selinux(const char *name) {
return streq(ASSERT_PTR(name), "security.selinux");
}

View File

@ -54,6 +54,3 @@ int getcrtime_at(int fd, const char *path, int at_flags, usec_t *ret);
static inline int fd_getcrtime(int fd, usec_t *ret) { static inline int fd_getcrtime(int fd, usec_t *ret) {
return getcrtime_at(fd, NULL, 0, ret); return getcrtime_at(fd, NULL, 0, ret);
} }
bool xattr_is_acl(const char *name);
bool xattr_is_selinux(const char *name);

View File

@ -1,60 +1,71 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sched.h> #include <sched.h>
#include <sys/prctl.h> #include <sys/stat.h>
#include <unistd.h>
#include "sd-event.h" #include "sd-event.h"
#include "alloc-util.h"
#include "capability-util.h" #include "capability-util.h"
#include "dirent-util.h" #include "dirent-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h"
#include "fs-util.h" #include "fs-util.h"
#include "import-common.h" #include "import-common.h"
#include "libarchive-util.h"
#include "log.h" #include "log.h"
#include "os-util.h" #include "os-util.h"
#include "pidref.h" #include "pidref.h"
#include "process-util.h" #include "process-util.h"
#include "selinux-util.h" #include "selinux-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "tar-util.h"
#include "tmpfile-util.h" #include "tmpfile-util.h"
int import_fork_tar_x(int tree_fd, PidRef *ret_pid) { int import_fork_tar_x(const char *path, PidRef *ret) {
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
_cleanup_close_pair_ int pipefd[2] = EBADF_PAIR;
bool use_selinux;
int r; int r;
assert(tree_fd >= 0); assert(path);
assert(ret_pid); assert(ret);
r = dlopen_libarchive();
if (r < 0)
return r;
TarFlags flags = mac_selinux_use() ? TAR_SELINUX : 0;
_cleanup_close_pair_ int pipefd[2] = EBADF_PAIR;
if (pipe2(pipefd, O_CLOEXEC) < 0) if (pipe2(pipefd, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to create pipe for tar: %m"); return log_error_errno(errno, "Failed to create pipe for tar: %m");
(void) fcntl(pipefd[0], F_SETPIPE_SZ, IMPORT_BUFFER_SIZE); (void) fcntl(pipefd[0], F_SETPIPE_SZ, IMPORT_BUFFER_SIZE);
use_selinux = mac_selinux_use();
r = pidref_safe_fork_full( r = pidref_safe_fork_full(
"tar-x", "(tar)",
/* stdio_fds= */ NULL, (int[]) { pipefd[0], -EBADF, STDERR_FILENO },
(int[]) { tree_fd, pipefd[0] }, 2, NULL, 0,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_REOPEN_LOG, FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_LOG,
ret_pid); &pid);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0) { if (r == 0) {
static const uint64_t retain = const char *cmdline[] = {
"tar",
"--ignore-zeros",
"--numeric-owner",
"-C", path,
"-pxf",
"-",
"--xattrs",
"--xattrs-include=*",
use_selinux ? "--selinux" : "--no-selinux",
NULL
};
uint64_t retain =
(1ULL << CAP_CHOWN) | (1ULL << CAP_CHOWN) |
(1ULL << CAP_FOWNER) | (1ULL << CAP_FOWNER) |
(1ULL << CAP_FSETID) | (1ULL << CAP_FSETID) |
(1ULL << CAP_MKNOD) | (1ULL << CAP_MKNOD) |
(1ULL << CAP_SETFCAP) | (1ULL << CAP_SETFCAP) |
(1ULL << CAP_DAC_OVERRIDE) | (1ULL << CAP_DAC_OVERRIDE);
(1ULL << CAP_DAC_READ_SEARCH);
/* Child */ /* Child */
@ -65,15 +76,21 @@ int import_fork_tar_x(int tree_fd, PidRef *ret_pid) {
if (r < 0) if (r < 0)
log_warning_errno(r, "Failed to drop capabilities, ignoring: %m"); log_warning_errno(r, "Failed to drop capabilities, ignoring: %m");
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) /* Try "gtar" before "tar". We only test things upstream with GNU tar. Some distros appear to
log_warning_errno(errno, "Failed to enable PR_SET_NO_NEW_PRIVS, ignoring: %m"); * install a different implementation as "tar" (in particular some that do not support the
* same command line switches), but then provide "gtar" as alias for the real thing, hence
* let's prefer that. (Yes, it's a bad idea they do that, given they don't provide equivalent
* command line support, but we are not here to argue, let's just expose the same
* behaviour/implementation everywhere.) */
execvp("gtar", (char* const*) cmdline);
execvp("tar", (char* const*) cmdline);
if (tar_x(pipefd[0], tree_fd, flags) < 0) log_error_errno(errno, "Failed to execute tar: %m");
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
_exit(EXIT_SUCCESS);
} }
*ret = TAKE_PIDREF(pid);
return TAKE_FD(pipefd[1]); return TAKE_FD(pipefd[1]);
} }

View File

@ -34,7 +34,7 @@ typedef enum ImportFlags {
} ImportFlags; } ImportFlags;
int import_fork_tar_c(const char *path, PidRef *ret); int import_fork_tar_c(const char *path, PidRef *ret);
int import_fork_tar_x(int tree_fd, PidRef *ret_pid); int import_fork_tar_x(const char *path, PidRef *ret);
int import_mangle_os_tree(const char *path); int import_mangle_os_tree(const char *path);

View File

@ -45,7 +45,6 @@ typedef struct TarImport {
int input_fd; int input_fd;
int tar_fd; int tar_fd;
int tree_fd;
ImportCompress compress; ImportCompress compress;
@ -80,7 +79,6 @@ TarImport* tar_import_unref(TarImport *i) {
sd_event_unref(i->event); sd_event_unref(i->event);
safe_close(i->tar_fd); safe_close(i->tar_fd);
safe_close(i->tree_fd);
free(i->final_path); free(i->final_path);
free(i->image_root); free(i->image_root);
@ -113,7 +111,6 @@ int tar_import_new(
*i = (TarImport) { *i = (TarImport) {
.input_fd = -EBADF, .input_fd = -EBADF,
.tar_fd = -EBADF, .tar_fd = -EBADF,
.tree_fd = -EBADF,
.on_finished = on_finished, .on_finished = on_finished,
.userdata = userdata, .userdata = userdata,
.last_percent = UINT_MAX, .last_percent = UINT_MAX,
@ -175,7 +172,6 @@ static int tar_import_finish(TarImport *i) {
assert(i); assert(i);
assert(i->tar_fd >= 0); assert(i->tar_fd >= 0);
assert(i->tree_fd >= 0);
i->tar_fd = safe_close(i->tar_fd); i->tar_fd = safe_close(i->tar_fd);
@ -219,7 +215,6 @@ static int tar_import_fork_tar(TarImport *i) {
assert(!i->final_path); assert(!i->final_path);
assert(!i->temp_path); assert(!i->temp_path);
assert(i->tar_fd < 0); assert(i->tar_fd < 0);
assert(i->tree_fd < 0);
if (i->flags & IMPORT_DIRECT) { if (i->flags & IMPORT_DIRECT) {
d = i->local; d = i->local;
@ -259,11 +254,7 @@ static int tar_import_fork_tar(TarImport *i) {
(void) import_assign_pool_quota_and_warn(d); (void) import_assign_pool_quota_and_warn(d);
} }
i->tree_fd = open(d, O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); i->tar_fd = import_fork_tar_x(d, &i->tar_pid);
if (i->tree_fd < 0)
return log_error_errno(errno, "Failed to open '%s': %m", d);
i->tar_fd = import_fork_tar_x(i->tree_fd, &i->tar_pid);
if (i->tar_fd < 0) if (i->tar_fd < 0)
return i->tar_fd; return i->tar_fd;

View File

@ -10,7 +10,6 @@
#include "copy.h" #include "copy.h"
#include "curl-util.h" #include "curl-util.h"
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h"
#include "fs-util.h" #include "fs-util.h"
#include "import-common.h" #include "import-common.h"
#include "import-util.h" #include "import-util.h"
@ -62,8 +61,6 @@ typedef struct TarPull {
char *settings_temp_path; char *settings_temp_path;
char *checksum; char *checksum;
int tree_fd;
} TarPull; } TarPull;
TarPull* tar_pull_unref(TarPull *i) { TarPull* tar_pull_unref(TarPull *i) {
@ -89,8 +86,6 @@ TarPull* tar_pull_unref(TarPull *i) {
free(i->local); free(i->local);
free(i->checksum); free(i->checksum);
safe_close(i->tree_fd);
return mfree(i); return mfree(i);
} }
@ -137,7 +132,6 @@ int tar_pull_new(
.event = TAKE_PTR(e), .event = TAKE_PTR(e),
.glue = TAKE_PTR(g), .glue = TAKE_PTR(g),
.tar_pid = PIDREF_NULL, .tar_pid = PIDREF_NULL,
.tree_fd = -EBADF,
}; };
i->glue->on_finished = pull_job_curl_on_finished; i->glue->on_finished = pull_job_curl_on_finished;
@ -518,7 +512,6 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
i = j->userdata; i = j->userdata;
assert(i->tar_job == j); assert(i->tar_job == j);
assert(!pidref_is_set(&i->tar_pid)); assert(!pidref_is_set(&i->tar_pid));
assert(i->tree_fd < 0);
if (i->flags & IMPORT_DIRECT) if (i->flags & IMPORT_DIRECT)
where = i->local; where = i->local;
@ -552,11 +545,7 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
(void) import_assign_pool_quota_and_warn(where); (void) import_assign_pool_quota_and_warn(where);
} }
i->tree_fd = open(where, O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); j->disk_fd = import_fork_tar_x(where, &i->tar_pid);
if (i->tree_fd < 0)
return log_error_errno(errno, "Failed to open '%s': %m", where);
j->disk_fd = import_fork_tar_x(i->tree_fd, &i->tar_pid);
if (j->disk_fd < 0) if (j->disk_fd < 0)
return j->disk_fd; return j->disk_fd;

View File

@ -46,7 +46,6 @@ typedef struct sd_dhcp_server {
uint32_t pool_size; uint32_t pool_size;
char *timezone; char *timezone;
char *domain_name;
DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX]; DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
struct in_addr boot_server_address; struct in_addr boot_server_address;

View File

@ -128,7 +128,6 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) {
free(server->boot_server_name); free(server->boot_server_name);
free(server->boot_filename); free(server->boot_filename);
free(server->timezone); free(server->timezone);
free(server->domain_name);
for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++)
free(server->servers[i].addr); free(server->servers[i].addr);
@ -626,15 +625,6 @@ static int server_send_offer_or_ack(
return r; return r;
} }
if (server->domain_name) {
r = dhcp_option_append(
&packet->dhcp, req->max_optlen, &offset, 0,
SD_DHCP_OPTION_DOMAIN_NAME,
strlen(server->domain_name), server->domain_name);
if (r < 0)
return r;
}
/* RFC 8925 section 3.3. DHCPv4 Server Behavior /* RFC 8925 section 3.3. DHCPv4 Server Behavior
* The server MUST NOT include the IPv6-Only Preferred option in the DHCPOFFER or DHCPACK message if * The server MUST NOT include the IPv6-Only Preferred option in the DHCPOFFER or DHCPACK message if
* the option was not present in the Parameter Request List sent by the client. */ * the option was not present in the Parameter Request List sent by the client. */
@ -1425,22 +1415,6 @@ int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *tz) {
return 1; return 1;
} }
int sd_dhcp_server_set_domain_name(sd_dhcp_server *server, const char *domain_name) {
int r;
assert_return(server, -EINVAL);
if (domain_name) {
r = dns_name_is_valid(domain_name);
if (r < 0)
return r;
if (r == 0)
return -EINVAL;
}
return free_and_strdup(&server->domain_name, domain_name);
}
int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint64_t t) { int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint64_t t) {
assert_return(server, -EINVAL); assert_return(server, -EINVAL);

View File

@ -316,44 +316,6 @@ static void test_static_lease(void) {
(uint8_t*) &(uint32_t) { 0x01020306 }, sizeof(uint32_t))); (uint8_t*) &(uint32_t) { 0x01020306 }, sizeof(uint32_t)));
} }
static void test_domain_name(void) {
_cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL;
log_debug("/* %s */", __func__);
ASSERT_OK(sd_dhcp_server_new(&server, 1));
/* Test setting domain name */
ASSERT_OK_POSITIVE(sd_dhcp_server_set_domain_name(server, "example.com"));
/* Test setting same domain name (should return 0 - no change) */
ASSERT_OK_ZERO(sd_dhcp_server_set_domain_name(server, "example.com"));
/* Test changing domain name */
ASSERT_OK_POSITIVE(sd_dhcp_server_set_domain_name(server, "test.local"));
/* Test clearing domain name */
ASSERT_OK_POSITIVE(sd_dhcp_server_set_domain_name(server, NULL));
/* Test clearing again (should return 0 - already cleared) */
ASSERT_OK_ZERO(sd_dhcp_server_set_domain_name(server, NULL));
/* Test invalid domain name */
ASSERT_ERROR(sd_dhcp_server_set_domain_name(server, "invalid..domain"), EINVAL);
/* Test empty string (treated differently from NULL) */
ASSERT_OK_POSITIVE(sd_dhcp_server_set_domain_name(server, ""));
/* Test clearing domain name with NULL */
ASSERT_OK_POSITIVE(sd_dhcp_server_set_domain_name(server, NULL));
/* Test valid domain with subdomain */
ASSERT_OK_POSITIVE(sd_dhcp_server_set_domain_name(server, "sub.example.com"));
/* Test single-label domain */
ASSERT_OK_POSITIVE(sd_dhcp_server_set_domain_name(server, "local"));
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int r; int r;
@ -361,7 +323,6 @@ int main(int argc, char *argv[]) {
test_client_id_hash(); test_client_id_hash();
test_static_lease(); test_static_lease();
test_domain_name();
r = test_basic(true); r = test_basic(true);
if (r < 0) if (r < 0)

View File

@ -108,7 +108,7 @@
<defaults> <defaults>
<allow_any>auth_admin</allow_any> <allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive> <allow_inactive>auth_admin</allow_inactive>
<allow_active>yes</allow_active> <allow_active>auth_admin_keep</allow_active>
</defaults> </defaults>
</action> </action>

View File

@ -27,7 +27,6 @@
#include "loop-util.h" #include "loop-util.h"
#include "main-func.h" #include "main-func.h"
#include "memory-util.h" #include "memory-util.h"
#include "mount-util.h"
#include "namespace-util.h" #include "namespace-util.h"
#include "nsresource.h" #include "nsresource.h"
#include "nulstr-util.h" #include "nulstr-util.h"
@ -42,7 +41,6 @@
#include "time-util.h" #include "time-util.h"
#include "uid-classification.h" #include "uid-classification.h"
#include "uid-range.h" #include "uid-range.h"
#include "user-util.h"
#include "varlink-io.systemd.MountFileSystem.h" #include "varlink-io.systemd.MountFileSystem.h"
#include "varlink-util.h" #include "varlink-util.h"
@ -91,7 +89,6 @@ typedef struct MountImageParameters {
int growfs; int growfs;
char *password; char *password;
ImagePolicy *image_policy; ImagePolicy *image_policy;
bool verity_sharing;
} MountImageParameters; } MountImageParameters;
static void mount_image_parameters_done(MountImageParameters *p) { static void mount_image_parameters_done(MountImageParameters *p) {
@ -286,13 +283,12 @@ static int vl_method_mount_image(
void *userdata) { void *userdata) {
static const sd_json_dispatch_field dispatch_table[] = { static const sd_json_dispatch_field dispatch_table[] = {
{ "imageFileDescriptor", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(MountImageParameters, image_fd_idx), SD_JSON_MANDATORY }, { "imageFileDescriptor", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(MountImageParameters, image_fd_idx), SD_JSON_MANDATORY },
{ "userNamespaceFileDescriptor", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(MountImageParameters, userns_fd_idx), 0 }, { "userNamespaceFileDescriptor", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(MountImageParameters, userns_fd_idx), 0 },
{ "readOnly", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MountImageParameters, read_only), 0 }, { "readOnly", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MountImageParameters, read_only), 0 },
{ "growFileSystems", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MountImageParameters, growfs), 0 }, { "growFileSystems", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(MountImageParameters, growfs), 0 },
{ "password", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(MountImageParameters, password), 0 }, { "password", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(MountImageParameters, password), 0 },
{ "imagePolicy", SD_JSON_VARIANT_STRING, json_dispatch_image_policy, offsetof(MountImageParameters, image_policy), 0 }, { "imagePolicy", SD_JSON_VARIANT_STRING, json_dispatch_image_policy, offsetof(MountImageParameters, image_policy), 0 },
{ "veritySharing", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(MountImageParameters, verity_sharing), 0 },
VARLINK_DISPATCH_POLKIT_FIELD, VARLINK_DISPATCH_POLKIT_FIELD,
{} {}
}; };
@ -407,7 +403,6 @@ static int vl_method_mount_image(
DISSECT_IMAGE_FSCK | DISSECT_IMAGE_FSCK |
DISSECT_IMAGE_ADD_PARTITION_DEVICES | DISSECT_IMAGE_ADD_PARTITION_DEVICES |
DISSECT_IMAGE_PIN_PARTITION_DEVICES | DISSECT_IMAGE_PIN_PARTITION_DEVICES |
(p.verity_sharing ? DISSECT_IMAGE_VERITY_SHARE : 0) |
DISSECT_IMAGE_ALLOW_USERSPACE_VERITY; DISSECT_IMAGE_ALLOW_USERSPACE_VERITY;
/* Let's see if we have acquired the privilege to mount untrusted images already */ /* Let's see if we have acquired the privilege to mount untrusted images already */
@ -566,8 +561,8 @@ static int vl_method_mount_image(
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(pp->uuid), "partitionUuid", SD_JSON_BUILD_UUID(pp->uuid)), SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(pp->uuid), "partitionUuid", SD_JSON_BUILD_UUID(pp->uuid)),
SD_JSON_BUILD_PAIR("fileSystemType", SD_JSON_BUILD_STRING(dissected_partition_fstype(pp))), SD_JSON_BUILD_PAIR("fileSystemType", SD_JSON_BUILD_STRING(dissected_partition_fstype(pp))),
SD_JSON_BUILD_PAIR_CONDITION(!!pp->label, "partitionLabel", SD_JSON_BUILD_STRING(pp->label)), SD_JSON_BUILD_PAIR_CONDITION(!!pp->label, "partitionLabel", SD_JSON_BUILD_STRING(pp->label)),
SD_JSON_BUILD_PAIR("size", SD_JSON_BUILD_UNSIGNED(pp->size)), SD_JSON_BUILD_PAIR("size", SD_JSON_BUILD_INTEGER(pp->size)),
SD_JSON_BUILD_PAIR("offset", SD_JSON_BUILD_UNSIGNED(pp->offset)), SD_JSON_BUILD_PAIR("offset", SD_JSON_BUILD_INTEGER(pp->offset)),
SD_JSON_BUILD_PAIR("mountFileDescriptor", SD_JSON_BUILD_INTEGER(fd_idx)), SD_JSON_BUILD_PAIR("mountFileDescriptor", SD_JSON_BUILD_INTEGER(fd_idx)),
JSON_BUILD_PAIR_STRV_NON_EMPTY("mountPoint", l)); JSON_BUILD_PAIR_STRV_NON_EMPTY("mountPoint", l));
if (r < 0) if (r < 0)
@ -580,8 +575,8 @@ static int vl_method_mount_image(
link, link,
SD_JSON_BUILD_PAIR("partitions", SD_JSON_BUILD_VARIANT(aj)), SD_JSON_BUILD_PAIR("partitions", SD_JSON_BUILD_VARIANT(aj)),
SD_JSON_BUILD_PAIR("imagePolicy", SD_JSON_BUILD_STRING(ps)), SD_JSON_BUILD_PAIR("imagePolicy", SD_JSON_BUILD_STRING(ps)),
SD_JSON_BUILD_PAIR("imageSize", SD_JSON_BUILD_UNSIGNED(di->image_size)), SD_JSON_BUILD_PAIR("imageSize", SD_JSON_BUILD_INTEGER(di->image_size)),
SD_JSON_BUILD_PAIR("sectorSize", SD_JSON_BUILD_UNSIGNED(di->sector_size)), SD_JSON_BUILD_PAIR("sectorSize", SD_JSON_BUILD_INTEGER(di->sector_size)),
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(di->image_uuid), "imageUuid", SD_JSON_BUILD_UUID(di->image_uuid))); SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(di->image_uuid), "imageUuid", SD_JSON_BUILD_UUID(di->image_uuid)));
} }
@ -642,16 +637,10 @@ static MountMapMode default_mount_map_mode(DirectoryOwnership ownership) {
static JSON_DISPATCH_ENUM_DEFINE(dispatch_mount_directory_mode, MountMapMode, mount_map_mode_from_string); static JSON_DISPATCH_ENUM_DEFINE(dispatch_mount_directory_mode, MountMapMode, mount_map_mode_from_string);
static DirectoryOwnership validate_directory_fd( static DirectoryOwnership validate_directory_fd(int fd, uid_t peer_uid) {
int fd,
uid_t peer_uid,
uid_t *ret_current_owner_uid) {
int r, fl; int r, fl;
assert(fd >= 0); assert(fd >= 0);
assert(uid_is_valid(peer_uid));
assert(ret_current_owner_uid);
/* Checks if the specified directory fd looks sane. Returns a DirectoryOwnership that categorizes the /* Checks if the specified directory fd looks sane. Returns a DirectoryOwnership that categorizes the
* ownership situation in comparison to the peer's UID. * ownership situation in comparison to the peer's UID.
@ -676,7 +665,6 @@ static DirectoryOwnership validate_directory_fd(
return log_debug_errno(fl, "Directory file descriptor has unsafe flags set: %m"); return log_debug_errno(fl, "Directory file descriptor has unsafe flags set: %m");
if (st.st_uid == 0) { if (st.st_uid == 0) {
*ret_current_owner_uid = st.st_uid;
if (peer_uid == 0) { if (peer_uid == 0) {
log_debug("Directory file descriptor points to root owned directory, who is also the peer."); log_debug("Directory file descriptor points to root owned directory, who is also the peer.");
return DIRECTORY_IS_ROOT_PEER_OWNED; return DIRECTORY_IS_ROOT_PEER_OWNED;
@ -686,7 +674,6 @@ static DirectoryOwnership validate_directory_fd(
} }
if (st.st_uid == peer_uid) { if (st.st_uid == peer_uid) {
log_debug("Directory file descriptor points to peer owned directory."); log_debug("Directory file descriptor points to peer owned directory.");
*ret_current_owner_uid = st.st_uid;
return DIRECTORY_IS_PEER_OWNED; return DIRECTORY_IS_PEER_OWNED;
} }
@ -700,14 +687,12 @@ static DirectoryOwnership validate_directory_fd(
/* Stop iteration if we find a directory up the tree that is neither owned by the user, nor is from the foreign UID range */ /* Stop iteration if we find a directory up the tree that is neither owned by the user, nor is from the foreign UID range */
if (!uid_is_foreign(st.st_uid) || !gid_is_foreign(st.st_gid)) { if (!uid_is_foreign(st.st_uid) || !gid_is_foreign(st.st_gid)) {
log_debug("Directory file descriptor points to directory which itself or its parents is neither owned by foreign UID range nor by the user."); log_debug("Directory file descriptor points to directory which itself or its parents is neither owned by foreign UID range nor by the user.");
*ret_current_owner_uid = st.st_uid;
return DIRECTORY_IS_OTHERWISE_OWNED; return DIRECTORY_IS_OTHERWISE_OWNED;
} }
/* If the peer is root, then it doesn't matter if we find a parent owned by root, let's shortcut things. */ /* If the peer is root, then it doesn't matter if we find a parent owned by root, let's shortcut things. */
if (peer_uid == 0) { if (peer_uid == 0) {
log_debug("Directory file descriptor is owned by foreign UID range, and peer is root."); log_debug("Directory file descriptor is owned by foreign UID range, and peer is root.");
*ret_current_owner_uid = st.st_uid;
return DIRECTORY_IS_FOREIGN_OWNED; return DIRECTORY_IS_FOREIGN_OWNED;
} }
@ -723,13 +708,11 @@ static DirectoryOwnership validate_directory_fd(
/* Safety check to see if we hit the root dir */ /* Safety check to see if we hit the root dir */
if (stat_inode_same(&st, &new_st)) { if (stat_inode_same(&st, &new_st)) {
log_debug("Directory file descriptor is owned by foreign UID range, but didn't find parent directory that is owned by peer among ancestors."); log_debug("Directory file descriptor is owned by foreign UID range, but didn't find parent directory that is owned by peer among ancestors.");
*ret_current_owner_uid = st.st_uid;
return DIRECTORY_IS_OTHERWISE_OWNED; return DIRECTORY_IS_OTHERWISE_OWNED;
} }
if (new_st.st_uid == peer_uid) { /* Parent inode is owned by the peer. That's good! Everything's fine. */ if (new_st.st_uid == peer_uid) { /* Parent inode is owned by the peer. That's good! Everything's fine. */
log_debug("Directory file descriptor is owned by foreign UID range, and ancestor is owned by peer."); log_debug("Directory file descriptor is owned by foreign UID range, and ancestor is owned by peer.");
*ret_current_owner_uid = st.st_uid;
return DIRECTORY_IS_FOREIGN_OWNED; return DIRECTORY_IS_FOREIGN_OWNED;
} }
@ -738,7 +721,6 @@ static DirectoryOwnership validate_directory_fd(
} }
log_debug("Failed to find peer owned parent directory after %u levels, refusing.", n_level); log_debug("Failed to find peer owned parent directory after %u levels, refusing.", n_level);
*ret_current_owner_uid = st.st_uid;
return DIRECTORY_IS_OTHERWISE_OWNED; return DIRECTORY_IS_OTHERWISE_OWNED;
} }
@ -789,8 +771,7 @@ static int vl_method_mount_directory(
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to get client UID: %m"); return log_debug_errno(r, "Failed to get client UID: %m");
uid_t current_owner_uid; DirectoryOwnership owned_by = validate_directory_fd(directory_fd, peer_uid);
DirectoryOwnership owned_by = validate_directory_fd(directory_fd, peer_uid, &current_owner_uid);
if (owned_by == -EREMOTEIO) if (owned_by == -EREMOTEIO)
return sd_varlink_errorbo(link, "io.systemd.MountFileSystem.BadFileDescriptorFlags", SD_JSON_BUILD_PAIR_STRING("parameter", "directoryFileDescriptor")); return sd_varlink_errorbo(link, "io.systemd.MountFileSystem.BadFileDescriptorFlags", SD_JSON_BUILD_PAIR_STRING("parameter", "directoryFileDescriptor"));
if (owned_by < 0) if (owned_by < 0)
@ -855,28 +836,10 @@ static int vl_method_mount_directory(
if (r < 0) if (r < 0)
return r; return r;
_cleanup_close_ int mount_fd = open_tree_try_drop_idmap( _cleanup_close_ int mount_fd = open_tree(directory_fd, "", OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC|AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH);
directory_fd,
"",
OPEN_TREE_CLONE|OPEN_TREE_CLOEXEC|AT_SYMLINK_NOFOLLOW|AT_EMPTY_PATH);
if (mount_fd < 0) if (mount_fd < 0)
return log_debug_errno(errno, "Failed to issue open_tree() of provided directory '%s': %m", strna(directory_path)); return log_debug_errno(errno, "Failed to issue open_tree() of provided directory '%s': %m", strna(directory_path));
/* MOUNT_ATTR_IDMAP has possibly been cleared. Let's verify that the underlying data matches our expectations. */
struct stat unmapped_st;
if (fstat(mount_fd, &unmapped_st) < 0)
return log_debug_errno(errno, "Failed to stat unmapped inode: %m");
r = stat_verify_directory(&unmapped_st);
if (r < 0)
return r;
/* For now, let's simply refuse things if dropping the idmapping changed anything. For now that
* should be good enough, because the primary usecase for this (homed) will mount the foreign UID
* range 1:1. */
if (unmapped_st.st_uid != current_owner_uid)
return log_debug_errno(SYNTHETIC_ERRNO(EPERM), "Owner UID of mount after clearing ID mapping not the same anymore, refusing.");
if (p.read_only > 0 && mount_setattr( if (p.read_only > 0 && mount_setattr(
mount_fd, "", AT_EMPTY_PATH, mount_fd, "", AT_EMPTY_PATH,
&(struct mount_attr) { &(struct mount_attr) {

View File

@ -13,7 +13,6 @@
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "hashmap.h" #include "hashmap.h"
#include "hostname-setup.h"
#include "network-common.h" #include "network-common.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-dhcp-server.h" #include "networkd-dhcp-server.h"
@ -32,30 +31,6 @@
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
static int get_hostname_domain(char **ret) {
_cleanup_free_ char *hostname = NULL;
const char *domain;
int r;
assert(ret);
/* Get the full hostname (FQDN if available) */
r = gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST | GET_HOSTNAME_FALLBACK_DEFAULT, &hostname);
if (r < 0)
return r;
/* Find the first dot to extract the domain part */
domain = strchr(hostname, '.');
if (!domain)
return -ENOENT; /* No domain part in hostname */
domain++; /* Skip the dot */
if (isempty(domain))
return -ENOENT; /* Empty domain after dot */
return strdup_to(ret, domain);
}
static bool link_dhcp4_server_enabled(Link *link) { static bool link_dhcp4_server_enabled(Link *link) {
assert(link); assert(link);
@ -703,29 +678,6 @@ static int dhcp4_server_configure(Link *link) {
} }
} }
if (link->network->dhcp_server_emit_domain) {
_cleanup_free_ char *buffer = NULL;
const char *domain = NULL;
if (link->network->dhcp_server_domain)
domain = link->network->dhcp_server_domain;
else {
r = get_hostname_domain(&buffer);
if (r < 0)
log_link_warning_errno(link, r, "Failed to determine domain name from host's hostname, will not send domain in DHCP leases: %m");
else {
domain = buffer;
log_link_debug(link, "Using autodetected domain name '%s' for DHCP server.", domain);
}
}
if (domain) {
r = sd_dhcp_server_set_domain_name(link->dhcp_server, domain);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set domain name for DHCP server: %m");
}
}
ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_send_options) { ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_send_options) {
r = sd_dhcp_server_add_option(link->dhcp_server, p); r = sd_dhcp_server_add_option(link->dhcp_server, p);
if (r == -EEXIST) if (r == -EEXIST)

View File

@ -381,8 +381,6 @@ DHCPServer.EmitRouter, config_parse_bool,
DHCPServer.Router, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_router) DHCPServer.Router, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_router)
DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone) DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone)
DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone) DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone)
DHCPServer.EmitDomain, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_domain)
DHCPServer.Domain, config_parse_dns_name, 0, offsetof(Network, dhcp_server_domain)
DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset) DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset)
DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size) DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size)
DHCPServer.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_server_send_vendor_options) DHCPServer.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_server_send_vendor_options)

View File

@ -755,7 +755,6 @@ static Network *network_free(Network *network) {
free(network->dhcp_server_boot_server_name); free(network->dhcp_server_boot_server_name);
free(network->dhcp_server_boot_filename); free(network->dhcp_server_boot_filename);
free(network->dhcp_server_timezone); free(network->dhcp_server_timezone);
free(network->dhcp_server_domain);
free(network->dhcp_server_uplink_name); free(network->dhcp_server_uplink_name);
for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++) for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++)
free(network->dhcp_server_emit[t].addresses); free(network->dhcp_server_emit[t].addresses);

View File

@ -220,8 +220,6 @@ typedef struct Network {
struct in_addr dhcp_server_router; struct in_addr dhcp_server_router;
bool dhcp_server_emit_timezone; bool dhcp_server_emit_timezone;
char *dhcp_server_timezone; char *dhcp_server_timezone;
bool dhcp_server_emit_domain;
char *dhcp_server_domain;
usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec; usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec;
uint32_t dhcp_server_pool_offset; uint32_t dhcp_server_pool_offset;
uint32_t dhcp_server_pool_size; uint32_t dhcp_server_pool_size;

View File

@ -826,16 +826,17 @@ static int mount_bind(const char *dest, CustomMount *m, uid_t uid_shift, uid_t u
* caller's userns *without* any mount idmapping in place. To get that uid, we clone the * caller's userns *without* any mount idmapping in place. To get that uid, we clone the
* mount source tree and clear any existing idmapping and temporarily mount that tree over * mount source tree and clear any existing idmapping and temporarily mount that tree over
* the mount source before we stat the mount source to figure out the source uid. */ * the mount source before we stat the mount source to figure out the source uid. */
_cleanup_close_ int fd_clone = _cleanup_close_ int fd_clone = open_tree_attr_with_fallback(
idmapping == REMOUNT_IDMAPPING_NONE ?
RET_NERRNO(open_tree(
AT_FDCWD, AT_FDCWD,
m->source, m->source,
open_tree_flags)) : open_tree_flags,
open_tree_try_drop_idmap( &(struct mount_attr) {
AT_FDCWD, .attr_clr = idmapping != REMOUNT_IDMAPPING_NONE ? MOUNT_ATTR_IDMAP : 0,
m->source, });
open_tree_flags); if (ERRNO_IS_NEG_NOT_SUPPORTED(fd_clone))
/* We can only clear idmapped mounts with open_tree_attr(), but there might not be one in
* the first place, so we keep going if we get a not supported error. */
fd_clone = open_tree(AT_FDCWD, m->source, open_tree_flags);
if (fd_clone < 0) if (fd_clone < 0)
return log_error_errno(errno, "Failed to clone %s: %m", m->source); return log_error_errno(errno, "Failed to clone %s: %m", m->source);

View File

@ -3830,7 +3830,6 @@ static DissectImageFlags determine_dissect_image_flags(void) {
DISSECT_IMAGE_PIN_PARTITION_DEVICES | DISSECT_IMAGE_PIN_PARTITION_DEVICES |
(arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS) | (arg_read_only ? DISSECT_IMAGE_READ_ONLY : DISSECT_IMAGE_FSCK|DISSECT_IMAGE_GROWFS) |
DISSECT_IMAGE_ALLOW_USERSPACE_VERITY | DISSECT_IMAGE_ALLOW_USERSPACE_VERITY |
DISSECT_IMAGE_VERITY_SHARE |
(arg_console_mode == CONSOLE_INTERACTIVE && arg_ask_password ? DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH : 0) | (arg_console_mode == CONSOLE_INTERACTIVE && arg_ask_password ? DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH : 0) |
((arg_userns_ownership == USER_NAMESPACE_OWNERSHIP_FOREIGN) ? DISSECT_IMAGE_FOREIGN_UID : ((arg_userns_ownership == USER_NAMESPACE_OWNERSHIP_FOREIGN) ? DISSECT_IMAGE_FOREIGN_UID :
(arg_userns_ownership != USER_NAMESPACE_OWNERSHIP_AUTO) ? DISSECT_IMAGE_IDENTITY_UID : 0); (arg_userns_ownership != USER_NAMESPACE_OWNERSHIP_AUTO) ? DISSECT_IMAGE_IDENTITY_UID : 0);

View File

@ -4727,7 +4727,6 @@ int mountfsd_mount_image(
SD_JSON_BUILD_PAIR("readOnly", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_MOUNT_READ_ONLY))), SD_JSON_BUILD_PAIR("readOnly", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_MOUNT_READ_ONLY))),
SD_JSON_BUILD_PAIR("growFileSystems", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_GROWFS))), SD_JSON_BUILD_PAIR("growFileSystems", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_GROWFS))),
SD_JSON_BUILD_PAIR_CONDITION(!!ps, "imagePolicy", SD_JSON_BUILD_STRING(ps)), SD_JSON_BUILD_PAIR_CONDITION(!!ps, "imagePolicy", SD_JSON_BUILD_STRING(ps)),
SD_JSON_BUILD_PAIR("veritySharing", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))),
SD_JSON_BUILD_PAIR("allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH)))); SD_JSON_BUILD_PAIR("allowInteractiveAuthentication", SD_JSON_BUILD_BOOLEAN(FLAGS_SET(flags, DISSECT_IMAGE_ALLOW_INTERACTIVE_AUTH))));
if (r < 0) if (r < 0)
return r; return r;

View File

@ -7,24 +7,8 @@
#if HAVE_LIBARCHIVE #if HAVE_LIBARCHIVE
static void *libarchive_dl = NULL; static void *libarchive_dl = NULL;
DLSYM_PROTOTYPE(archive_entry_filetype) = NULL;
DLSYM_PROTOTYPE(archive_entry_free) = NULL; DLSYM_PROTOTYPE(archive_entry_free) = NULL;
DLSYM_PROTOTYPE(archive_entry_gid) = NULL;
#if HAVE_LIBARCHIVE_UID_IS_SET
DLSYM_PROTOTYPE(archive_entry_gid_is_set) = NULL;
#endif
DLSYM_PROTOTYPE(archive_entry_hardlink) = NULL;
#if HAVE_LIBARCHIVE_HARDLINK_IS_SET
DLSYM_PROTOTYPE(archive_entry_hardlink_is_set) = NULL;
#endif
DLSYM_PROTOTYPE(archive_entry_mode) = NULL;
DLSYM_PROTOTYPE(archive_entry_mtime) = NULL;
DLSYM_PROTOTYPE(archive_entry_mtime_is_set) = NULL;
DLSYM_PROTOTYPE(archive_entry_mtime_nsec) = NULL;
DLSYM_PROTOTYPE(archive_entry_new) = NULL; DLSYM_PROTOTYPE(archive_entry_new) = NULL;
DLSYM_PROTOTYPE(archive_entry_pathname) = NULL;
DLSYM_PROTOTYPE(archive_entry_rdevmajor) = NULL;
DLSYM_PROTOTYPE(archive_entry_rdevminor) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_ctime) = NULL; DLSYM_PROTOTYPE(archive_entry_set_ctime) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_filetype) = NULL; DLSYM_PROTOTYPE(archive_entry_set_filetype) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_gid) = NULL; DLSYM_PROTOTYPE(archive_entry_set_gid) = NULL;
@ -33,24 +17,10 @@ DLSYM_PROTOTYPE(archive_entry_set_pathname) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_perm) = NULL; DLSYM_PROTOTYPE(archive_entry_set_perm) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_rdevmajor) = NULL; DLSYM_PROTOTYPE(archive_entry_set_rdevmajor) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_rdevminor) = NULL; DLSYM_PROTOTYPE(archive_entry_set_rdevminor) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_size) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_symlink) = NULL; DLSYM_PROTOTYPE(archive_entry_set_symlink) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_size) = NULL;
DLSYM_PROTOTYPE(archive_entry_set_uid) = NULL; DLSYM_PROTOTYPE(archive_entry_set_uid) = NULL;
DLSYM_PROTOTYPE(archive_entry_symlink) = NULL;
DLSYM_PROTOTYPE(archive_entry_uid) = NULL;
#if HAVE_LIBARCHIVE_UID_IS_SET
DLSYM_PROTOTYPE(archive_entry_uid_is_set) = NULL;
#endif
DLSYM_PROTOTYPE(archive_entry_xattr_next) = NULL;
DLSYM_PROTOTYPE(archive_entry_xattr_reset) = NULL;
DLSYM_PROTOTYPE(archive_error_string) = NULL; DLSYM_PROTOTYPE(archive_error_string) = NULL;
DLSYM_PROTOTYPE(archive_read_data_into_fd) = NULL;
DLSYM_PROTOTYPE(archive_read_free) = NULL;
DLSYM_PROTOTYPE(archive_read_new) = NULL;
DLSYM_PROTOTYPE(archive_read_next_header) = NULL;
DLSYM_PROTOTYPE(archive_read_open_fd) = NULL;
DLSYM_PROTOTYPE(archive_read_support_format_cpio) = NULL;
DLSYM_PROTOTYPE(archive_read_support_format_tar) = NULL;
DLSYM_PROTOTYPE(archive_write_close) = NULL; DLSYM_PROTOTYPE(archive_write_close) = NULL;
DLSYM_PROTOTYPE(archive_write_data) = NULL; DLSYM_PROTOTYPE(archive_write_data) = NULL;
DLSYM_PROTOTYPE(archive_write_free) = NULL; DLSYM_PROTOTYPE(archive_write_free) = NULL;
@ -71,24 +41,8 @@ int dlopen_libarchive(void) {
&libarchive_dl, &libarchive_dl,
"libarchive.so.13", "libarchive.so.13",
LOG_DEBUG, LOG_DEBUG,
DLSYM_ARG(archive_entry_filetype),
DLSYM_ARG(archive_entry_free), DLSYM_ARG(archive_entry_free),
DLSYM_ARG(archive_entry_gid),
#if HAVE_LIBARCHIVE_UID_IS_SET
DLSYM_ARG(archive_entry_gid_is_set),
#endif
DLSYM_ARG(archive_entry_hardlink),
#if HAVE_LIBARCHIVE_HARDLINK_IS_SET
DLSYM_ARG(archive_entry_hardlink_is_set),
#endif
DLSYM_ARG(archive_entry_mode),
DLSYM_ARG(archive_entry_mtime),
DLSYM_ARG(archive_entry_mtime_is_set),
DLSYM_ARG(archive_entry_mtime_nsec),
DLSYM_ARG(archive_entry_new), DLSYM_ARG(archive_entry_new),
DLSYM_ARG(archive_entry_pathname),
DLSYM_ARG(archive_entry_rdevmajor),
DLSYM_ARG(archive_entry_rdevminor),
DLSYM_ARG(archive_entry_set_ctime), DLSYM_ARG(archive_entry_set_ctime),
DLSYM_ARG(archive_entry_set_filetype), DLSYM_ARG(archive_entry_set_filetype),
DLSYM_ARG(archive_entry_set_gid), DLSYM_ARG(archive_entry_set_gid),
@ -100,21 +54,7 @@ int dlopen_libarchive(void) {
DLSYM_ARG(archive_entry_set_size), DLSYM_ARG(archive_entry_set_size),
DLSYM_ARG(archive_entry_set_symlink), DLSYM_ARG(archive_entry_set_symlink),
DLSYM_ARG(archive_entry_set_uid), DLSYM_ARG(archive_entry_set_uid),
DLSYM_ARG(archive_entry_symlink),
DLSYM_ARG(archive_entry_uid),
#if HAVE_LIBARCHIVE_UID_IS_SET
DLSYM_ARG(archive_entry_uid_is_set),
#endif
DLSYM_ARG(archive_entry_xattr_next),
DLSYM_ARG(archive_entry_xattr_reset),
DLSYM_ARG(archive_error_string), DLSYM_ARG(archive_error_string),
DLSYM_ARG(archive_read_data_into_fd),
DLSYM_ARG(archive_read_free),
DLSYM_ARG(archive_read_new),
DLSYM_ARG(archive_read_next_header),
DLSYM_ARG(archive_read_open_fd),
DLSYM_ARG(archive_read_support_format_cpio),
DLSYM_ARG(archive_read_support_format_tar),
DLSYM_ARG(archive_write_close), DLSYM_ARG(archive_write_close),
DLSYM_ARG(archive_write_data), DLSYM_ARG(archive_write_data),
DLSYM_ARG(archive_write_free), DLSYM_ARG(archive_write_free),
@ -123,18 +63,7 @@ int dlopen_libarchive(void) {
DLSYM_ARG(archive_write_open_FILE), DLSYM_ARG(archive_write_open_FILE),
DLSYM_ARG(archive_write_open_fd), DLSYM_ARG(archive_write_open_fd),
DLSYM_ARG(archive_write_set_format_filter_by_ext), DLSYM_ARG(archive_write_set_format_filter_by_ext),
DLSYM_ARG(archive_write_set_format_gnutar) DLSYM_ARG(archive_write_set_format_gnutar));
);
} }
/* libarchive uses its own file type macros. They happen to be defined the same way as the Linux ones, and
* we'd like to rely on it. Let's verify this first though. */
assert_cc(S_IFDIR == AE_IFDIR);
assert_cc(S_IFREG == AE_IFREG);
assert_cc(S_IFLNK == AE_IFLNK);
assert_cc(S_IFBLK == AE_IFBLK);
assert_cc(S_IFCHR == AE_IFCHR);
assert_cc(S_IFIFO == AE_IFIFO);
assert_cc(S_IFSOCK == AE_IFSOCK);
#endif #endif

View File

@ -9,18 +9,8 @@
#include "dlfcn-util.h" #include "dlfcn-util.h"
extern DLSYM_PROTOTYPE(archive_entry_filetype);
extern DLSYM_PROTOTYPE(archive_entry_free); extern DLSYM_PROTOTYPE(archive_entry_free);
extern DLSYM_PROTOTYPE(archive_entry_gid);
extern DLSYM_PROTOTYPE(archive_entry_hardlink);
extern DLSYM_PROTOTYPE(archive_entry_mode);
extern DLSYM_PROTOTYPE(archive_entry_mtime);
extern DLSYM_PROTOTYPE(archive_entry_mtime_is_set);
extern DLSYM_PROTOTYPE(archive_entry_mtime_nsec);
extern DLSYM_PROTOTYPE(archive_entry_new); extern DLSYM_PROTOTYPE(archive_entry_new);
extern DLSYM_PROTOTYPE(archive_entry_pathname);
extern DLSYM_PROTOTYPE(archive_entry_rdevmajor);
extern DLSYM_PROTOTYPE(archive_entry_rdevminor);
extern DLSYM_PROTOTYPE(archive_entry_set_ctime); extern DLSYM_PROTOTYPE(archive_entry_set_ctime);
extern DLSYM_PROTOTYPE(archive_entry_set_filetype); extern DLSYM_PROTOTYPE(archive_entry_set_filetype);
extern DLSYM_PROTOTYPE(archive_entry_set_gid); extern DLSYM_PROTOTYPE(archive_entry_set_gid);
@ -29,21 +19,10 @@ extern DLSYM_PROTOTYPE(archive_entry_set_pathname);
extern DLSYM_PROTOTYPE(archive_entry_set_perm); extern DLSYM_PROTOTYPE(archive_entry_set_perm);
extern DLSYM_PROTOTYPE(archive_entry_set_rdevmajor); extern DLSYM_PROTOTYPE(archive_entry_set_rdevmajor);
extern DLSYM_PROTOTYPE(archive_entry_set_rdevminor); extern DLSYM_PROTOTYPE(archive_entry_set_rdevminor);
extern DLSYM_PROTOTYPE(archive_entry_set_size);
extern DLSYM_PROTOTYPE(archive_entry_set_symlink); extern DLSYM_PROTOTYPE(archive_entry_set_symlink);
extern DLSYM_PROTOTYPE(archive_entry_set_size);
extern DLSYM_PROTOTYPE(archive_entry_set_uid); extern DLSYM_PROTOTYPE(archive_entry_set_uid);
extern DLSYM_PROTOTYPE(archive_entry_symlink);
extern DLSYM_PROTOTYPE(archive_entry_uid);
extern DLSYM_PROTOTYPE(archive_entry_xattr_next);
extern DLSYM_PROTOTYPE(archive_entry_xattr_reset);
extern DLSYM_PROTOTYPE(archive_error_string); extern DLSYM_PROTOTYPE(archive_error_string);
extern DLSYM_PROTOTYPE(archive_read_data_into_fd);
extern DLSYM_PROTOTYPE(archive_read_free);
extern DLSYM_PROTOTYPE(archive_read_new);
extern DLSYM_PROTOTYPE(archive_read_next_header);
extern DLSYM_PROTOTYPE(archive_read_open_fd);
extern DLSYM_PROTOTYPE(archive_read_support_format_cpio);
extern DLSYM_PROTOTYPE(archive_read_support_format_tar);
extern DLSYM_PROTOTYPE(archive_write_close); extern DLSYM_PROTOTYPE(archive_write_close);
extern DLSYM_PROTOTYPE(archive_write_data); extern DLSYM_PROTOTYPE(archive_write_data);
extern DLSYM_PROTOTYPE(archive_write_free); extern DLSYM_PROTOTYPE(archive_write_free);
@ -54,32 +33,10 @@ extern DLSYM_PROTOTYPE(archive_write_open_fd);
extern DLSYM_PROTOTYPE(archive_write_set_format_filter_by_ext); extern DLSYM_PROTOTYPE(archive_write_set_format_filter_by_ext);
extern DLSYM_PROTOTYPE(archive_write_set_format_gnutar); extern DLSYM_PROTOTYPE(archive_write_set_format_gnutar);
#if HAVE_LIBARCHIVE_UID_IS_SET
extern DLSYM_PROTOTYPE(archive_entry_gid_is_set);
extern DLSYM_PROTOTYPE(archive_entry_uid_is_set);
#else
#include "user-util.h"
static inline int sym_archive_entry_gid_is_set(struct archive_entry *e) {
return gid_is_valid(sym_archive_entry_gid(e));
}
static inline int sym_archive_entry_uid_is_set(struct archive_entry *e) {
return uid_is_valid(sym_archive_entry_uid(e));
}
#endif
#if HAVE_LIBARCHIVE_HARDLINK_IS_SET
extern DLSYM_PROTOTYPE(archive_entry_hardlink_is_set);
#else
static inline int sym_archive_entry_hardlink_is_set(struct archive_entry *e) {
return !!sym_archive_entry_hardlink(e);
}
#endif
int dlopen_libarchive(void); int dlopen_libarchive(void);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct archive_entry*, sym_archive_entry_free, NULL); DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct archive_entry*, sym_archive_entry_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct archive*, sym_archive_write_free, NULL); DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct archive*, sym_archive_write_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct archive*, sym_archive_read_free, NULL);
#else #else

View File

@ -177,7 +177,6 @@ shared_sources = files(
'socket-netlink.c', 'socket-netlink.c',
'specifier.c', 'specifier.c',
'switch-root.c', 'switch-root.c',
'tar-util.c',
'tmpfile-util-label.c', 'tmpfile-util-label.c',
'tomoyo-util.c', 'tomoyo-util.c',
'tpm2-util.c', 'tpm2-util.c',

View File

@ -1477,7 +1477,7 @@ int make_userns(uid_t uid_shift,
return TAKE_FD(userns_fd); return TAKE_FD(userns_fd);
} }
int open_tree_attr_with_fallback(int dir_fd, const char *path, unsigned flags, struct mount_attr *attr) { int open_tree_attr_with_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr) {
_cleanup_close_ int fd = -EBADF; _cleanup_close_ int fd = -EBADF;
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
@ -1507,42 +1507,6 @@ int open_tree_attr_with_fallback(int dir_fd, const char *path, unsigned flags, s
return TAKE_FD(fd); return TAKE_FD(fd);
} }
int open_tree_try_drop_idmap(int dir_fd, const char *path, unsigned flags) {
/* Tries to drop MOUNT_ATTR_IDMAP while calling open_tree_attr(), but if that doesn't work just uses
* a regular open_tree() */
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
if (isempty(path)) {
path = "";
flags |= AT_EMPTY_PATH;
}
_cleanup_close_ int fd = open_tree_attr_with_fallback(
dir_fd,
path,
flags,
&(struct mount_attr) {
.attr_clr = MOUNT_ATTR_IDMAP,
});
if (fd < 0) {
if (!ERRNO_IS_NEG_NOT_SUPPORTED(fd))
return log_debug_errno(fd, "Failed to clear idmap of directory with open_tree_attr(): %m");
log_debug_errno(fd, "Failed to clear idmap with open_tree_attr(), retrying open_tree() without clearing idmap: %m");
fd = RET_NERRNO(open_tree(dir_fd, path, flags));
if (fd < 0)
return log_debug_errno(fd, "Both open_tree() and open_tree_attr() failed, giving up: %m");
log_debug("open_tree() without clearing idmap worked.");
return TAKE_FD(fd);
}
log_debug("Successfully acquired mount fd with cleared idmap.");
return TAKE_FD(fd);
}
int remount_idmap_fd( int remount_idmap_fd(
char **paths, char **paths,
int userns_fd, int userns_fd,

View File

@ -145,8 +145,7 @@ typedef enum RemountIdmapping {
_REMOUNT_IDMAPPING_INVALID = -EINVAL, _REMOUNT_IDMAPPING_INVALID = -EINVAL,
} RemountIdmapping; } RemountIdmapping;
int open_tree_attr_with_fallback(int dir_fd, const char *path, unsigned flags, struct mount_attr *attr); int open_tree_attr_with_fallback(int dir_fd, const char *path, unsigned int flags, struct mount_attr *attr);
int open_tree_try_drop_idmap(int dir_fd, const char *path, unsigned flags);
int make_userns(uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping); int make_userns(uid_t uid_shift, uid_t uid_range, uid_t host_owner, uid_t dest_owner, RemountIdmapping idmapping);
int remount_idmap_fd(char **p, int userns_fd, uint64_t extra_mount_attr_set); int remount_idmap_fd(char **p, int userns_fd, uint64_t extra_mount_attr_set);

View File

@ -400,8 +400,8 @@ int nsresource_add_netif_tap(
return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to add network to user namespace: %s", error_id); return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to add network to user namespace: %s", error_id);
static const sd_json_dispatch_field dispatch_table[] = { static const sd_json_dispatch_field dispatch_table[] = {
{ "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, host_interface_name), SD_JSON_MANDATORY }, { "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, host_interface_name), SD_JSON_MANDATORY },
{ "interfaceFileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, offsetof(InterfaceParams, interface_fd_index), SD_JSON_MANDATORY }, { "interfaceFileDescriptor", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint, offsetof(InterfaceParams, namespace_interface_name), SD_JSON_MANDATORY },
}; };
_cleanup_(interface_params_done) InterfaceParams p = {}; _cleanup_(interface_params_done) InterfaceParams p = {};

View File

@ -1,686 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "errno-util.h"
#include "log.h"
#include "tar-util.h"
#if HAVE_LIBARCHIVE
#include <sys/sysmacros.h>
#include "alloc-util.h"
#include "chase.h"
#include "fd-util.h"
#include "fs-util.h"
#include "iovec-util.h"
#include "libarchive-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "tmpfile-util.h"
#include "user-util.h"
#include "xattr-util.h"
#define DEPTH_MAX 128U
typedef struct XAttr {
char *name;
struct iovec data;
} XAttr;
typedef struct OpenInode {
int fd;
char *path;
/* File properties to apply when we are done with the inode, i.e. right before closing it */
mode_t filetype;
mode_t mode;
struct timespec mtime;
uid_t uid;
gid_t gid;
XAttr *xattr;
size_t n_xattr;
} OpenInode;
static void xattr_done(XAttr *xa) {
assert(xa);
free(xa->name);
iovec_done(&xa->data);
}
static void xattr_done_many(XAttr *xa, size_t n) {
assert(xa || n == 0);
FOREACH_ARRAY(i, xa, n)
xattr_done(i);
free(xa);
}
static void open_inode_done(OpenInode *of) {
assert(of);
if (of->path) {
/* Only close the stored fd if the path field is set. We'll set the path to NULL for the root
* inode, and we don't want the fd for that closed, as it's owned by the caller. */
of->fd = safe_close(of->fd);
of->path = mfree(of->path);
}
xattr_done_many(of->xattr, of->n_xattr);
}
static void open_inode_done_many(OpenInode *array, size_t n) {
assert(array || n == 0);
FOREACH_ARRAY(i, array, n)
open_inode_done(i);
free(array);
}
static int open_inode_finalize(OpenInode *of) {
int r = 0;
assert(of);
if (of->fd >= 0) {
int k;
/* We adjust the UID/GID right before the mode, since doing this might affect the mode (drops
* suid/sgid bits).
*
* We adjust the mode only when leaving a dir, because if we are unpriv we might lose the
* ability to enter it once we do this. */
if (uid_is_valid(of->uid) || gid_is_valid(of->gid) || of->mode != MODE_INVALID) {
k = fchmod_and_chown_with_fallback(of->fd, /* path= */ NULL, of->mode, of->uid, of->gid);
if (k < 0)
RET_GATHER(r, log_error_errno(k, "Failed to adjust ownership/mode of '%s': %m", of->path));
}
/* We also adjust the mtime only after leaving a dir, since it might otherwise change again
* because we make modifications inside it */
if (of->mtime.tv_nsec != UTIME_OMIT) {
k = futimens_opath(of->fd, (const struct timespec[2]) {
{ .tv_nsec = UTIME_OMIT },
of->mtime,
});
if (k < 0)
RET_GATHER(r, log_error_errno(k, "Failed to adjust mtime of '%s': %m", of->path));
}
/* Setting certain xattrs might cause us to lose access to the inode, hence set this last */
FOREACH_ARRAY(i, of->xattr, of->n_xattr) {
k = xsetxattr_full(
of->fd,
/* path= */ NULL,
AT_EMPTY_PATH,
i->name,
i->data.iov_base,
i->data.iov_len,
/* xattr_flags= */ 0);
if (k < 0)
RET_GATHER(r, log_error_errno(k, "Failed to set xattr '%s' of '%s': %m", i->name, of->path));
}
}
open_inode_done(of); /* free this item even on failure */
return r;
}
static int open_inode_finalize_many(OpenInode **array, size_t *n) {
int r = 0;
assert(array);
assert(n);
assert(*array || *n == 0);
/* Go backwards, so that we adjust innermost first */
for (size_t i = *n; i > 0; i--)
RET_GATHER(r, open_inode_finalize(*array + i - 1));
*array = mfree(*array);
*n = 0;
return r;
}
static int archive_unpack_regular(
struct archive *a,
struct archive_entry *entry,
int parent_fd,
const char *filename,
const char *path) {
int r;
assert(a);
assert(entry);
assert(parent_fd >= 0);
assert(filename);
assert(path);
_cleanup_free_ char *tmp = NULL;
_cleanup_close_ int fd = open_tmpfile_linkable_at(parent_fd, filename, O_CLOEXEC|O_WRONLY, &tmp);
if (fd < 0)
return log_error_errno(fd, "Failed to create regular file '%s': %m", path);
r = sym_archive_read_data_into_fd(a, fd);
if (r != ARCHIVE_OK) {
r = log_error_errno(
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to unpack regular file '%s': %s", path, sym_archive_error_string(a));
goto fail;
}
/* If this is a sparse file, then libarchive's archive_read_data_into_fd() won't insert the final
* hole. We need to manually truncate. */
off_t l = lseek(fd, 0, SEEK_CUR);
if (l < 0) {
r = log_error_errno(errno, "Failed to determine current file position in '%s': %m", path);
goto fail;
}
if (ftruncate(fd, l) < 0) {
r = log_error_errno(errno, "Failed to truncate regular file '%s' to %" PRIu64 ": %m", path, (uint64_t) l);
goto fail;
}
r = link_tmpfile_at(fd, parent_fd, tmp, filename, LINK_TMPFILE_REPLACE);
if (r < 0) {
log_error_errno(r, "Failed to install regular file '%s': %m", path);
goto fail;
}
return TAKE_FD(fd);
fail:
if (tmp)
(void) unlinkat(parent_fd, tmp, /* flags= */ 0);
return r;
}
static int archive_unpack_directory(
struct archive *a,
struct archive_entry *entry,
int parent_fd,
const char *filename,
const char *path) {
assert(a);
assert(entry);
assert(parent_fd >= 0);
assert(filename);
assert(path);
/* For the other inode types we operate in an atomic replace fashion, but not for the directories,
* they are more of a "shared" concept, and we try to reuse existing inodes. Note that we create the
* dir inode in mode 0700, so that we can fully access it (but others cannot). We'll adjust the modes
* right before closing the inode. */
_cleanup_close_ int fd = open_mkdir_at(parent_fd, filename, O_CLOEXEC, 0700);
if (fd < 0)
return log_error_errno(fd, "Failed to create directory '%s': %m", path);
return TAKE_FD(fd);
}
static int archive_unpack_symlink(
struct archive *a,
struct archive_entry *entry,
int parent_fd,
const char *filename,
const char *path) {
int r;
assert(a);
assert(entry);
assert(parent_fd >= 0);
assert(filename);
assert(path);
const char *target = sym_archive_entry_symlink(entry);
if (!target)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to get symlink target for '%s': %m", path);
r = symlinkat_atomic_full(target, parent_fd, filename, /* flags= */ 0);
if (r < 0)
return log_error_errno(r, "Failed to create symlink '%s' → '%s': %m", path, target);
_cleanup_close_ int fd = openat(parent_fd, filename, O_CLOEXEC|O_PATH|O_NOFOLLOW);
if (fd < 0)
return log_error_errno(errno, "Failed to open symlink '%s' we just created: %m", path);
r = fd_verify_symlink(fd);
if (r < 0)
return log_error_errno(r, "Symlink '%s' we just created is not a symlink: %m", path);
return TAKE_FD(fd);
}
static int archive_unpack_special_inode(
struct archive *a,
struct archive_entry *entry,
int parent_fd,
const char *filename,
const char *path,
mode_t filetype) {
int r;
assert(a);
assert(entry);
assert(parent_fd >= 0);
assert(filename);
assert(path);
dev_t major = 0, minor = 0;
if (IN_SET(filetype, S_IFCHR, S_IFBLK)) {
major = sym_archive_entry_rdevmajor(entry);
minor = sym_archive_entry_rdevminor(entry);
}
r = mknodat_atomic(parent_fd, filename, filetype | 0000, makedev(major, minor));
if (r < 0)
return log_error_errno(r, "Failed to create special node '%s': %m", path);
_cleanup_close_ int fd = openat(parent_fd, filename, O_CLOEXEC|O_PATH|O_NOFOLLOW);
if (fd < 0)
return log_error_errno(errno, "Failed to open special node '%s' we just created: %m", path);
struct stat st;
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to fstat() '%s': %m", path);
if (((st.st_mode ^ filetype) & S_IFMT) != 0)
return log_error_errno(
SYNTHETIC_ERRNO(ENODEV),
"Special node '%s' we just created is of a wrong type: %m", path);
return TAKE_FD(fd);
}
static int archive_entry_pathname_safe(struct archive_entry *entry, const char **ret) {
/* libarchive prefixes all paths with "./", let's chop that off. Note that we'll return a path of
* NULL for the root inode here! */
assert(entry);
assert(ret);
const char *p = sym_archive_entry_pathname(entry);
if (!p)
return -EBADMSG;
const char *e = startswith(p, "./") ?: p;
if (isempty(e))
*ret = NULL;
else if (path_is_safe(e))
*ret = e;
else
return -EBADMSG;
return 0;
}
static int archive_entry_read_stat(
struct archive_entry *entry,
mode_t *filetype,
mode_t *mode,
struct timespec *mtime,
uid_t *uid,
gid_t *gid,
XAttr **xa,
size_t *n_xa,
TarFlags flags) {
assert(entry);
/* Fills in all fields that are present in the archive entry. Doesn't change the fields if the entry
* doesn't contain the relevant data */
if (filetype)
*filetype = sym_archive_entry_filetype(entry);
if (mode)
*mode = sym_archive_entry_mode(entry);
if (mtime && sym_archive_entry_mtime_is_set(entry))
*mtime = (struct timespec) {
sym_archive_entry_mtime(entry),
sym_archive_entry_mtime_nsec(entry),
};
if (uid && sym_archive_entry_uid_is_set(entry))
*uid = sym_archive_entry_uid(entry);
if (gid && sym_archive_entry_gid_is_set(entry))
*gid = sym_archive_entry_gid(entry);
(void) sym_archive_entry_xattr_reset(entry);
for (;;) {
const char *name = NULL;
struct iovec data;
(void) sym_archive_entry_xattr_next(entry, &name, (const void**) &data.iov_base, &data.iov_len);
if (!name)
break;
if (xattr_is_acl(name))
continue;
if (!FLAGS_SET(flags, TAR_SELINUX) && xattr_is_selinux(name))
continue;
_cleanup_free_ char *n = strdup(name);
if (!n)
return log_oom();
_cleanup_(iovec_done) struct iovec iovec_copy = {};
if (!iovec_memdup(&data, &iovec_copy))
return log_oom();
if (!GREEDY_REALLOC(*xa, *n_xa+1))
return log_oom();
(*xa)[(*n_xa)++] = (XAttr) {
.name = TAKE_PTR(n),
.data = TAKE_STRUCT(iovec_copy),
};
}
return 0;
}
int tar_x(int input_fd, int tree_fd, TarFlags flags) {
int ar, r;
assert(input_fd >= 0);
assert(tree_fd >= 0);
_cleanup_(sym_archive_read_freep) struct archive *a = NULL;
a = sym_archive_read_new();
if (!a)
return log_oom();
ar = sym_archive_read_support_format_tar(a);
if (ar != ARCHIVE_OK)
return log_error_errno(
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to enable tar unpacking: %s", sym_archive_error_string(a));
ar = sym_archive_read_support_format_cpio(a);
if (ar != ARCHIVE_OK)
return log_error_errno(
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Failed to enable cpio unpacking: %s", sym_archive_error_string(a));
ar = sym_archive_read_open_fd(a, input_fd, 64 * 1024);
if (ar != ARCHIVE_OK)
return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to initialize archive context: %s", sym_archive_error_string(a));
OpenInode *open_inodes = NULL;
if (!GREEDY_REALLOC(open_inodes, 2)) /* the minimal case is a single file in an archive, which would
* mean two inodes, the root dir inode, and he regular file
* inode, hence start with 2 here */
return log_oom();
size_t n_open_inodes = 0;
CLEANUP_ARRAY(open_inodes, n_open_inodes, open_inode_done_many);
/* Fill in the root inode. (Note: we leave the .path field as NULL to mark it as root inode.) */
open_inodes[0] = (OpenInode) {
.fd = tree_fd,
.filetype = S_IFDIR,
.mode = MODE_INVALID,
.mtime = { .tv_nsec = UTIME_OMIT },
.uid = UID_INVALID,
.gid = GID_INVALID,
};
n_open_inodes = 1;
for (;;) {
struct archive_entry *entry = NULL;
ar = sym_archive_read_next_header(a, &entry);
if (ar == ARCHIVE_EOF)
break;
if (ar != ARCHIVE_OK)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse archive: %s", sym_archive_error_string(a));
const char *p = NULL;
r = archive_entry_pathname_safe(entry, &p);
if (r < 0)
return log_error_errno(r, "Invalid path name in entry, refusing.");
if (!p) {
/* This is the root inode */
r = archive_entry_read_stat(
entry,
&open_inodes[0].filetype,
&open_inodes[0].mode,
&open_inodes[0].mtime,
&open_inodes[0].uid,
&open_inodes[0].gid,
&open_inodes[0].xattr,
&open_inodes[0].n_xattr,
flags);
if (r < 0)
return r;
if (open_inodes[0].filetype != S_IFDIR)
return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Archives root inode is not a directory, refusing.");
continue;
}
/* Find common prefix with path elements we were looking at so far. */
const char *rest = p;
size_t i;
for (i = 1; i < n_open_inodes; i++) {
const char *e = path_startswith(p, open_inodes[i].path);
if (isempty(e))
break;
rest = e;
}
/* Finalize all inodes we won't need anymore now (go backwards, i.e. close inner fds first) */
while (n_open_inodes > i) {
r = open_inode_finalize(open_inodes + n_open_inodes - 1);
if (r < 0)
return r;
n_open_inodes--;
}
/* And now create all remaining components */
for (;;) {
const char *element;
r = path_find_first_component(&rest, /* accept_dot_dot= */ false, &element);
if (r < 0)
return log_error_errno(r, "Failed to extract next element from path: %m");
if (r == 0)
break;
/* Safety check, before we add another level to our stack */
if (n_open_inodes >= DEPTH_MAX)
return log_error_errno(
SYNTHETIC_ERRNO(E2BIG),
"Archive's directory tree nested too deeply, refusing to descend more than %u levels.", DEPTH_MAX);
_cleanup_free_ char *e = strndup(element, r);
if (!e)
return log_oom();
const char *parent_path = NULL;
int parent_fd = -EBADF;
assert(n_open_inodes > 0);
parent_fd = open_inodes[n_open_inodes-1].fd;
parent_path = open_inodes[n_open_inodes-1].path;
_cleanup_free_ char *j = parent_path ? path_join(parent_path, e) : strdup(e);
if (!j)
return log_oom();
if (!GREEDY_REALLOC(open_inodes, n_open_inodes+1))
return log_oom();
_cleanup_close_ int fd = -EBADF;
mode_t filetype = MODE_INVALID;
mode_t mode = MODE_INVALID;
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
struct timespec mtime = { .tv_nsec = UTIME_OMIT };
XAttr *xa = NULL;
size_t n_xa = 0;
CLEANUP_ARRAY(xa, n_xa, xattr_done_many);
if (isempty(rest)) {
/* This is the final node in the path, create it */
if (sym_archive_entry_hardlink_is_set(entry)) {
/* If this is a hardlink, act on it */
const char *h = sym_archive_entry_hardlink(entry);
if (!h)
return log_error_errno(
SYNTHETIC_ERRNO(EBADMSG),
"No hardlink target in hardlink entry, refusing.");
/* libarchive prefixes all paths with "./", let's chop that off */
const char *target = startswith(h, "./") ?: h;
if (!path_is_safe(target))
return log_error_errno(
SYNTHETIC_ERRNO(EBADMSG),
"Invalid hardlink path name '%s' in entry, refusing.", target);
_cleanup_close_ int target_fd = -EBADF;
r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT, /* ret_path= */ NULL, &target_fd);
if (r < 0)
return log_error_errno(
r,
"Failed to find inode '%s' which shall be hardlinked as '%s': %m", target, j);
struct stat verify_st;
if (fstat(target_fd, &verify_st) < 0)
return log_error_errno(errno, "Failed to stat inode '%s': %m", target);
/* Refuse hardlinking directories early. */
if (!inode_type_can_hardlink(verify_st.st_mode))
return log_error_errno(
SYNTHETIC_ERRNO(EBADF),
"Refusing to hardlink inode '%s' of type '%s': %m", target, inode_type_to_string(verify_st.st_mode));
if (linkat(target_fd, "", parent_fd, e, AT_EMPTY_PATH) < 0) {
if (errno != ENOENT)
return log_error_errno(
errno,
"Failed to hardlink inode '%s' as '%s': %m", target, j);
/* To be able to link by inode fd we might have needed
* CAP_DAC_READ_SEARCH which we lacked. Let's retry with the
* parent. Yes, glibc/kernel report this as ENOENT. Kinda
* annoying. */
_cleanup_close_ int target_parent_fd = -EBADF;
_cleanup_free_ char *target_filename = NULL;
r = chaseat(tree_fd, target, CHASE_PROHIBIT_SYMLINKS|CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_EXTRACT_FILENAME, &target_filename, &target_parent_fd);
if (r < 0)
return log_error_errno(
r,
"Failed to find inode '%s' which shall be hardlinked as '%s': %m", target, j);
if (linkat(target_parent_fd, target_filename, parent_fd, e, /* flags= */ 0) < 0)
return log_error_errno(
errno,
"Failed to hardlink inode '%s' as '%s': %m", target, j);
}
continue;
}
r = archive_entry_read_stat(
entry,
&filetype,
&mode,
&mtime,
&uid,
&gid,
&xa,
&n_xa,
flags);
if (r < 0)
return r;
switch (filetype) {
case S_IFREG:
fd = archive_unpack_regular(a, entry, parent_fd, e, j);
break;
case S_IFDIR:
fd = archive_unpack_directory(a, entry, parent_fd, e, j);
break;
case S_IFLNK:
fd = archive_unpack_symlink(a, entry, parent_fd, e, j);
break;
case S_IFCHR:
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
fd = archive_unpack_special_inode(a, entry, parent_fd, e, j, filetype);
break;
default:
return log_error_errno(
SYNTHETIC_ERRNO(ENOTRECOVERABLE),
"Unexpected file type %i of '%s', refusing.", (int) filetype, j);
}
if (fd < 0)
return fd;
} else {
/* This is some intermediary node in the path that we haven't opened yet. Create it with default attributes */
fd = open_mkdir_at(parent_fd, e, O_CLOEXEC, 0700);
if (fd < 0)
return log_error_errno(fd, "Failed to create directory '%s': %m", j);
filetype = S_IFDIR;
}
/* Now store a reference to the inode we just created in our stack array. Note that
* we have not applied file ownership, access mode, mtime here, we'll do that only
* when we are finished with the inode, since we have to apply them *after* we are
* fully done with the inode (i.e. after creating further inodes inside of dir inodes
* for example), due to permission problems this might create or that the mtime
* changes we do might still be affected by our changes. */
open_inodes[n_open_inodes++] = (OpenInode) {
.fd = TAKE_FD(fd),
.path = TAKE_PTR(j),
.filetype = filetype,
.mode = mode,
.mtime = mtime,
.uid = uid,
.gid = gid,
.xattr = TAKE_PTR(xa),
.n_xattr = n_xa,
};
n_xa = 0;
}
}
r = open_inode_finalize_many(&open_inodes, &n_open_inodes);
if (r < 0)
return r;
return 0;
}
#else
int tar_x(int input_fd, int tree_fd, TarFlags flags) {
assert(input_fd >= 0);
assert(tree_fd >= 0);
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libarchive support not available.");
}
#endif

View File

@ -1,8 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
typedef enum TarFlags {
TAR_SELINUX = 1 << 0,
} TarFlags;
int tar_x(int input_fd, int tree_fd, TarFlags flags);

View File

@ -60,8 +60,6 @@ static SD_VARLINK_DEFINE_METHOD(
SD_VARLINK_DEFINE_INPUT(password, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_INPUT(password, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Takes an image policy string (see systemd.image-policy(7) for details) to apply while mounting the image"), SD_VARLINK_FIELD_COMMENT("Takes an image policy string (see systemd.image-policy(7) for details) to apply while mounting the image"),
SD_VARLINK_DEFINE_INPUT(imagePolicy, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_INPUT(imagePolicy, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Whether to automatically reuse already set up dm-verity devices that share the same roothash."),
SD_VARLINK_DEFINE_INPUT(veritySharing, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE),
VARLINK_DEFINE_POLKIT_INPUT, VARLINK_DEFINE_POLKIT_INPUT,
SD_VARLINK_FIELD_COMMENT("An array with information about contained partitions that have been prepared for mounting, as well as their mount file descriptors."), SD_VARLINK_FIELD_COMMENT("An array with information about contained partitions that have been prepared for mounting, as well as their mount file descriptors."),
SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(partitions, PartitionInfo, SD_VARLINK_ARRAY), SD_VARLINK_DEFINE_OUTPUT_BY_TYPE(partitions, PartitionInfo, SD_VARLINK_ARRAY),

View File

@ -61,7 +61,6 @@ int sd_dhcp_server_set_boot_server_name(sd_dhcp_server *server, const char *name
int sd_dhcp_server_set_boot_filename(sd_dhcp_server *server, const char *filename); int sd_dhcp_server_set_boot_filename(sd_dhcp_server *server, const char *filename);
int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server *server, int enabled); int sd_dhcp_server_set_bind_to_interface(sd_dhcp_server *server, int enabled);
int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone); int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone);
int sd_dhcp_server_set_domain_name(sd_dhcp_server *server, const char *domain_name);
int sd_dhcp_server_set_router(sd_dhcp_server *server, const struct in_addr *address); int sd_dhcp_server_set_router(sd_dhcp_server *server, const struct in_addr *address);
int sd_dhcp_server_set_servers( int sd_dhcp_server_set_servers(

View File

@ -29,16 +29,9 @@ ProtectHostname=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
RestrictRealtime=yes RestrictRealtime=yes
RestrictSUIDSGID=yes RestrictSUIDSGID=yes
SystemCallArchitectures=native
# FIXME: libseccomp (as of 2.6.0) doesn't know the open_tree_attr() system call SystemCallErrorNumber=EPERM
# yet which we need. Thus, applying any system call filter would block this SystemCallFilter=@system-service @mount
# system call unconditionally, which is not desirable. This should be added
# back once libseccomp is updated. See
# https://github.com/seccomp/libseccomp/issues/465
#SystemCallArchitectures=native
#SystemCallErrorNumber=EPERM
#SystemCallFilter=@system-service @mount
Type=notify Type=notify
NotifyAccess=all NotifyAccess=all
FileDescriptorStoreMax=4096 FileDescriptorStoreMax=4096