‘--disable-chroot’ don't let guix-daemon skip the ‘personality’ call after be8aca0651 #3917

Closed
opened 2025-10-28 11:50:50 +01:00 by reycoseb · 9 comments

I'm trying the GitlabCI guix ready workflow developped by Simon Josefsson https://social.sciences.re/@[email protected] at https://gitlab.com/debdistutils/guix/container

guix describe outputs:

  guix 230ad0e
    repository URL: https://git.guix.gnu.org/guix.git
    branch: master
    commit: 230ad0e3370e7a7a927d54dff33d2cee8b6300f9

I have no choice to run the guix daemon only using --disable-chroot

The complete gitlab CI :

test-guix-deploy-website:

  image: registry.gitlab.com/debdistutils/guix/container:latest
  before_script:
    - cp -rL /gnu/store/*profile/etc/* /etc/
    - echo 'root:x:0:0:root:/:/bin/sh' > /etc/passwd
    - echo 'root:x:0:' > /etc/group
    - groupadd --system guixbuild
    - for i in $(seq -w 1 10); do useradd -g guixbuild -G guixbuild -d /var/empty -s $(command -v nologin) -c "Guix build user $i" --system guixbuilder$i; done
    - export HOME=/
    - env LANG=C.UTF-8 guix-daemon --disable-chroot --build-users-group=guixbuild &
    - guix archive --authorize < /share/guix/ci.guix.gnu.org.pub
    - guix archive --authorize < /share/guix/bordeaux.guix.gnu.org.pub
    - guix describe
    - guix install hello
    - GUIX_PROFILE="//.guix-profile"
    - . "$GUIX_PROFILE/etc/profile"

  script:
     - guix describe

Any guix install on the CI return : guix install: error: while setting up the child process: in phase setPersonality: cannot set personality: Operation not permitted

The full trace here :
https://gitlab.huma-num.fr/gt-notebook/wiki-website/wiki-mkdocs/-/jobs/160915

@civodul say to me on mastodon this is potentially linked to commit be8aca065118aa4485c02f991c51bea89034defa :

My guess is that before be8aca065118aa4485c02f991c51bea89034defa, ‘--disable-chroot’ would let guix-daemon skip the ‘personality’ call, but that after that it no longer skips it.
I'm trying the **GitlabCI guix ready workflow** developped by Simon Josefsson https://social.sciences.re/@[email protected] at https://gitlab.com/debdistutils/guix/container `guix describe` outputs: ```text guix 230ad0e repository URL: https://git.guix.gnu.org/guix.git branch: master commit: 230ad0e3370e7a7a927d54dff33d2cee8b6300f9 ``` I have no choice to run the guix daemon only using `--disable-chroot` The complete gitlab CI : ``` test-guix-deploy-website: image: registry.gitlab.com/debdistutils/guix/container:latest before_script: - cp -rL /gnu/store/*profile/etc/* /etc/ - echo 'root:x:0:0:root:/:/bin/sh' > /etc/passwd - echo 'root:x:0:' > /etc/group - groupadd --system guixbuild - for i in $(seq -w 1 10); do useradd -g guixbuild -G guixbuild -d /var/empty -s $(command -v nologin) -c "Guix build user $i" --system guixbuilder$i; done - export HOME=/ - env LANG=C.UTF-8 guix-daemon --disable-chroot --build-users-group=guixbuild & - guix archive --authorize < /share/guix/ci.guix.gnu.org.pub - guix archive --authorize < /share/guix/bordeaux.guix.gnu.org.pub - guix describe - guix install hello - GUIX_PROFILE="//.guix-profile" - . "$GUIX_PROFILE/etc/profile" script: - guix describe ``` Any guix install on the CI return : `guix install: error: while setting up the child process: in phase setPersonality: cannot set personality: Operation not permitted` The full trace here : https://gitlab.huma-num.fr/gt-notebook/wiki-website/wiki-mkdocs/-/jobs/160915 @civodul say to me on [mastodon](https://social.sciences.re/deck/@[email protected]/115429075142861566) this is potentially linked to commit `be8aca065118aa4485c02f991c51bea89034defa` : My guess is that before be8aca065118aa4485c02f991c51bea89034defa, ‘--disable-chroot’ would let guix-daemon skip the ‘personality’ call, but that after that it no longer skips it.
Owner

Hello,

Thanks for reporting it, @reycoseb! @reepca: Should setPersonalityAction be moved from getBasicSpawnPhases to getCloneSpawnPhases given that the former is used when useChroot == false?

Hello, Thanks for reporting it, @reycoseb! @reepca: Should `setPersonalityAction` be moved from `getBasicSpawnPhases` to `getCloneSpawnPhases` given that the former is used when `useChroot == false`?
Contributor

The reasoning behind putting setPersonalityAction with getBasicSpawnPhases is that it doesn't depend on namespaces in any way, and is nevertheless a useful per-process property to configure.

If we want to disable it, this can be done by configuring SpawnContext.setPersona to false, which is the default when not explicitly initialized.

The reason that build.cc currently always uses personality on linux (as opposed to solely when impersonating a 32-bit system) is twofold: first, to set ADDR_NO_RANDOMIZE and UNAME26 (where available) for increased determinism, and second, because it's possible that the daemon was run with additional personality flags that could affect reproducibility, in which case they should be reset to some uniform state. Rather than check the current personality flags and reset them only if they don't match the uniform state, it was simpler to just ignore the previous personality flags and unconditionally set to the target personality flags.

I had assumed that this was reasonable on the basis that the only error listed in personality(2) is EINVAL, and there aren't any listed permission requirements. Glancing through the kernel source, I don't immediately see anything that would give EPERM. Is there a seccomp filter or something similar in place for the container that is preventing its use? When I manually modify test-env to run with --disable-chroot, it starts builds just fine.

We could add a flag or environment variable to disable the personality call, but I'd like to know why it's failing. Does it always fail with EPERM, or only when it's setting it (by passing in an argument other than 0xffffffff), or only when it's actually changing it (by passing in an argument that's not 0xffffffff and is also different from the current value)? Could you try running setarch --show and setarch --addr-no-randomize true, where setarch is from the util-linux package?

If the container tool you're using is blocking personality, does it have some way to unblock it? Some brief searching online suggests that it might be specifically ADDR_NO_RANDOMIZE that's being blocked, e.g. https://sourceware.org/pipermail/glibc-cvs/2023q2/082573.html.

If so, we could perhaps modify build.cc to do a "test" call of personality to see if it's allowed to set that, undo it if it succeeds, and leave it out of the personality specification if it doesn't.

The reasoning behind putting `setPersonalityAction` with `getBasicSpawnPhases` is that it doesn't depend on namespaces in any way, and is nevertheless a useful per-process property to configure. If we want to disable it, this can be done by configuring `SpawnContext.setPersona` to `false`, which is the default when not explicitly initialized. The reason that build.cc currently always uses `personality` on linux (as opposed to solely when impersonating a 32-bit system) is twofold: first, to set `ADDR_NO_RANDOMIZE` and `UNAME26` (where available) for increased determinism, and second, because it's possible that the daemon was run with additional personality flags that could affect reproducibility, in which case they should be reset to some uniform state. Rather than check the current personality flags and reset them only if they don't match the uniform state, it was simpler to just ignore the previous personality flags and unconditionally set to the target personality flags. I had assumed that this was reasonable on the basis that the only error listed in `personality(2)` is `EINVAL`, and there aren't any listed permission requirements. Glancing through the kernel source, I don't immediately see anything that would give `EPERM`. Is there a seccomp filter or something similar in place for the container that is preventing its use? When I manually modify `test-env` to run with `--disable-chroot`, it starts builds just fine. We could add a flag or environment variable to disable the `personality` call, but I'd like to know why it's failing. Does it always fail with `EPERM`, or only when it's setting it (by passing in an argument other than `0xffffffff`), or only when it's actually changing it (by passing in an argument that's not `0xffffffff` and is also different from the current value)? Could you try running `setarch --show` and `setarch --addr-no-randomize true`, where `setarch` is from the util-linux package? If the container tool you're using is blocking `personality`, does it have some way to unblock it? Some brief searching online suggests that it might be specifically `ADDR_NO_RANDOMIZE` that's being blocked, e.g. https://sourceware.org/pipermail/glibc-cvs/2023q2/082573.html. If so, we could perhaps modify build.cc to do a "test" call of `personality` to see if it's allowed to set that, undo it if it succeeds, and leave it out of the personality specification if it doesn't.
Owner

@reepca Just checked with @reycoseb on Mastodon: @reycoseb confirms that setarch --addr-no-randomize true also fails with EPERM in that container.

Most likely a seccomp filter installed by Docker?

@reepca Just checked with @reycoseb on Mastodon: @reycoseb [confirms](https://gitlab.huma-num.fr/gt-notebook/wiki-website/wiki-mkdocs/-/jobs/162992) that `setarch --addr-no-randomize true` also fails with `EPERM` in that container. Most likely a seccomp filter installed by Docker?
Contributor

I confirmed that invoking podman/buildah with --security-opt seccomp=unconfined works around this, so yes indeed seccomp filter is one aspect. I'm working on updating Guix container images, I'm hopeful I got this resolved.

build.cc reads:

    /* Disable address space randomization for improved determinism. */
    ctx.persona |= ADDR_NO_RANDOMIZE;

