civodul pushed a commit to branch master in repository guix. commit eab097c682ed31efd8668f46fce8de8f73b92849 Author: Sergey Trofimov <s...@sarg.org.ru> AuthorDate: Wed Apr 23 16:13:10 2025 +0200
gnu: openssh: Adapt for root-less guix store. Fixes <https://issues.guix.gnu.org/78067>. Previously sshd would use /gnu/store/…-openssh-…/var/empty as its PRIVSEP_PATH. However, when using the unprivileged daemon, that directory would belong to guix-daemon:guix-daemon, leading to this error: sshd[234]: fatal: /gnu/store/…-openssh-10.0p1/var/empty must be owned by root and not group or world-writable. Fix that by switching to /var/empty. * gnu/packages/patches/openssh-trust-guix-store-directory.patch (openssh): Adjust to trust files in guix store owned by guix-daemon. * gnu/packages/ssh.scm (openssh)[arguments]: Remove ‘reset-/var/empty’ phase; change ‘install’ phase to not create PRIVSEP_PATH.. Append ending slash when substituting STORE_DIRECTORY. Change-Id: I3bd01f8b9d6406e3b886eea8f4b8c265a51cc72f Reported-by: Zack Weinberg <z...@owlfolio.org> Signed-off-by: Ludovic Courtès <l...@gnu.org> --- .../openssh-trust-guix-store-directory.patch | 67 +++++++++++++++------- gnu/packages/ssh.scm | 14 ++--- 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/gnu/packages/patches/openssh-trust-guix-store-directory.patch b/gnu/packages/patches/openssh-trust-guix-store-directory.patch index b3a9c1bdfc..d190740f10 100644 --- a/gnu/packages/patches/openssh-trust-guix-store-directory.patch +++ b/gnu/packages/patches/openssh-trust-guix-store-directory.patch @@ -3,20 +3,20 @@ From: Alexey Abramov <leven...@mmer.org> Date: Fri, 22 Apr 2022 11:32:15 +0200 Subject: [PATCH] Trust guix store directory -To be able to execute binaries defined in OpenSSH configuration, we -need to tell OpenSSH that we can trust Guix store objects. safe_path -procedure takes a canonical path and for each component, walking -upwards, checks ownership and permissions constrains which are: must -be owned by root, not writable by group or others. +To be able to execute binaries defined in OpenSSH configuration, we need to +tell OpenSSH that we can trust Guix store objects. safe_path procedure is +patched to assume files in Guix store to be safe. Additionally configuration +file placed in Guix store is assumed to be safe to load. --- - misc.c | 5 +++++ - 1 file changed, 5 insertions(+) + misc.c | 6 ++++++ + readconf.c | 7 ++++--- + 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/misc.c b/misc.c -index 0134d69..7131d5e 100644 +index dd0bd032a..6b866464c 100644 --- a/misc.c +++ b/misc.c -@@ -2146,6 +2146,7 @@ int +@@ -2254,6 +2254,7 @@ int safe_path(const char *name, struct stat *stp, const char *pw_dir, uid_t uid, char *err, size_t errlen) { @@ -24,17 +24,42 @@ index 0134d69..7131d5e 100644 char buf[PATH_MAX], homedir[PATH_MAX]; char *cp; int comparehome = 0; -@@ -2178,6 +2179,10 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir, - } - strlcpy(buf, cp, sizeof(buf)); - -+ /* If we are past the Guix store then we can stop */ -+ if (strcmp(guix_store, buf) == 0) -+ break; +@@ -2271,6 +2272,11 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir, + snprintf(err, errlen, "%s is not a regular file", buf); + return -1; + } ++ // the file is trusted when it is located in guix store ++ if (strncmp(buf, guix_store, strlen(guix_store)) == 0) { ++ return 0; ++ } + - if (stat(buf, &st) == -1 || - (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || - (st.st_mode & 022) != 0) { + if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || + (stp->st_mode & 022) != 0) { + snprintf(err, errlen, "bad ownership or modes for file %s", +diff --git a/readconf.c b/readconf.c +index 7cbe7d2c2..40a5f1ace 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -2566,6 +2566,7 @@ read_config_file_depth(const char *filename, struct passwd *pw, + { + FILE *f; + char *line = NULL; ++ char errmsg[512]; + size_t linesize = 0; + int linenum; + int bad_options = 0; +@@ -2581,9 +2582,9 @@ read_config_file_depth(const char *filename, struct passwd *pw, + + if (fstat(fileno(f), &sb) == -1) + fatal("fstat %s: %s", filename, strerror(errno)); +- if (((sb.st_uid != 0 && sb.st_uid != getuid()) || +- (sb.st_mode & 022) != 0)) +- fatal("Bad owner or permissions on %s", filename); ++ if (safe_path(filename, &sb, pw->pw_dir, pw->pw_uid, errmsg, sizeof(errmsg)) != 0) { ++ fatal(errmsg); ++ } + } + + debug("Reading configuration data %.200s", filename); -- -2.34.0 - +2.49.0 diff --git a/gnu/packages/ssh.scm b/gnu/packages/ssh.scm index de99bbfc90..f14dd431ac 100644 --- a/gnu/packages/ssh.scm +++ b/gnu/packages/ssh.scm @@ -275,16 +275,11 @@ a server that supports the SSH-2 protocol.") '())) #:phases #~(modify-phases %standard-phases - (add-after 'configure 'reset-/var/empty - (lambda _ - (substitute* "Makefile" - (("PRIVSEP_PATH=/var/empty") - (string-append "PRIVSEP_PATH=" #$output "/var/empty"))))) (add-after 'configure 'set-store-location (lambda _ (substitute* "misc.c" (("@STORE_DIRECTORY@") - (string-append "\"" (%store-directory) "\""))))) + (string-append "\"" (%store-directory) "/\""))))) (add-before 'check 'patch-tests (lambda _ (substitute* "regress/test-exec.sh" @@ -297,9 +292,10 @@ a server that supports the SSH-2 protocol.") (string-append pre post))))) (replace 'install (lambda* (#:key (make-flags '()) #:allow-other-keys) - ;; Install without host keys and system configuration files. This - ;; will install /var/empty to the store, which is needed by the - ;; system openssh-service-type. + ;; Don't create /var/empty. + (substitute* "Makefile" + ((".*MKDIR_P.*PRIVSEP_PATH.*") "")) + ;; Install without host keys and system configuration files. (apply invoke "make" "install-nosysconf" make-flags) (with-directory-excursion "contrib" (chmod "ssh-copy-id" #o555)