Openssh package build failed (check phase)

Hello all!

I’m trying to build an openssh package with the latest nixpkgs in the official container image nixos/nix:2.8.0. Here are my actions, done manually:

docker run --rm -it -w /root nixos/nix:2.8.0 bash
echo "https://channels.nixos.org/nixos-21.11 nixpkgs" > ~/.nix-channels
nix-channel --update
nix-collect-garbage -d
cat > configuration.nix << END
{ ... }:
{
  nixpkgs.overlays = [
    (self: super: {
      openssh = super.openssh.override {
        withKerberos = false;
        withFIDO = false;
      };
    })
  ];
}
END
cat > default.nix << END
{ ... }:

let
  system = "x86_64-linux";

  eval = import <nixpkgs/nixos/lib/eval-config.nix> {
    inherit system;
    modules = [ ./configuration.nix ];
  };

in {
  inherit (eval) config pkgs;
}
END
nix-build . --no-out-link -A pkgs.openssh 2>&1 | tee openssh-build.log

I’m getting this error as a result:

make[1]: Entering directory '/tmp/nix-build-openssh-8.8p1.drv-0/openssh-8.8p1/regress'
run test connect.sh ...

WARNING: Unsafe (group or world writable) directory permissions found:
 /tmp

These could be abused to locally escalate privileges.  If you are
sure that this is not a risk (eg there are no other users), you can
bypass this check by setting TEST_SSH_UNSAFE_PERMISSIONS=1

ssh direct connect failed
ssh proxycommand connect failed
failed simple connect
make[1]: *** [Makefile:219: t-exec] Error 1
make[1]: Leaving directory '/tmp/nix-build-openssh-8.8p1.drv-0/openssh-8.8p1/regress'
make: *** [Makefile:721: t-exec] Error 2
error: builder for '/nix/store/j1dya0s6zdhv5fq44c2izpbd8imc7vni-openssh-8.8p1.drv' failed with exit code 2

What am I doing wrong? How to fix the error?

Regards,
Timofei

Well, as openssh says in its error message, /tmp happens to have world/group writeable permissions in your container. Openssh, as a relatively security critical application, really cares about the permissions of the directory in which its configuration lives (since otherwise a local, unprivileged user might change it and make it possible to ssh root@localhost).

By default, nix will test everything in /tmp because it will delete the directory once it’s done. This means that ssh’s configuration will be in that directory, and it blows up.

This is hardly a concern for a build docker container, so you could just set the environment variable it recommends and be done with it. Or you could change the permissions of /tmp before the build, since no other process will be running in the container anyway. Or change the directory in which nix tests this derivation somehow, not sure if/how that’s possible.

More interestingly, why does this fail here but not upstream? I think probably because of the sandbox, which presumably isn’t usable in a container?

I’m tried to do the same in official ubuntu:22.04 container:

docker run --rm -it -w /root ubuntu:22.04 bash

useradd -m -G sudo -s /bin/bash nixbld
mkdir /nix
chown nixbld.nixbld /nix
apt update
apt install -y bzip2 curl git vim xz-utils

su - nixbld

curl -sSO https://releases.nixos.org/nix/nix-2.8.0/nix-2.8.0-x86_64-linux.tar.xz
tar xJf nix-2.8.0-x86_64-linux.tar.xz
cd nix-2.8.0-x86_64-linux
echo "https://channels.nixos.org/nixos-21.11 nixpkgs" > ~/.nix-channels
./install
cd ..
rm -rf nix-*-x86_64-linux*
. ~/.nix-profile/etc/profile.d/nix.sh

cat > configuration.nix << END
{ ... }:
{
  nixpkgs.overlays = [
    (self: super: {
      openssh = super.openssh.override {
        withKerberos = false;
        withFIDO = false;
      };
    })
  ];
}
END
cat > default.nix << END
{ ... }:

let
  system = "x86_64-linux";

  eval = import <nixpkgs/nixos/lib/eval-config.nix> {
    inherit system;
    modules = [ ./configuration.nix ];
  };

in {
  inherit (eval) config pkgs;
}
END
nix-build . --no-out-link -A pkgs.openssh 2>&1 | tee openssh-build.log

And got another error:

make[1]: Entering directory '/tmp/nix-build-openssh-8.8p1.drv-0/openssh-8.8p1/regress'
run test connect.sh ...

WARNING: Unsafe (group or world writable) directory permissions found:
 /tmp

These could be abused to locally escalate privileges.  If you are
sure that this is not a risk (eg there are no other users), you can
bypass this check by setting TEST_SSH_UNSAFE_PERMISSIONS=1

/bin/sh: symbol lookup error: /nix/store/qjgj2642srlbr59wwdihnn66sw97ming-glibc-2.33-123/lib/libdl.so.2: undefined symbol: _dl_catch_error_ptr, version GLIBC_PRIVATE
/bin/sh: symbol lookup error: /nix/store/qjgj2642srlbr59wwdihnn66sw97ming-glibc-2.33-123/lib/libdl.so.2: undefined symbol: _dl_catch_error_ptr, version GLIBC_PRIVATE
chmod: cannot access '/tmp/nix-build-openssh-8.8p1.drv-0/openssh-8.8p1/regress/authorized_keys_nixbld': No such file or directory
sshd: no hostkeys available -- exiting.
FATAL: sshd_proxy broken
make[1]: *** [Makefile:219: t-exec] Error 1
make[1]: Leaving directory '/tmp/nix-build-openssh-8.8p1.drv-0/openssh-8.8p1/regress'
make: *** [Makefile:721: t-exec] Error 2
error: builder for '/nix/store/j1dya0s6zdhv5fq44c2izpbd8imc7vni-openssh-8.8p1.drv' failed with exit code 2

