Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Running programs' command line arguments are not scanned for gc roots #3108

Open
chkno opened this issue Sep 26, 2019 · 3 comments

Comments

@chkno
Copy link
Contributor

@chkno chkno commented Sep 26, 2019

Running programs can reference other programs in their command line arguments. Garbage collection misses this link, and can collect things still referenced by the running system.

For example, I noticed this when my screen locker was garbage-collected. In NixOS, the services.xserver.xautolock service couples xautolock (the daemon with the timer) and xlockmore's xlock (the thing that prompts for a password) together only by command line argument -- xautolock is invoked as xautolock -locker /nix/store/...xlockmore/bin/xlock. When xlockmore/xlock is upgraded, there is no nix-visible reference to the old one referenced on the running xautolock's command line, and it becomes eligible for garbage collection. If the old xlockmore/xlock is garbage collected, screen locking stops working.

Looking through the list of running processes, agetty's --login-program argument, rdnssd's -H argument, and dhcp/dhclient's -sf argument all also reference a file from a different package on the command line in a way that they expect it to be available as long as they are running, and so may also be affected by this issue.

Concrete steps to reproduce this issue on NixOS with the screen locker:

  1. Add services.xserver.xautolock.enable = true; to /etc/nixos/configuration.nix
  2. nixos-rebuild switch
  3. Restart your X session, such as by logging out and logging back in.
  4. Note that this process is now running:
    /nix/store/0lf07v3wwbp6n4c57barhwc0iqkgrhmi-xautolock-2.2/bin/xautolock \
      -noclose \
      -time 15 \
      -locker /nix/store/r5c3wv4gj1rzldzj98hancbpjp2a9vzl-xlockmore-5.56/bin/xlock
  1. Remove services.xserver.xautolock.enable = true; from /etc/nixos/configuration.nix
  2. nixos-rebuild switch
  3. nix-collect-garbage -d

xlock has been deleted! xautolock is preserved because it is discovered as a gc root:

# nix-store --gc --print-roots | grep lock
{memory:2} -> /nix/store/0lf07v3wwbp6n4c57barhwc0iqkgrhmi-xautolock-2.2

(Of course, this can happen when xlock is upgraded as well. Removing the service is just an easier way to force the problem to happen immediately.)

LocalStore::findRuntimeRoots() in nix/src/libstore/gc.cc which grabs all process' /proc/%s/exe , etc. as gc roots should look through /proc/%s/cmdline as well.

Possibly it should also look through /proc/%s/environ?

@edolstra

This comment has been minimized.

Copy link
Member

@edolstra edolstra commented Sep 27, 2019

It already scans /proc/<pid>/environ. Scanning cmdline sounds like a good idea.

@zimbatm

This comment has been minimized.

Copy link
Member

@zimbatm zimbatm commented Sep 27, 2019

over here: https://github.com/tweag/nix/blob/98d684de5fc16f534fbc06a791d288aac31394c8/src/libstore/gc.cc#L426

It also looks at the /proc/<pid>/maps file. I wonder if the args are not supposed to be in there usually.

@edolstra

This comment has been minimized.

Copy link
Member

@edolstra edolstra commented Sep 27, 2019

No, /proc/<pid>/maps is just the memory mappings (dynamic libraries etc).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.