From: Yu Watanabe Date: Sat, 11 Oct 2025 03:30:05 +0000 (+0900) Subject: hostname-setup: introduce pidref_gethostname_full() X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F39350%2Fhead;p=thirdparty%2Fsystemd.git hostname-setup: introduce pidref_gethostname_full() --- diff --git a/src/shared/hostname-setup.c b/src/shared/hostname-setup.c index ac13d06fb23..4e977eed125 100644 --- a/src/shared/hostname-setup.c +++ b/src/shared/hostname-setup.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include #include #include #include @@ -15,8 +16,12 @@ #include "hostname-setup.h" #include "hostname-util.h" #include "initrd-util.h" +#include "io-util.h" #include "log.h" +#include "namespace-util.h" +#include "pidref.h" #include "proc-cmdline.h" +#include "process-util.h" #include "siphash24.h" #include "string-table.h" #include "string-util.h" @@ -344,3 +349,66 @@ int gethostname_full(GetHostnameFlags flags, char **ret) { *ret = TAKE_PTR(buf); return 0; } + +int pidref_gethostname_full(PidRef *pidref, GetHostnameFlags flags, char **ret) { + int r; + + assert(pidref); + assert(ret); + + r = pidref_in_same_namespace(pidref, NULL, NAMESPACE_UTS); + if (r < 0) + return r; + if (r > 0) + return gethostname_full(flags, ret); + + _cleanup_close_ int utsns_fd = r = pidref_namespace_open_by_type(pidref, NAMESPACE_UTS); + if (r < 0) + return r; + + _cleanup_close_pair_ int errno_pipe[2] = EBADF_PAIR; + r = pipe2(errno_pipe, O_CLOEXEC); + if (r < 0) + return -errno; + + _cleanup_close_pair_ int result_pipe[2] = EBADF_PAIR; + r = pipe2(result_pipe, O_CLOEXEC); + if (r < 0) + return -errno; + + _cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL; + r = pidref_safe_fork("(gethostname)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &child); + if (r < 0) + return r; + if (r == 0) { + errno_pipe[0] = safe_close(errno_pipe[0]); + result_pipe[0] = safe_close(result_pipe[0]); + + if (setns(utsns_fd, CLONE_NEWUTS) < 0) + report_errno_and_exit(errno_pipe[1], -errno); + + char *t; + r = gethostname_full(flags, &t); + if (r < 0) + report_errno_and_exit(errno_pipe[1], r); + + r = loop_write(result_pipe[1], t, strlen(t) + 1); + report_errno_and_exit(errno_pipe[1], r); + } + + errno_pipe[1] = safe_close(errno_pipe[1]); + result_pipe[1] = safe_close(result_pipe[1]); + + r = read_errno(errno_pipe[0]); + if (r < 0) + return r; + + char buf[HOST_NAME_MAX+1]; + ssize_t n = loop_read(result_pipe[0], buf, sizeof(buf), /* do_poll = */ false); + if (n < 0) + return n; + if (n == 0 || buf[n - 1] != '\0') + return -EPROTO; + + return strdup_to(ret, buf); +} diff --git a/src/shared/hostname-setup.h b/src/shared/hostname-setup.h index 9af57fad564..7f6216ce6eb 100644 --- a/src/shared/hostname-setup.h +++ b/src/shared/hostname-setup.h @@ -56,3 +56,5 @@ static inline char* gethostname_short_malloc(void) { return s; } + +int pidref_gethostname_full(PidRef *pidref, GetHostnameFlags flags, char **ret); diff --git a/src/test/test-hostname-setup.c b/src/test/test-hostname-setup.c index 87c9f7d7515..e3fc8a220b6 100644 --- a/src/test/test-hostname-setup.c +++ b/src/test/test-hostname-setup.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include "alloc-util.h" @@ -9,6 +10,8 @@ #include "hostname-setup.h" #include "hostname-util.h" #include "id128-util.h" +#include "pidref.h" +#include "process-util.h" #include "tests.h" #include "tmpfile-util.h" @@ -132,4 +135,69 @@ TEST(default_hostname) { ASSERT_TRUE(hostname_is_valid(m, VALID_HOSTNAME_QUESTION_MARK)); } +TEST(pidref_gethostname_full) { + int r; + + if (geteuid() != 0) + return (void) log_tests_skipped("Not privileged"); + + _cleanup_free_ char *original = NULL, *original_short = NULL; + ASSERT_NOT_NULL(original = gethostname_malloc()); + ASSERT_NOT_NULL(original_short = gethostname_short_malloc()); + + _cleanup_close_pair_ int fds[2] = EBADF_PAIR; + ASSERT_OK_ERRNO(pipe2(fds, O_CLOEXEC)); + + _cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL; + r = pidref_safe_fork("(test-pidref-gethostname)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, &pidref); + ASSERT_OK(r); + if (r == 0) { + fds[0] = safe_close(fds[0]); + + ASSERT_OK_ERRNO(unshare(CLONE_NEWUTS)); + ASSERT_OK(sethostname_idempotent("hogehoge.example.com")); + + ASSERT_OK_EQ_ERRNO(write(fds[1], &(const char[]) { 'x' }, 1), 1); + freeze(); + } + + fds[1] = safe_close(fds[1]); + + char x; + ASSERT_OK_EQ_ERRNO(read(fds[0], &x, 1), 1); + ASSERT_EQ(x, 'x'); + + _cleanup_free_ char *s = NULL; + ASSERT_OK(pidref_gethostname_full(&pidref, /* flags= */ 0, &s)); + ASSERT_STREQ(s, "hogehoge.example.com"); + + s = mfree(s); + + ASSERT_OK(pidref_gethostname_full(&pidref, GET_HOSTNAME_SHORT, &s)); + ASSERT_STREQ(s, "hogehoge"); + + s = mfree(s); + + _cleanup_(pidref_done) PidRef self = PIDREF_NULL; + ASSERT_OK(pidref_set_self(&self)); + + ASSERT_OK(pidref_gethostname_full(&self, /* flags= */ 0, &s)); + ASSERT_STREQ(s, original); + + s = mfree(s); + + ASSERT_OK(pidref_gethostname_full(&self, GET_HOSTNAME_SHORT, &s)); + ASSERT_STREQ(s, original_short); + + s = mfree(s); + + ASSERT_NOT_NULL(s = gethostname_malloc()); + ASSERT_STREQ(s, original); + + s = mfree(s); + + ASSERT_NOT_NULL(s = gethostname_short_malloc()); + ASSERT_STREQ(s, original_short); +} + DEFINE_TEST_MAIN(LOG_DEBUG);