I found a workaround (a bad one) for the error:

ln -sf /nix/store/dzrvibwj2vjwqmc34wk3x1ffsjpp4av7-bash-4.4-p23/bin/bash /bin/sh

After that openssh builds correctly.

How to fix the error?
Any help is appreciated.

Timofei

Thanks, @TLATER, but /tmp permissions do not cause this error.

Is there any way to do check phase in sandbox?

I don’t know for sure :slight_smile: I suspect you probably shouldn’t if it doesn’t already, or if the /tmp permissions aren’t the problem (which your second experiment suggests, though I don’t understand what changed).

If you’d like to try, you probably need to run a privileged docker container (much more of a security risk, essentially gives the container root access to your system), or set up its cgroup correctly, to make it possible, and then set sandbox = true in the nix config.

Your hack there is interesting. That definitely points to pollution of the build env because the container’s /bin/sh happens to be used, rather than the one nix provides. Maybe you can fix that by patching a shebang or some kind of external command calling function somewhere? If you can find out what tries to execute that it’s probably fixable.

Assuming you’re using a container you will throw away, and this is only in checkPhase, the hack might be totally fine though.

On a side note, are you aware of the nixos docker containers? You might have more luck with them: NixOS - Getting Nix / NixOS

Thanx, @TLATER, I tried to patch shebangs and build openssh in ubuntu:22.04 container without my /bin/sh hack. Here is my new configuration.nix file:

{ lib, ... }:

with lib;

{
  nixpkgs.overlays = [
    (self: super: {
      openssh = overrideDerivation (super.openssh.override {
          withKerberos = false;
          withFIDO = false;
        }) (p: {
          postPatch = (p.postPatch or "") + ''
            for file in `grep -r '^#!/bin/sh' regress/ | cut -d: -f1 | sort -u`; do
              substituteInPlace $file --replace /bin/sh "${self.runtimeShell}"
            done
            substituteInPlace regress/sftp-perm.sh --replace /bin/sh "${self.runtimeShell}"
          '';
      });
    })
  ];
}

With shebang patching are checks running, but failed in another place:

run test sftp-glob.sh ...

WARNING: Unsafe (group or world writable) directory permissions found:
 /tmp

These could be abused to locally escalate privileges.  If you are
sure that this is not a risk (eg there are no other users), you can
bypass this check by setting TEST_SSH_UNSAFE_PERMISSIONS=1

sftp glob: file glob
/tmp/nix-build-openssh-8.8p1.drv-0/openssh-8.8p1/regress/glob/dir/file missing from file glob results
sftp glob: dir glob
file missing from dir glob results
sftp glob: quoted glob
g-wild* missing from quoted glob results
sftp glob: escaped glob
g-wild* missing from escaped glob results
sftp glob: escaped quote
g-quote" missing from escaped quote results
sftp glob: quoted quote
g-quote" missing from quoted quote results
sftp glob: single-quoted quote
g-quote" missing from single-quoted quote results
sftp glob: escaped space
g-q space missing from escaped space results
sftp glob: quoted space
g-q space missing from quoted space results
sftp glob: escaped slash
g-sl\ash missing from escaped slash results
sftp glob: quoted slash
g-sl\ash missing from quoted slash results
sftp glob: escaped slash at EOL
g-slash\ missing from escaped slash at EOL results
sftp glob: quoted slash at EOL
g-slash\ missing from quoted slash at EOL results
sftp glob: escaped slash+quote
g-qs\" missing from escaped slash+quote results
sftp glob: quoted slash+quote
g-qs\" missing from quoted slash+quote results
failed sftp glob
make[1]: *** [Makefile:219: t-exec] Error 1
make[1]: Leaving directory '/tmp/nix-build-openssh-8.8p1.drv-0/openssh-8.8p1/regress'
make: *** [Makefile:721: t-exec] Error 2
note: keeping build directory '/tmp/nix-build-openssh-8.8p1.drv-0'
error: builder for '/nix/store/r1z328kbqwb7dvpwc6ysiq8b391fzcz3-openssh-8.8p1.drv' failed with exit code 2

So the shebang patching does not solve the problem. Is it possible to run check phase in chroot or sandbox where /bin/sh may be overridden?

Could you try ${pkgs.bash}/bin/bash? It seems to be using busybox’ ash, which I suspect doesn’t support all the globbing your check files expect to be able to use.

That’s what the sandbox = true in nix’ config would be for. If you try that, you should probably also disable the fallback so you’ll see if it’s not working, and double check it’s set to bind-mount /bin/sh. Once again though, doing this in a docker container is not trivial, because it’s essentially running a container inside your container (which requires privileges that docker containers don’t usually have).

The error in sftp-glob.sh is due to it uses fgrep program and the fgrep itself is a script with direct '/bin/sh` shebang:

$ cat /nix/store/hq0dj7mrf3nn4xppyg4ypmm2jb2cpfla-gnugrep-3.7/bin/fgrep 
#! /bin/sh
exec /nix/store/hq0dj7mrf3nn4xppyg4ypmm2jb2cpfla-gnugrep-3.7/bin/grep -F "$@"

So, in sftp-glob.sh fgrep should be replaced by grep -F for check phase to work. hostkey-rotate.sh should be patched too.

1 Like