Is that actually a good idea here? Couldn't build.cc gracefully back down and continue?

I haven't confirmed that this is the only thing causing the seccomp filter to trigger, maybe some of the other capability stuff trigger the error too.

I confirmed that invoking podman/buildah with `--security-opt seccomp=unconfined` works around this, so yes indeed seccomp filter is one aspect. I'm working on updating Guix container images, I'm hopeful I got this resolved. build.cc reads: ``` /* Disable address space randomization for improved determinism. */ ctx.persona |= ADDR_NO_RANDOMIZE; ``` Is that actually a good idea here? Couldn't build.cc gracefully back down and continue? I haven't confirmed that this is the only thing causing the seccomp filter to trigger, maybe some of the other capability stuff trigger the error too.
Contributor

This is now easy to reproduce:

jas@kaka:~$ podman run -it --rm registry.gitlab.com/debdistutils/guix/debian-with-guix-container:stable
root@44b959bbc0ac:/# LC_ALL=C.UTF-8 /root/.config/guix/current/bin/guix-daemon --build-users-group=guixbuild --disable-chroot &
[1] 2
root@44b959bbc0ac:/# guix install --verbosity=0 hello
accepted connection from pid 36, user root
guix install: warning: Consider running 'guix pull' followed by
'guix package -u' to get up-to-date packages and security updates.

