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)

Reply via email to