The following package will be installed:
   hello 2.12.2

guix install: error: while setting up the child process: in phase setPersonality: cannot set personality: Operation not permitted
root@44b959bbc0ac:/# 
This is now easy to reproduce: ``` jas@kaka:~$ podman run -it --rm registry.gitlab.com/debdistutils/guix/debian-with-guix-container:stable root@44b959bbc0ac:/# LC_ALL=C.UTF-8 /root/.config/guix/current/bin/guix-daemon --build-users-group=guixbuild --disable-chroot & [1] 2 root@44b959bbc0ac:/# guix install --verbosity=0 hello accepted connection from pid 36, user root guix install: warning: Consider running 'guix pull' followed by 'guix package -u' to get up-to-date packages and security updates. The following package will be installed: hello 2.12.2 guix install: error: while setting up the child process: in phase setPersonality: cannot set personality: Operation not permitted root@44b959bbc0ac:/# ```
Owner

Hi @jas,

Thanks for testing this.

Couldn't build.cc gracefully back down and continue?

I have mixed feelings here. One one hand it sounds like the right thing to do: it would save headaches to people running guix-daemon in podman & co.

On the other hand, silently ignoring personality errors and similar errors that might occur while setting up the build environment would lead people to perform builds in degraded mode, with fewer reproducibility guarantees, without noticing

Granted, disabling ASLR is not the most important aspect of reproducible build environments, but it’s not negligible either and it all adds up.

Hi @jas, Thanks for testing this. > Couldn't build.cc gracefully back down and continue? I have mixed feelings here. One one hand it sounds like the right thing to do: it would save headaches to people running `guix-daemon` in podman & co. On the other hand, silently ignoring `personality` errors and similar errors that might occur while setting up the build environment would lead people to perform builds in degraded mode, with fewer reproducibility guarantees, without noticing Granted, disabling ASLR is not the most important aspect of reproducible build environments, but it’s not negligible either and it all adds up.
civodul added this to the 1.5.0 release milestone 2025-11-29 16:18:39 +01:00
Member

@civodul wrote in #3917 (comment):

On the other hand, silently ignoring personality errors and similar errors that might occur while setting up the build environment would lead people to perform builds in degraded mode, with fewer reproducibility guarantees, without noticing

Hi, I will have to do some studying in order to understand better the issue. But one thing that's not clear to me - can personality check give us something when chroot is disabled?

If yes, can we make a flag for disabling such checks for running in containers?

@civodul wrote in https://codeberg.org/guix/guix/issues/3917#issuecomment-8591634: > On the other hand, silently ignoring `personality` errors and similar errors that might occur while setting up the build environment would lead people to perform builds in degraded mode, with fewer reproducibility guarantees, without noticing Hi, I will have to do some studying in order to understand better the issue. But one thing that's not clear to me - can personality check give us something when chroot is disabled? If yes, can we make a flag for disabling such checks for running in containers?
Owner

@Rutherther Yes, this call to personality disables address space layout randomization (ASLR), thus removing one source of non-determinism, whether or not the build is being performed in a chroot.

Prior to be8aca0651, --disable-chroot would also skip the call to personality, but the two are not fundamentally related.

@Rutherther Yes, this call to `personality` disables address space layout randomization (ASLR), thus removing one source of non-determinism, whether or not the build is being performed in a chroot. Prior to be8aca065118aa4485c02f991c51bea89034defa, `--disable-chroot` would also skip the call to `personality`, but the two are not fundamentally related.
Contributor

Indeed this seems like a complex area. On one hand, I think the user should be able to control things, so maybe something like --security chroot,personality or similar? To override whatever the default logic is.

On the other hand, the default logic should be sensible. If some feature is unavailable, maybe it shouldn't downgrade by default? If the above parameter existed, then the user would be able to override things, if there is a need. It is only now that we don't have that parameter that we would like it to do the right thing by default. If we can tell it what to do, the defaults could be to demand all security features.

Indeed this seems like a complex area. On one hand, I think the user should be able to control things, so maybe something like `--security chroot,personality` or similar? To override whatever the default logic is. On the other hand, the default logic should be sensible. If some feature is unavailable, maybe it shouldn't downgrade by default? If the above parameter existed, then the user would be able to override things, if there is a need. It is only now that we don't have that parameter that we would like it to do the right thing by default. If we can tell it what to do, the defaults could be to demand all security features.
Sign in to join this conversation.
No milestone
No project
No assignees
5 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
guix/guix#3917
No description provided.