unofficial mirror of bug-guix@gnu.org 
 help / color / mirror / code / Atom feed
* bug#36508: GDM files have incorrect owner after temporarily replacing with SDDM
@ 2019-07-05  8:36 ison
  2021-04-13 13:24 ` bug#36508: GDM files have incorrect owner after temporarily removing service Brendan Tildesley via Bug reports for GNU Guix
  2022-09-18 12:22 ` bug#36508: [DRAFT PATCH] Stable allocation of uids, by keeping a historical mapping Maxime Devos
  0 siblings, 2 replies; 20+ messages in thread
From: ison @ 2019-07-05  8:36 UTC (permalink / raw)
  To: 36508

After replacing GDM with SDDM in my Guix System config (to test Wayland) and
then reverting back to my old config and reconfiguring GDM would crash
(printing out around 500 lines about creating a seat)
I also tried rolling back to the generation I had before using SDDM and it would
still crash.
In both instances I also tried "herd restart xorg-server" but same problem.

I then checked the log file /var/log/gdm/greeter.log which had errors such as:
-------------------
Fatal server error:
(EE) Cannot open log file "/var/lib/gdm/.local/share/xorg/Xorg.pid-720.log"
-------------------

And then I could verify that files inside of /var/lib/gdm had incorrect
ownership of 9##:gdm
where 9## was some 3-digit number I can't remember now.
(note: the directory itself /var/lib/gdm still had correct ownership gdm:gdm)

I then manually fixed the ownership with:
chown -R gdm:gdm /var/lib/gdm
and GDM successfully came up without crashing.

The relevant portion of my config when I replaced GDM with SDDM was:
-------------------------------
(operating-system
  ...
  (services
    (cons*
      ...
      (sddm-service
        (sddm-configuration
          (display-server "wayland")))

      ;; Return %desktop-services with GDM removed
      (remove (lambda (service)
                (eq? (service-kind service) gdm-service-type))
              %desktop-services))))
-------------------------------

^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2019-07-05  8:36 bug#36508: GDM files have incorrect owner after temporarily replacing with SDDM ison
@ 2021-04-13 13:24 ` Brendan Tildesley via Bug reports for GNU Guix
  2021-04-13 20:51   ` Mark H Weaver
  2022-09-18 12:22 ` bug#36508: [DRAFT PATCH] Stable allocation of uids, by keeping a historical mapping Maxime Devos
  1 sibling, 1 reply; 20+ messages in thread
From: Brendan Tildesley via Bug reports for GNU Guix @ 2021-04-13 13:24 UTC (permalink / raw)
  To: 36508@debbugs.gnu.org; +Cc: Ludovic Courtès


[-- Attachment #1.1: Type: text/plain, Size: 1054 bytes --]

I recently encountered what is likely the same bug. The directory /var/lib/gdm
had the correct permissions gdm:gdm, but all the files inside had something like
973:gdm

a43e9157ef479e94c19951cc9d228cf153bf78ee is supposed to fix this (duplicate bug
37423) but it only checks the permissions of /var/lib/gdm/ itself. Not all of
the files in it. This explains why in my case it failed to fix the permissions,
because the directory was gdm:gdm. How it got that way I don't know, and infact
it doesn't really matter. The directory is mutable, and thus can theoretically be
changed for any number of reasons. Therefore if we wish for Guix to be robust
with it's Functional design, and have meaningful rollbacks, we perhaps have no
choice but to assert the required invariants like these on mutable files.

A better solution may be to make it fully chown -R on reconfigure, but not each time
on boot?

I've attached an untested patch with a suggested solution of making
%gdm-activation operate every single time, instead of just after checking
/var/lib/gdm.



[-- Attachment #1.2: Type: text/html, Size: 1658 bytes --]

[-- Attachment #2: 0001-services-gdm-Correctly-set-ownership-on-var-lib-gdm.patch --]
[-- Type: text/x-patch, Size: 2015 bytes --]

From 31cb6dbd756af695bd6a1f4d4c89b42367b13307 Mon Sep 17 00:00:00 2001
From: Brendan Tildesley <mail@brendan.scot>
Date: Tue, 13 Apr 2021 23:04:28 +1000
Subject: [PATCH] services: gdm: Correctly set ownership on /var/lib/gdm.

* gnu/services/xorg.scm (%gdm-activation): Always chown /var/lib/gdm,
instead of only when it appears to be correct, because it's still
possible the files inside could be wrong and break GDM. I encountered
this once: https://issues.guix.gnu.org/36508 .

Perhaps it is with good intentions to try not running this code every
single time on boot, but when it fails, the consequence is that GDM can
break not just for the current revision, but all previous rollback
systems in GRUB will fail, and subsequent reconfigure-ings fail
too. That totally destroys a desktop system and our rollback
functionally, which is much much worse!
---
 gnu/services/xorg.scm | 15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/gnu/services/xorg.scm b/gnu/services/xorg.scm
index 17d983ff8d..a206c7c93a 100644
--- a/gnu/services/xorg.scm
+++ b/gnu/services/xorg.scm
@@ -861,16 +861,11 @@ the GNOME desktop environment.")
 
         (let* ((gdm (getpwnam "gdm"))
                (uid (passwd:uid gdm))
-               (gid (passwd:gid gdm))
-               (st  (stat "/var/lib/gdm" #f)))
-          ;; Recurse into /var/lib/gdm only if it has wrong ownership.
-          (when (and st
-                     (or (not (= uid (stat:uid st)))
-                         (not (= gid (stat:gid st)))))
-            (for-each (lambda (file)
-                        (chown file uid gid))
-                      (find-files "/var/lib/gdm"
-                                  #:directories? #t)))))))
+               (gid (passwd:gid gdm)))
+          (for-each (lambda (file)
+                      (chown file uid gid))
+                    (find-files "/var/lib/gdm"
+                                #:directories? #t))))))
 
 (define dbus-daemon-wrapper
   (program-file
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-13 13:24 ` bug#36508: GDM files have incorrect owner after temporarily removing service Brendan Tildesley via Bug reports for GNU Guix
@ 2021-04-13 20:51   ` Mark H Weaver
  2021-04-14  4:31     ` Brendan Tildesley via Bug reports for GNU Guix
  2021-04-14 10:32     ` Ludovic Courtès
  0 siblings, 2 replies; 20+ messages in thread
From: Mark H Weaver @ 2021-04-13 20:51 UTC (permalink / raw)
  To: Brendan Tildesley, 36508

Hi Brendan,

Brendan Tildesley via Bug reports for GNU Guix <bug-guix@gnu.org>
writes:

> I recently encountered what is likely the same bug. The directory /var/lib/gdm
> had the correct permissions gdm:gdm, but all the files inside had something like
> 973:gdm

The underlying problem here, which I've also experienced, is that if you
reconfigure your system with fewer users/groups, and then later add
those users/groups back, there is no guarantee that they will be
assigned the same UIDs and GIDs.

This problem is made much worse by the fact that files may be left
around, e.g. in /var, with the old UIDs and GIDs.

In your case, I guess that the 'gdm' user was previously assigned UID
973, but now it has been given a different UID.

In my case, after reconfiguring to a minimal system and later switching
back to a full GNOME-based desktop system, I found that many files and
directories in /var had the wrong owner or group.  Here's what I saw
before I cleaned things up:

--8<---------------cut here---------------start------------->8---
root@jojen ~# ls -l /var/lib/
total 4
drwxr-xr-x 1 colord colord    40 Mar 28  2017 colord
drwx------ 1 995    978       56 Sep  3 02:10 gdm
drwx------ 1 root   root   30400 Dec 25 01:55 NetworkManager
-rw------- 1 root   root     512 Dec 25 01:35 random-seed
drwxr-xr-x 1 colord colord   164 Dec 28  2017 sddm
drwx------ 1 tor    tor      178 Dec 19 21:28 tor
drwx------ 1 root   root      20 Sep  5 01:32 udisks2
drwxr-xr-x 1 root   root     274 Dec 25 01:55 upower
drwxr-xr-x 1 root   root      86 Mar 28  2017 wicd
root@jojen ~# ls -la /var/lib/gdm/
total 4
drwx------ 1  995    978  56 Sep  3 02:10 .
drwxr-xr-x 1 root root   750 Dec 25 01:59 ..
drwxr-xr-x 1  994 colord  64 Sep  3 02:10 .cache
drwx------ 1  994 colord  54 Sep  3 02:10 .config
-rw------- 1  994 colord  16 Sep  3 02:10 .esd_auth
drwxr-xr-x 1  994 colord  10 Sep  3 02:10 .local
root@jojen ~# 
--8<---------------cut here---------------end--------------->8---

Given the fact that existing files and directories in /var can
*effectively* have their ownership changed, I think that this issue
could be a security risk.

There's some discussion of this issue at <https://bugs.gnu.org/44944>,
although I'm not sure that Danny's suggested solution is practical.

Here's one idea: when activating a system, *never* delete users or
groups if files still exist that are owned by those users/groups.
Checking all filesystems would likely be too expensive, but perhaps it
would be sufficient to check certain directories such as /var, /etc, and
possibly the top directory of /home.

What do you think?

      Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-13 20:51   ` Mark H Weaver
@ 2021-04-14  4:31     ` Brendan Tildesley via Bug reports for GNU Guix
  2021-04-15 18:09       ` Mark H Weaver
  2021-04-14 10:32     ` Ludovic Courtès
  1 sibling, 1 reply; 20+ messages in thread
From: Brendan Tildesley via Bug reports for GNU Guix @ 2021-04-14  4:31 UTC (permalink / raw)
  To: 36508; +Cc: Mark H Weaver, Ludovic Courtès


> On 04/13/2021 10:51 PM Mark H Weaver <mhw@netris.org> wrote:
> 
>  
> Hi Brendan,
> 
> Brendan Tildesley via Bug reports for GNU Guix <bug-guix@gnu.org>
> writes:
> 
> > I recently encountered what is likely the same bug. The directory /var/lib/gdm
> > had the correct permissions gdm:gdm, but all the files inside had something like
> > 973:gdm
> 
> The underlying problem here, which I've also experienced, is that if you
> reconfigure your system with fewer users/groups, and then later add
> those users/groups back, there is no guarantee that they will be
> assigned the same UIDs and GIDs.
> 
> This problem is made much worse by the fact that files may be left
> around, e.g. in /var, with the old UIDs and GIDs.
> 
> In your case, I guess that the 'gdm' user was previously assigned UID
> 973, but now it has been given a different UID.
> 
> In my case, after reconfiguring to a minimal system and later switching
> back to a full GNOME-based desktop system, I found that many files and
> directories in /var had the wrong owner or group.  Here's what I saw
> before I cleaned things up:
> 
> --8<---------------cut here---------------start------------->8---
> root@jojen ~# ls -l /var/lib/
> total 4
> drwxr-xr-x 1 colord colord    40 Mar 28  2017 colord
> drwx------ 1 995    978       56 Sep  3 02:10 gdm
> drwx------ 1 root   root   30400 Dec 25 01:55 NetworkManager
> -rw------- 1 root   root     512 Dec 25 01:35 random-seed
> drwxr-xr-x 1 colord colord   164 Dec 28  2017 sddm
> drwx------ 1 tor    tor      178 Dec 19 21:28 tor
> drwx------ 1 root   root      20 Sep  5 01:32 udisks2
> drwxr-xr-x 1 root   root     274 Dec 25 01:55 upower
> drwxr-xr-x 1 root   root      86 Mar 28  2017 wicd
> root@jojen ~# ls -la /var/lib/gdm/
> total 4
> drwx------ 1  995    978  56 Sep  3 02:10 .
> drwxr-xr-x 1 root root   750 Dec 25 01:59 ..
> drwxr-xr-x 1  994 colord  64 Sep  3 02:10 .cache
> drwx------ 1  994 colord  54 Sep  3 02:10 .config
> -rw------- 1  994 colord  16 Sep  3 02:10 .esd_auth
> drwxr-xr-x 1  994 colord  10 Sep  3 02:10 .local
> root@jojen ~# 
> --8<---------------cut here---------------end--------------->8---
> 
> Given the fact that existing files and directories in /var can
> *effectively* have their ownership changed, I think that this issue
> could be a security risk.

Yes and they could change for any reason under the sun, and so we have no
choice but to set them right on service activation.

Guix system rollbacks should be a supported feature of Guix, not just a gimmick
that falls out of its design. It should be that a Guix user could leave their
system for 5 years, and then do a guix pull; guix system reconfigure in the year
2026. Perhaps at that time the new system will break, and then its desirable
that they can rollback to the previous generation. So what fixes we put in to 
Guix services today need to consider not just how files could have changed in
the past, but how they might change in breaking ways in the future, within reason.
I don't know off the top of my head of any way that can be done other than to
have chmod -R gdm:gdm /var/lib/gdm always executed.
> 
> There's some discussion of this issue at <https://bugs.gnu.org/44944>,
> although I'm not sure that Danny's suggested solution is practical.
> 
> Here's one idea: when activating a system, *never* delete users or
> groups if files still exist that are owned by those users/groups.
> Checking all filesystems would likely be too expensive, but perhaps it
> would be sufficient to check certain directories such as /var, /etc, and
> possibly the top directory of /home.
> 
> What do you think

Wouldn't that imply that uids could be randomly different on different systems
with the same configuration, and then remain statically different permanently?
We want as little randomness and moving parts as possible. It's yet another
way the system is not actually Functional, but has state.

Seems this bug spans 3 or so different bug reports. In http://issues.guix.gnu.org/45571
I commented that Nix uses hard coded id's, sorta like how ports are allocated
for a purpose:

https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/ids.nix

Perhaps you are thinking of other kinds of security issues that could be caused that
I'm not thinking of. In that case maybe Nix devs have already made the best choice by
making them static?

... After all, if the permissions can change, then it is possible another user could
actually modify the contents of /var/lib/gdm its self, thereby infecting other users,
if for some reason that other malicious user gets allocated that ID.
That further points towards static ID's like Nix has as a solution.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-13 20:51   ` Mark H Weaver
  2021-04-14  4:31     ` Brendan Tildesley via Bug reports for GNU Guix
@ 2021-04-14 10:32     ` Ludovic Courtès
  2021-04-14 12:21       ` Brendan Tildesley via Bug reports for GNU Guix
                         ` (3 more replies)
  1 sibling, 4 replies; 20+ messages in thread
From: Ludovic Courtès @ 2021-04-14 10:32 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: Brendan Tildesley, 36508

Hi Mark,

Mark H Weaver <mhw@netris.org> skribis:

> Brendan Tildesley via Bug reports for GNU Guix <bug-guix@gnu.org>
> writes:
>
>> I recently encountered what is likely the same bug. The directory /var/lib/gdm
>> had the correct permissions gdm:gdm, but all the files inside had something like
>> 973:gdm
>
> The underlying problem here, which I've also experienced, is that if you
> reconfigure your system with fewer users/groups, and then later add
> those users/groups back, there is no guarantee that they will be
> assigned the same UIDs and GIDs.

Yes.

The patch Brendan posted LGTM (though I’m surprised the directory itself
can have the right UID/GID while files inside it don’t; perhaps this was
made possible by 2161820ebbbab62a5ce76c9101ebaec54dc61586, which chowns
the home directory unconditionally.)

Note that there are other places, in addition to GDM, where we
forcefully reset the UID/GID of the home directory (e.g., for the
‘knot-resolver’ service.)

My preferred solution to this would be to unconditionally chown -R home
directories upon activation (for efficiency, it would be best if we
could do that if and only if the home directory itself has wrong
ownership).  Thoughts?

systemd-homed does something like that.  The intuition here is that
UIDs/GIDs are implementation details that should get out of the way.

> There's some discussion of this issue at <https://bugs.gnu.org/44944>,
> although I'm not sure that Danny's suggested solution is practical.
>
> Here's one idea: when activating a system, *never* delete users or
> groups if files still exist that are owned by those users/groups.
> Checking all filesystems would likely be too expensive, but perhaps it
> would be sufficient to check certain directories such as /var, /etc, and
> possibly the top directory of /home.

How would you determine which directories to look at though?  What if we
miss an important one?

Note that the ID allocation strategy in (gnu build accounts) ensures
UIDs/GIDs aren’t reused right away (same strategy as implemented by
Shadow, etc.).  So if you remove “bob”, then add “alice”, “alice” won’t
be able to access the left-behind /home/bob because it has a different
UID.

Ludo’.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-14 10:32     ` Ludovic Courtès
@ 2021-04-14 12:21       ` Brendan Tildesley via Bug reports for GNU Guix
  2021-04-15 14:24         ` Ludovic Courtès
  2021-04-15 18:30       ` Mark H Weaver
                         ` (2 subsequent siblings)
  3 siblings, 1 reply; 20+ messages in thread
From: Brendan Tildesley via Bug reports for GNU Guix @ 2021-04-14 12:21 UTC (permalink / raw)
  To: 36508; +Cc: Mark H Weaver, Ludovic Courtès


> On 04/14/2021 12:32 PM Ludovic Courtès <ludo@gnu.org> wrote:
> 
>  
> Hi Mark,
> 
> Mark H Weaver <mhw@netris.org> skribis:
> 
> > Brendan Tildesley via Bug reports for GNU Guix <bug-guix@gnu.org>
> > writes:
> >
> >> I recently encountered what is likely the same bug. The directory /var/lib/gdm
> >> had the correct permissions gdm:gdm, but all the files inside had something like
> >> 973:gdm
> >
> > The underlying problem here, which I've also experienced, is that if you
> > reconfigure your system with fewer users/groups, and then later add
> > those users/groups back, there is no guarantee that they will be
> > assigned the same UIDs and GIDs.
> 
> Yes.
> 
> The patch Brendan posted LGTM (though I’m surprised the directory itself
> can have the right UID/GID while files inside it don’t; perhaps this was
> made possible by 2161820ebbbab62a5ce76c9101ebaec54dc61586, which chowns
> the home directory unconditionally.)
> 
> Note that there are other places, in addition to GDM, where we
> forcefully reset the UID/GID of the home directory (e.g., for the
> ‘knot-resolver’ service.)
> 
> My preferred solution to this would be to unconditionally chown -R home
> directories upon activation (for efficiency, it would be best if we
> could do that if and only if the home directory itself has wrong
> ownership).  Thoughts?
> 
I'm confused. It sounds like you're suggesting to add the very IF condition that my
patch removes from %gdm-activation in order to fix the problem.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-14 12:21       ` Brendan Tildesley via Bug reports for GNU Guix
@ 2021-04-15 14:24         ` Ludovic Courtès
  0 siblings, 0 replies; 20+ messages in thread
From: Ludovic Courtès @ 2021-04-15 14:24 UTC (permalink / raw)
  To: Brendan Tildesley; +Cc: 36508

Hi,

Brendan Tildesley <btild@mailbox.org> skribis:

>> On 04/14/2021 12:32 PM Ludovic Courtès <ludo@gnu.org> wrote:

[...]

>> The patch Brendan posted LGTM (though I’m surprised the directory itself
>> can have the right UID/GID while files inside it don’t; perhaps this was
>> made possible by 2161820ebbbab62a5ce76c9101ebaec54dc61586, which chowns
>> the home directory unconditionally.)
>> 
>> Note that there are other places, in addition to GDM, where we
>> forcefully reset the UID/GID of the home directory (e.g., for the
>> ‘knot-resolver’ service.)
>> 
>> My preferred solution to this would be to unconditionally chown -R home
>> directories upon activation (for efficiency, it would be best if we
>> could do that if and only if the home directory itself has wrong
>> ownership).  Thoughts?
>> 
> I'm confused. It sounds like you're suggesting to add the very IF condition that my
> patch removes from %gdm-activation in order to fix the problem.

I’d like to understand why the ‘if’ the patch removes was problematic.
I think it relates to the commit above, but that needs more
investigation.

Ludo’.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-14  4:31     ` Brendan Tildesley via Bug reports for GNU Guix
@ 2021-04-15 18:09       ` Mark H Weaver
  0 siblings, 0 replies; 20+ messages in thread
From: Mark H Weaver @ 2021-04-15 18:09 UTC (permalink / raw)
  To: Brendan Tildesley, 36508

Hi Brendan,

Brendan Tildesley <btild@mailbox.org> writes:

> Guix system rollbacks should be a supported feature of Guix, not just a gimmick
> that falls out of its design. It should be that a Guix user could leave their
> system for 5 years, and then do a guix pull; guix system reconfigure in the year
> 2026. Perhaps at that time the new system will break, and then its desirable
> that they can rollback to the previous generation.

This sounds like a good set of goals to strive for.  I'm not sure that
Guix, on its own, will be able to achieve reliable 5-year rollback.  I
think that would require _all_ software in Guix that maintains mutable
state on disk to gracefully support downgrading to a version from 5
years earlier.

Nonetheless, Guix can certainly do its part to try to ensure that
multi-year rollbacks can work, and I agree that it's a good thing to
keep in mind.

> So what fixes we put in to 
> Guix services today need to consider not just how files could have changed in
> the past, but how they might change in breaking ways in the future, within reason.

It's a good thing to keep in mind, yes.

> I don't know off the top of my head of any way that can be done other than to
> have chmod -R gdm:gdm /var/lib/gdm always executed.

I'm not necessarily opposed to doing that, at least as a temporary
workaround for GDM, but I don't think this is a satisfactory solution to
the larger problem.  A few points:

(1) I don't think we can assume that all files owned by a given user
    will be in that user's home directory, especially for "system"
    users.

(2) I also don't think we can assume that all files in a user's home
    directory *should* be owned by that user.  Even if it's true today,
    it might not be true tomorrow.

(3) Groups don't even have home directories.

> On 04/13/2021 10:51 PM Mark H Weaver <mhw@netris.org> wrote:
>> 
>> There's some discussion of this issue at <https://bugs.gnu.org/44944>,
>> although I'm not sure that Danny's suggested solution is practical.
>> 
>> Here's one idea: when activating a system, *never* delete users or
>> groups if files still exist that are owned by those users/groups.
>> Checking all filesystems would likely be too expensive, but perhaps it
>> would be sufficient to check certain directories such as /var, /etc, and
>> possibly the top directory of /home.
>> 
>> What do you think
>
> Wouldn't that imply that uids could be randomly different on different systems
> with the same configuration, and then remain statically different permanently?

Yes, and I agree that it's suboptimal.

> We want as little randomness and moving parts as possible. It's yet another
> way the system is not actually Functional, but has state.

Agreed.  Danny's suggested solution (UID = hash username) is clearly the
optimal approach in many respects.  It has the nice properties above.

The practical problem I see with Danny's approach is that in order to
make hash collisions sufficiently improbable, our UIDs and GIDs would
need to be much larger than the 16 bits that is widely supported by
POSIX software.  With 16-bit UIDs, the probability of a collision would
be 1.85% with 50 users, and 7.28% with 100 users.

To adopt this approach, I think that our UIDs and GIDs would need to be
at least 31 bits.  These are the problems I see:

(1) It's unlikely that all software in Guix robustly handles such large
    UIDs/GIDs.  Desktop systems with UIDs/GIDs larger than 65533 have
    not been widely tested, as far as I know.

(2) Even with 31 bit IDs, the probability of collisions would still be
    uncomfortably high when large numbers of users are present: with 10k
    users, the probability of hash collisions would be about 2.3%.

(3) We'd need a transition plan for users' existing file systems.

(4) It would be aesthetically unpleasant for our UIDs and GIDs to be
    random-looking numbers with 10 decimal digits.

> Seems this bug spans 3 or so different bug reports. In http://issues.guix.gnu.org/45571
> I commented that Nix uses hard coded id's, sorta like how ports are allocated
> for a purpose:
>
> https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/misc/ids.nix
>
> Perhaps you are thinking of other kinds of security issues that could be caused that
> I'm not thinking of.

I'm not sure what you're getting at here.  The only security issue I've
raised so far is that ownership of files can _effectively_ be changed
when removing services and later adding them back.  For example, in my
case, 'colord' ended up being the owner of files in /var/lib/gdm.

> In that case maybe Nix devs have already made the best choice by
> making them static?

That might well be true.  At the present time, this is the option that
seems most appealing to me.

One possible approach would be to add a field to our 'operating-system'
record that explicitly specifies a total mapping from user/group names
to UIDs/GIDs.  It could either be a procedure (to support Danny's
hashing approach with its nice properties) or possibly also an alist for
convenience.  If any entries were missing, it would raise an error.

One risk to this approach is that users could accidentally make a mess
of their system if they made a mistake while changing that field.

What do you think?

    Thanks,
      Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-14 10:32     ` Ludovic Courtès
  2021-04-14 12:21       ` Brendan Tildesley via Bug reports for GNU Guix
@ 2021-04-15 18:30       ` Mark H Weaver
  2021-04-15 20:05         ` Ludovic Courtès
  2021-04-15 18:35       ` Mark H Weaver
  2021-04-15 18:58       ` Mark H Weaver
  3 siblings, 1 reply; 20+ messages in thread
From: Mark H Weaver @ 2021-04-15 18:30 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Brendan Tildesley, 36508

Ludovic Courtès <ludo@gnu.org> writes:

> Note that there are other places, in addition to GDM, where we
> forcefully reset the UID/GID of the home directory (e.g., for the
> ‘knot-resolver’ service.)
>
> My preferred solution to this would be to unconditionally chown -R home
> directories upon activation (for efficiency, it would be best if we
> could do that if and only if the home directory itself has wrong
> ownership).  Thoughts?

It might be okay to do this in specific cases like /var/lib/gdm, but I'm
very uncomfortable doing it for *all* users, because:

(1) We shouldn't assume that all files within a home directory are
    supposed to be owned by that user.

(2) We shouldn't assume that all files owned by a user will be within
    their home directory.

(3) We shouldn't assume that all files within a home directory are
    supposed to have the same 'group'.  I, for one, have sometimes had
    subdirectories of my home directory with a different 'group', to
    either restrict or grant other users access to selected files or
    directories.

(4) Groups do not, in general, have home directories.

(5) I consider it unsatifactory for there to be *any* window of time
    during system activation when the ownership of files is incorrect.

>> Here's one idea: when activating a system, *never* delete users or
>> groups if files still exist that are owned by those users/groups.
>> Checking all filesystems would likely be too expensive, but perhaps it
>> would be sufficient to check certain directories such as /var, /etc, and
>> possibly the top directory of /home.
>
> How would you determine which directories to look at though?  What if we
> miss an important one?

Yes, that's a good point.  I suppose that my idea above is not
satifactory either.

> Note that the ID allocation strategy in (gnu build accounts) ensures
> UIDs/GIDs aren’t reused right away (same strategy as implemented by
> Shadow, etc.).  So if you remove “bob”, then add “alice”, “alice” won’t
> be able to access the left-behind /home/bob because it has a different
> UID.

This mechanism is insufficient, because it only avoids the problem if
you add "alice" at the same time that "bob" is removed.  If you remove
"bob" during one system activation, and then later add "alice", then
"alice" might well be able to access bob's left-behind files.

In the case that I personally witnessed on my Guix system, files within
/var/lib/gdm ended up with 'colord' as their group.  That's not good.

Increasingly, I'm leaning toward the idea that the complete mapping from
names to IDs should somehow be explicitly given as part of the OS
configuration, as I advocated in <https://bugs.gnu.org/36508#26>.

What do you think?

     Thanks,
       Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-14 10:32     ` Ludovic Courtès
  2021-04-14 12:21       ` Brendan Tildesley via Bug reports for GNU Guix
  2021-04-15 18:30       ` Mark H Weaver
@ 2021-04-15 18:35       ` Mark H Weaver
  2021-04-15 18:58       ` Mark H Weaver
  3 siblings, 0 replies; 20+ messages in thread
From: Mark H Weaver @ 2021-04-15 18:35 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Brendan Tildesley, 36508

Ludovic Courtès <ludo@gnu.org> writes:
> My preferred solution to this would be to unconditionally chown -R home
> directories upon activation

I also wonder if this could lead to security flaws similar to
CVE-2021-27851 <https://bugs.gnu.org/47229>, but perhaps 'chown' has
been written carefully to avoid such problems.

       Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-14 10:32     ` Ludovic Courtès
                         ` (2 preceding siblings ...)
  2021-04-15 18:35       ` Mark H Weaver
@ 2021-04-15 18:58       ` Mark H Weaver
  2021-04-16 10:42         ` Maxime Devos
  3 siblings, 1 reply; 20+ messages in thread
From: Mark H Weaver @ 2021-04-15 18:58 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Brendan Tildesley, 36508

Ludovic Courtès <ludo@gnu.org> writes:

> Mark H Weaver <mhw@netris.org> skribis:
>
>> Here's one idea: when activating a system, *never* delete users or
>> groups if files still exist that are owned by those users/groups.
>> Checking all filesystems would likely be too expensive, but perhaps it
>> would be sufficient to check certain directories such as /var, /etc, and
>> possibly the top directory of /home.
>
> How would you determine which directories to look at though?  What if we
> miss an important one?

I have another idea:

Maintain historical mappings from user/group names to UIDs/GIDs, perhaps
in some file in /etc, where entries are added but *never* automatically
removed.  When allocating UIDs/GIDs, we would avoid any UIDs/GIDs in the
range of those mappings.

Then, provide a UID/GID garbage collector, to be explicitly run by users
if desired, which would scan all filesystems to find the set of UID/GIDs
currently referenced, and remove entries from the historical mappings
that are no longer needed.

What do you think?

      Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-15 18:30       ` Mark H Weaver
@ 2021-04-15 20:05         ` Ludovic Courtès
  2021-04-15 22:22           ` Mark H Weaver
  2021-04-15 23:04           ` Mark H Weaver
  0 siblings, 2 replies; 20+ messages in thread
From: Ludovic Courtès @ 2021-04-15 20:05 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: Brendan Tildesley, 36508

Hi Mark,

Mark H Weaver <mhw@netris.org> skribis:

> Ludovic Courtès <ludo@gnu.org> writes:
>
>> Note that there are other places, in addition to GDM, where we
>> forcefully reset the UID/GID of the home directory (e.g., for the
>> ‘knot-resolver’ service.)
>>
>> My preferred solution to this would be to unconditionally chown -R home
>> directories upon activation (for efficiency, it would be best if we
>> could do that if and only if the home directory itself has wrong
>> ownership).  Thoughts?
>
> It might be okay to do this in specific cases like /var/lib/gdm, but I'm
> very uncomfortable doing it for *all* users, because:
>
> (1) We shouldn't assume that all files within a home directory are
>     supposed to be owned by that user.
>
> (2) We shouldn't assume that all files owned by a user will be within
>     their home directory.
>
> (3) We shouldn't assume that all files within a home directory are
>     supposed to have the same 'group'.  I, for one, have sometimes had
>     subdirectories of my home directory with a different 'group', to
>     either restrict or grant other users access to selected files or
>     directories.
>
> (4) Groups do not, in general, have home directories.
>
> (5) I consider it unsatifactory for there to be *any* window of time
>     during system activation when the ownership of files is incorrect.

I agree this raises questions and we should take time to think through
it.  For system accounts though, I think 1–4 do not apply.

Perhaps a first step would be to do that for system accounts?

>> Note that the ID allocation strategy in (gnu build accounts) ensures
>> UIDs/GIDs aren’t reused right away (same strategy as implemented by
>> Shadow, etc.).  So if you remove “bob”, then add “alice”, “alice” won’t
>> be able to access the left-behind /home/bob because it has a different
>> UID.

To be clear, it’s doing the same as any other GNU/Linux distro.

> This mechanism is insufficient, because it only avoids the problem if
> you add "alice" at the same time that "bob" is removed.  If you remove
> "bob" during one system activation, and then later add "alice", then
> "alice" might well be able to access bob's left-behind files.
>
> In the case that I personally witnessed on my Guix system, files within
> /var/lib/gdm ended up with 'colord' as their group.  That's not good.
>
> Increasingly, I'm leaning toward the idea that the complete mapping from
> names to IDs should somehow be explicitly given as part of the OS
> configuration, as I advocated in <https://bugs.gnu.org/36508#26>.
>
> What do you think?

IDs as hash of the user names are interesting because that’d be
stateless (conversely, the current ID allocation strategy is stateful:
it arranges to not reuse recently-freed IDs.)

But like you write, we’d need 32-bit UIDs.  In libc, ‘uid_t’
(specifically ‘__UID_T_TYPE’ in typesizes.h) is 32-bit, so it might work
rather well in user space.

It still sounds like a change with significant implications though, and
it’s hard to predict exactly how it would go or what would break.  For
example, that does away with the system/non-system ranges, and wouldn’t
play well with “special” IDs like 0 and 65535.

To me, it’s a potential way out, but not a solution for the bug Brendan
reported today, nor a change we could implement in the coming
weeks/months; the time scale is probably longer.

WDYT?

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-15 20:05         ` Ludovic Courtès
@ 2021-04-15 22:22           ` Mark H Weaver
  2021-04-16 15:18             ` Ludovic Courtès
  2021-04-15 23:04           ` Mark H Weaver
  1 sibling, 1 reply; 20+ messages in thread
From: Mark H Weaver @ 2021-04-15 22:22 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Brendan Tildesley, 36508

Hi Ludovic,

Ludovic Courtès <ludo@gnu.org> wrote:
>>> Note that the ID allocation strategy in (gnu build accounts) ensures
>>> UIDs/GIDs aren’t reused right away (same strategy as implemented by
>>> Shadow, etc.).  So if you remove “bob”, then add “alice”, “alice” won’t
>>> be able to access the left-behind /home/bob because it has a different
>>> UID.

I replied:
>> This mechanism is insufficient, because it only avoids the problem if
>> you add "alice" at the same time that "bob" is removed.  If you remove
>> "bob" during one system activation, and then later add "alice", then
>> "alice" might well be able to access bob's left-behind files.

Ludovic Courtès <ludo@gnu.org> responded:
> To be clear, it’s doing the same as any other GNU/Linux distro.

I don't think that's quite right.

It's true that if you delete a user or group on another distro and then
re-add it, it might not be assigned the same UID/GID.  That much is the
same as any other distro.

The key difference is this: On Debian, at least in my experience, users
and groups are *never* deleted automatically.  They are only added
automatically, but never removed unless you explicitly ask to remove
them.  So, this problem does not arise in practice.

      Thanks,
        Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-15 20:05         ` Ludovic Courtès
  2021-04-15 22:22           ` Mark H Weaver
@ 2021-04-15 23:04           ` Mark H Weaver
  2021-04-16 15:14             ` Ludovic Courtès
  1 sibling, 1 reply; 20+ messages in thread
From: Mark H Weaver @ 2021-04-15 23:04 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Brendan Tildesley, 36508

Hi Ludovic,

Ludovic Courtès <ludo@gnu.org> writes:

> IDs as hash of the user names are interesting because that’d be
> stateless (conversely, the current ID allocation strategy is stateful:
> it arranges to not reuse recently-freed IDs.)
>
> But like you write, we’d need 32-bit UIDs.  In libc, ‘uid_t’
> (specifically ‘__UID_T_TYPE’ in typesizes.h) is 32-bit, so it might work
> rather well in user space.

The kernel and core system components certainly support 32-bit UIDs, and
have for around 20 years.

> It still sounds like a change with significant implications though, and
> it’s hard to predict exactly how it would go or what would break.

Right, my concern is with the vast majority of programs and libraries in
Guix, most of which probably haven't seen much (if any) testing with
large UIDs.

> For example, that does away with the system/non-system ranges, and
> wouldn’t play well with “special” IDs like 0 and 65535.

This particular issue is easily addressed.  It's easy enough to find a
function from 31-hash values to 32-bit IDs that's injective and avoids
any chosen subset of special IDs, as long as there are fewer than 2^31
special IDs.

Simply adding 65536 (or even 2^31) to the hash value would be one easy
option.

What do you think?

       Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-15 18:58       ` Mark H Weaver
@ 2021-04-16 10:42         ` Maxime Devos
  2021-04-17 16:28           ` Mark H Weaver
  0 siblings, 1 reply; 20+ messages in thread
From: Maxime Devos @ 2021-04-16 10:42 UTC (permalink / raw)
  To: Mark H Weaver, Ludovic Courtès; +Cc: Brendan Tildesley, 36508

[-- Attachment #1: Type: text/plain, Size: 2389 bytes --]

On Thu, 2021-04-15 at 14:58 -0400, Mark H Weaver wrote:
> Ludovic Courtès <ludo@gnu.org> writes:
> 
> > Mark H Weaver <mhw@netris.org> skribis:
> > 
> > > Here's one idea: when activating a system, *never* delete users or
> > > groups if files still exist that are owned by those users/groups.
> > > Checking all filesystems would likely be too expensive, but perhaps it
> > > would be sufficient to check certain directories such as /var, /etc, and
> > > possibly the top directory of /home.

And /tmp, /media and /run/user.

> > 
> > How would you determine which directories to look at though?  What if we
> > miss an important one?
> 
> I have another idea:
> 
> Maintain historical mappings from user/group names to UIDs/GIDs, perhaps
> in some file in /etc, where entries are added but *never* automatically
> removed.  When allocating UIDs/GIDs, we would avoid any UIDs/GIDs in the
> range of those mappings.

This seems rather convoluted to me.  Why not reuse /etc/passwd and /etc/groups?
My suggestion:

1. *never* automatically delete users/groups from /etc/passwd, /etc/groups
   (I thought that was how Guix already worked ...)
2. as users and groups appearing in /etc/passwd and /etc/groups, but not
   in the operating system configuration can be confusing, change the comment
   string of these users and groups, to something like

   "account removed"

   Add a group 'user-graveyard' for (3), and move these 'pseudo-removed' users
   to the 'user-graveyard' group.
3. Don't forget to remove graveyard users from all groups (except user-graveyard),
   make sure the graveyard users can't log in anymore ... (Perhaps add a rule to
   the SSH and PAM configuration that forbids logging in to graveyard accounts,
   by checking whether the user is in the 'user-graveyard' group?)

> Then, provide a UID/GID garbage collector, to be explicitly run by users
> if desired, which would scan all filesystems to find the set of UID/GIDs
> currently referenced, and remove entries from the historical mappings
> that are no longer needed.

That seems useful for if /etc/passwd and /etc/group is getting full, or just for
cleaning up.  You may want to exclude /gnu/store though, for efficiency (-:.
And just in case check whether any live processes have the UID/GID.

Suggested command name: "guix user-gc".

Greetings,
Maxime.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 260 bytes --]

^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-15 23:04           ` Mark H Weaver
@ 2021-04-16 15:14             ` Ludovic Courtès
  0 siblings, 0 replies; 20+ messages in thread
From: Ludovic Courtès @ 2021-04-16 15:14 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: Brendan Tildesley, 36508

Hi Mark,

Mark H Weaver <mhw@netris.org> skribis:

> This particular issue is easily addressed.  It's easy enough to find a
> function from 31-hash values to 32-bit IDs that's injective and avoids
> any chosen subset of special IDs, as long as there are fewer than 2^31
> special IDs.
>
> Simply adding 65536 (or even 2^31) to the hash value would be one easy
> option.
>
> What do you think?

Yes, but these special IDs are just examples of things that could go
wrong.  I don’t know, maybe I’m just overly cautious; we have to try to
get a better understanding of how things will go!

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-15 22:22           ` Mark H Weaver
@ 2021-04-16 15:18             ` Ludovic Courtès
  2021-04-17 16:16               ` Mark H Weaver
  0 siblings, 1 reply; 20+ messages in thread
From: Ludovic Courtès @ 2021-04-16 15:18 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: Brendan Tildesley, 36508

Hi,

Mark H Weaver <mhw@netris.org> skribis:

> It's true that if you delete a user or group on another distro and then
> re-add it, it might not be assigned the same UID/GID.  That much is the
> same as any other distro.
>
> The key difference is this: On Debian, at least in my experience, users
> and groups are *never* deleted automatically.  They are only added
> automatically, but never removed unless you explicitly ask to remove
> them.  So, this problem does not arise in practice.

>> Maintain historical mappings from user/group names to UIDs/GIDs, perhaps
>> in some file in /etc, where entries are added but *never* automatically
>> removed.  When allocating UIDs/GIDs, we would avoid any UIDs/GIDs in the
>> range of those mappings.

If we’re just worried about ID allocation, we could keep state in, say,
/etc/previous-uids, and feed that as input to the (gnu build accounts)
allocation code.

Thoughts?

Maxime Devos <maximedevos@telenet.be> skribis:

> This seems rather convoluted to me.  Why not reuse /etc/passwd and /etc/groups?
> My suggestion:
>
> 1. *never* automatically delete users/groups from /etc/passwd, /etc/groups
>    (I thought that was how Guix already worked ...)
> 2. as users and groups appearing in /etc/passwd and /etc/groups, but not
>    in the operating system configuration can be confusing, change the comment
>    string of these users and groups, to something like
>
>    "account removed"
>
>    Add a group 'user-graveyard' for (3), and move these 'pseudo-removed' users
>    to the 'user-graveyard' group.
> 3. Don't forget to remove graveyard users from all groups (except user-graveyard),
>    make sure the graveyard users can't log in anymore ... (Perhaps add a rule to
>    the SSH and PAM configuration that forbids logging in to graveyard accounts,
>    by checking whether the user is in the 'user-graveyard' group?)

Problem is that things like GDM would still propose those old accounts
(unless maybe their password is uninitialized, I’m not sure; but it’s
still hacky.)

Thanks,
Ludo’.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-16 15:18             ` Ludovic Courtès
@ 2021-04-17 16:16               ` Mark H Weaver
  0 siblings, 0 replies; 20+ messages in thread
From: Mark H Weaver @ 2021-04-17 16:16 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Brendan Tildesley, 36508

Hi Ludovic,

Ludovic Courtès <ludo@gnu.org> writes:

> Mark H Weaver <mhw@netris.org> skribis:
>
>>> Maintain historical mappings from user/group names to UIDs/GIDs, perhaps
>>> in some file in /etc, where entries are added but *never* automatically
>>> removed.  When allocating UIDs/GIDs, we would avoid any UIDs/GIDs in the
>>> range of those mappings.
>
> If we’re just worried about ID allocation, we could keep state in, say,
> /etc/previous-uids, and feed that as input to the (gnu build accounts)
> allocation code.

Sounds good to me, or at least better than the other available options.

     Thanks,
       Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: GDM files have incorrect owner after temporarily removing service
  2021-04-16 10:42         ` Maxime Devos
@ 2021-04-17 16:28           ` Mark H Weaver
  0 siblings, 0 replies; 20+ messages in thread
From: Mark H Weaver @ 2021-04-17 16:28 UTC (permalink / raw)
  To: Maxime Devos, Ludovic Courtès; +Cc: Brendan Tildesley, 36508

Hi Maxime,

Maxime Devos <maximedevos@telenet.be> writes:

> On Thu, 2021-04-15 at 14:58 -0400, Mark H Weaver wrote:
>> Maintain historical mappings from user/group names to UIDs/GIDs, perhaps
>> in some file in /etc, where entries are added but *never* automatically
>> removed.  When allocating UIDs/GIDs, we would avoid any UIDs/GIDs in the
>> range of those mappings.
>
> This seems rather convoluted to me.  Why not reuse /etc/passwd and /etc/groups?
> My suggestion:
>
> 1. *never* automatically delete users/groups from /etc/passwd, /etc/groups
>    (I thought that was how Guix already worked ...)
> 2. as users and groups appearing in /etc/passwd and /etc/groups, but not
>    in the operating system configuration can be confusing, change the comment
>    string of these users and groups, to something like
>
>    "account removed"
>
>    Add a group 'user-graveyard' for (3), and move these 'pseudo-removed' users
>    to the 'user-graveyard' group.
> 3. Don't forget to remove graveyard users from all groups (except user-graveyard),
>    make sure the graveyard users can't log in anymore ... (Perhaps add a rule to
>    the SSH and PAM configuration that forbids logging in to graveyard accounts,
>    by checking whether the user is in the 'user-graveyard' group?)

I would be okay with this approach as well, although it's not obvious to
me that it's any cleaner than having a separate /etc/previous-uids file,
given items 2 and 3 above.

>> Then, provide a UID/GID garbage collector, to be explicitly run by users
>> if desired, which would scan all filesystems to find the set of UID/GIDs
>> currently referenced, and remove entries from the historical mappings
>> that are no longer needed.
>
> That seems useful for if /etc/passwd and /etc/group is getting full, or just for
> cleaning up.  You may want to exclude /gnu/store though, for efficiency (-:.

Good point!  That's one directory that would clearly be a waste to scan :-)

> And just in case check whether any live processes have the UID/GID.

Sure, sounds good.

     Thanks!
       Mark




^ permalink raw reply	[flat|nested] 20+ messages in thread

* bug#36508: [DRAFT PATCH] Stable allocation of uids, by keeping a historical mapping.
  2019-07-05  8:36 bug#36508: GDM files have incorrect owner after temporarily replacing with SDDM ison
  2021-04-13 13:24 ` bug#36508: GDM files have incorrect owner after temporarily removing service Brendan Tildesley via Bug reports for GNU Guix
@ 2022-09-18 12:22 ` Maxime Devos
  1 sibling, 0 replies; 20+ messages in thread
From: Maxime Devos @ 2022-09-18 12:22 UTC (permalink / raw)
  To: 36508


[-- Attachment #1.1.1: Type: text/plain, Size: 1564 bytes --]

Hi,

The attached patch maintains a historical mapping from user names to 
UIDs/GIDs (even when those users are removed from the user accounts), to 
solve <https://issues.guix.gnu.org/36508>, as proposed by Mark H Weaver 
in <https://issues.guix.gnu.org/36508#10>.

(The proposed garbage collector is not included, however.)

As I proposed in <https://issues.guix.gnu.org/36508#14>, the information 
of this mapping is kept in a special 'user'.  However, I didn't 
implement the same for groups (raises some questions about atomicity -- 
/etc/passwd and /etc/groups are separate files).

I didn't completely follow that proposal though, since:

 > https://issues.guix.gnu.org/36508#16:
 > Problem is that things like GDM would still propose those old accounts
 > (unless maybe their password is uninitialized, I’m not sure; but it’s
 > still hacky.)

, though that could perhaps be solved by adjusting GDM appropriately.

"make check TESTS=tests/accounts.scm" passes, but otherwise the patch is 
rather untested (hence, 'DRAFT') -- the new functionality will need a 
few additional tests in tests/account.scm, to avoid introducing bugs in 
the handling of /etc/passwd.

On second thought, a separate /etc/previous-uids (as proposed in
<https://issues.guix.gnu.org/36508#16> by Ludovic Courtès)
might be better (there are atomicity issues anyway, due to /etc/passwd 
and /etc/groups being separate files, and losing the historical mapping
is relatively harmless and seems unlikely to happen in practice).

Greetings,
Maxime

[-- Attachment #1.1.2: 0001-DRAFT-Stable-allocation-of-uids.patch --]
[-- Type: text/x-patch, Size: 16012 bytes --]

From 1e0eb78fb7ae1a7b6c40e364d88b0b33945ef7c1 Mon Sep 17 00:00:00 2001
From: Maxime Devos <maximedevos@telenet.be>
Date: Sun, 18 Sep 2022 14:18:10 +0200
Subject: [PATCH] DRAFT: Stable allocation of uids

---
 gnu/build/accounts.scm | 186 +++++++++++++++++++++++++++++++++++------
 tests/accounts.scm     |  14 +++-
 2 files changed, 173 insertions(+), 27 deletions(-)

diff --git a/gnu/build/accounts.scm b/gnu/build/accounts.scm
index 1247fc640c..5e04e9f526 100644
--- a/gnu/build/accounts.scm
+++ b/gnu/build/accounts.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2019, 2021 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -17,9 +18,11 @@
 ;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.
 
 (define-module (gnu build accounts)
+  #:use-module (guix base64)
   #:use-module (guix records)
   #:use-module (guix combinators)
   #:use-module (gnu system accounts)
+  #:use-module (rnrs bytevectors)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-11)
   #:use-module (srfi srfi-19)
@@ -72,10 +75,16 @@ (define-module (gnu build accounts)
 ;;; <shadow.h>, <pwd.h>, and <grp.h> routines, as well as a subset of the
 ;;; functionality of the Shadow command-line tools.  It can parse and write
 ;;; /etc/passwd, /etc/shadow, and /etc/group.  It can also take care of UID
-;;; and GID allocation in a way similar to what 'useradd' does.
+;;; and GID allocation, in a different way than 'useradd' does.
 ;;;
-;;; The benefit is twofold: less code is involved, and the ID allocation
-;;; strategy and state preservation is made explicit.
+;;; The benefit is threefold: less code is involved, the ID allocation
+;;; strategy and state preservation is made explicit and it avoids
+;;; allocating IDs that were in the past allocated for some user user
+;;; and removed but still present somewhere in the file system.
+;;; Additionally, when such an user is re-added, Guix will use the same
+;;; ID again
+;;;
+;;; TODO: do the same 'keep old IDs' for groups as well.
 ;;;
 ;;; Code:
 
@@ -288,6 +297,85 @@ (define read-shadow
 (define read-group
   (database-reader "/etc/group" string->group-entry))
 
+(define (decode-guix-deleted-users encoded)
+  (alist->vhash (call-with-input-string
+                    (utf8->string (base64-decode encoded))
+                  read)))
+(define (encode-guix-deleted-users deleted-username->id)
+  (define (less this that)
+    (< (cdr this) (cdr that)))
+  (base64-encode
+   (string->utf8
+    (object->string
+     ;; Sort the mappings, to avoid hashing causing non-determinism.
+     (sort
+      (vhash-fold (lambda (username value accumulated)
+                    (unless (string? username)
+                      (error "username should be a string"))
+                    (unless (integer? value)
+                      (error "uid should be a string"))
+                    (cons (cons username value) accumulated))
+                  '()
+                  deleted-username->id)
+      less)))))
+
+(define (passwd-deleted passwd)
+  (define guix-deleted-users
+    ((lookup-procedure passwd password-entry-name)
+     "guix-deleted-users"))
+  (if guix-deleted-users
+      (decode-guix-deleted-users (password-entry-real-name guix-deleted-users))
+      vlist-null))
+
+(define (adjust-deleted-users current-passwd-entries new-passwd-entries
+                              current-deleted)
+  (define lookup-by-name/new
+    (lookup-procedure new-passwd-entries password-entry-name))
+  (define lookup-by-id/new
+    (lookup-procedure new-passwd-entries password-entry-uid))
+  (define lookup-by-id/old
+    (lookup-procedure current-passwd-entries password-entry-uid))
+  ;; Remove all usernames of 'current-deleted' that were allocated
+  ;; (in new-passwd-entries) and similarily, remove all IDs that were
+  ;; allocated.
+  (define current-deleted/filtered
+    (vhash-fold (lambda (username id accumulated)
+                  (if (or (lookup-by-name/new username)
+                          (lookup-by-id/new id))
+                      accumulated
+                      (vhash-cons username id accumulated)))
+                vlist-null
+                current-deleted))
+  (define (id-reused? username id)
+    ;; Was the ID used by a different username than USERNAME in
+    ;; CURRENT-PASSWD-ENTRIES?
+    (let ((old-password-entry (lookup-by-id/old id)))
+      (and old-password-entry (string=? (password-entry-name old-password-entry)
+                                        username))))
+  ;; Add usernames that are present in CURRENT-PASSWD-ENTRIES but
+  ;; not in NEW-PASSWD-ENTRIES, but only if the ID wasn't reused
+  ;; for some other user name.
+  (define new-deleted
+    (fold (lambda (username id accumulated)
+            (if (and (not (lookup-by-name/new username))
+                     (not (id-reused? username id)))
+                (vhash-cons username id accumulated)
+                accumulated))
+          current-deleted/filtered
+          current-passwd-entries))
+
+  (define (adjust password-entry* accumulated)
+    (cons (if (string=? (password-entry-name password-entry*) "guix-deleted-users")
+              (password-entry
+               (inherit password-entry*)
+               (real-name (encode-guix-deleted-users new-deleted)))
+              password-entry*)
+          accumulated))
+  ;; The 'reverse' is to preserve the order -- in theory, this should be
+  ;; unnecessary, but reverting the ordering of the entries in /etc/passwd
+  ;; after each reconfiguration would be surprising.
+  (fold adjust '() (reverse new-passwd-entries)))
+
 \f
 ;;;
 ;;; Building databases.
@@ -321,7 +409,8 @@ (define (user-id? id)
 
 (define* (allocate-id assignment #:key system?)
   "Return two values: a newly allocated ID, and an updated <allocation> record
-based on ASSIGNMENT.  If SYSTEM? is true, return a system ID."
+based on ASSIGNMENT.  If SYSTEM? is true, return a system ID.  This requires
+that no ID is allocated yet."
   (define next
     ;; Return the next available ID, looping if necessary.
     (if system?
@@ -441,20 +530,28 @@ (define previous-entry
           gids
           groups)))
 
-(define* (allocate-passwd users groups #:optional (current-passwd '()))
+(define* (allocate-passwd users groups #:optional (current-passwd '())
+                          (deleted-username->id vlist-null))
   "Return a list of password entries for USERS, a list of <user-account>.
 Take GIDs from GROUPS, a list of group entries.  Reuse UIDs from
-CURRENT-PASSWD, a list of password entries, when possible; otherwise allocate
-new UIDs."
+CURRENT-PASSWD, a list of password entries, or deleted-username->id,
+a vhash of usernames that were deleted in the previous /etc/passwd to IDs,
+when possible; otherwise allocate new UIDs."
   (define uids
-    (reserve-ids (reserve-ids (allocation)
-                              (map password-entry-uid current-passwd))
-                 (filter-map user-account-uid users)
-                 #:skip? #f))
-
-  (define previous-entry
+    (reserve-ids ; <-- TODO: is #:skip? #false needed here as well?
+     (reserve-ids (reserve-ids (allocation)
+                               (map password-entry-uid current-passwd))
+                  (filter-map user-account-uid users)
+                  #:skip? #f)
+     (vhash-fold (lambda (username id accumulated)
+                   (cons id accumulated)) '() deleted-username->id)))
+
+  (define previous-undeleted-entry
     (lookup-procedure current-passwd password-entry-name))
 
+  (define (previous-deleted-entry username)
+    (and=> (vhash-assoc username deleted-username->id) cdr))
+
   (define (group-id name)
     (or (any (lambda (entry)
                (and (string=? (group-entry-name entry) name)
@@ -471,17 +568,28 @@ (define (group-id name)
                   (directory    (user-account-home-directory user))
                   (shell        (user-account-shell user))
                   (system?      (user-account-system? user)))
-              (let*-values (((previous)
-                             (previous-entry name))
+              (let*-values (((previous-undeleted)
+                             (previous-undeleted-entry name))
+                            ((previous-deleted)
+                             (previous-deleted-entry name))
                             ((allocation id)
                              (cond
                               ((number? requested-id)
                                (values (reserve-ids allocation
                                                     (list requested-id))
                                        requested-id))
-                              (previous
+                              (previous-undeleted
                                (values allocation
-                                       (password-entry-uid previous)))
+                                       (password-entry-uid previous-undeleted)))
+                              ((and previous-deleted
+                                    (not (allocated? allocation previous-deleted)))
+                               ;; This deleted user might still have some files
+                               ;; in the file system, reuse the old id such
+                               ;; that it remains correct, unless some other
+                               ;; user has choosen that id.
+                               (values (reserve-ids allocation
+                                                    (list previous-deleted))
+                                       previous-deleted))
                               (else
                                (allocate-id allocation
                                             #:system? system?)))))
@@ -494,9 +602,10 @@ (define (group-id name)
                                ;; Users might change their name to something
                                ;; other than what the sysadmin chose, with
                                ;; 'chfn'.  Thus consider it "stateful".
-                               (real-name (if (and previous (not system?))
-                                              (password-entry-real-name previous)
-                                              real-name))
+                               (real-name
+                                (if (and previous-undeleted (not system?))
+                                    (password-entry-real-name previous-undeleted)
+                                    real-name))
 
                                ;; Do not reuse the shell of PREVIOUS since (1)
                                ;; that could lead to confusion, and (2) the
@@ -556,6 +665,25 @@ (define* (user+group-databases users groups
 entries, and the list of shadow entries corresponding to USERS and GROUPS.
 Preserve stateful bits from CURRENT-PASSWD, CURRENT-GROUPS, and
 CURRENT-SHADOW: UIDs, GIDs, passwords, user shells, etc."
+  (define users*
+    (if ((lookup-procedure users user-account-name)
+         "guix-deleted-users")
+        users
+        (append users
+                (list (user-account
+                       (name "guix-deleted-users")
+                       (group "guix-deleted-users")
+                       (home-directory "/var/empty")
+                       (system? #true))))))
+  (define groups*
+    (if ((lookup-procedure groups user-group-name)
+         "guix-deleted-users")
+        groups
+        (append groups
+                (list (user-group
+                       (name "guix-deleted-users")
+                       (system? #true))))))
+
   (define members
     ;; Map group name to user names.
     (fold (lambda (user members)
@@ -563,16 +691,24 @@ (define members
                   members
                   (user-account-supplementary-groups user)))
           vlist-null
-          users))
+          users*))
+
+  (define current-deleted (passwd-deleted current-passwd))
 
   (define group-entries
-    (allocate-groups groups members current-groups))
+    (allocate-groups groups* members current-groups))
 
   (define passwd-entries
-    (allocate-passwd users group-entries current-passwd))
+    (allocate-passwd users* group-entries current-passwd
+                     (passwd-deleted current-passwd)))
 
   (define shadow-entries
-    (passwd->shadow users passwd-entries current-shadow
+    (passwd->shadow users* passwd-entries current-shadow
                     #:current-time current-time))
 
-  (values group-entries passwd-entries shadow-entries))
+  ;; TODO: adjust new 'deleted'
+  (values group-entries (adjust-deleted-users
+                         current-passwd
+                         passwd-entries
+                         current-deleted)
+          shadow-entries))
diff --git a/tests/accounts.scm b/tests/accounts.scm
index 78136390bb..4e29bfe285 100644
--- a/tests/accounts.scm
+++ b/tests/accounts.scm
@@ -1,5 +1,6 @@
 ;;; GNU Guix --- Functional package management for GNU
 ;;; Copyright © 2019 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -272,7 +273,9 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd))
                            (members '("bob")))
               (group-entry (name "b") (gid (+ 1 %id-min))
                            (members '("alice")))
-              (group-entry (name "s") (gid %system-id-max)))
+              (group-entry (name "s") (gid %system-id-max))
+              (group-entry (name "guix-deleted-users")
+                           (gid (- %system-id-max 1))))
         (list (password-entry (name "alice") (real-name "Alice")
                               (uid %id-min) (gid %id-min)
                               (directory "/a"))
@@ -281,12 +284,19 @@ (define allocate-passwd (@@ (gnu build accounts) allocate-passwd))
                               (directory "/b"))
               (password-entry (name "nobody")
                               (uid 65534) (gid %system-id-max)
+                              (directory "/var/empty"))
+              (password-entry (name "guix-deleted-users")
+                              ;; empty list, start without deleted users
+                              (real-name "KCk=")
+                              (uid %system-id-max)
+                              (gid (- %system-id-max 1)) ; XXX: why not %system-id-max?  Bug or OK?
                               (directory "/var/empty")))
         (list (shadow-entry (name "alice") (last-change 100)
                             (password (crypt "initial pass" "$6$")))
               (shadow-entry (name "bob") (last-change 50)
                             (password (crypt "foo" "$6$")))
-              (shadow-entry (name "nobody") (last-change 100))))
+              (shadow-entry (name "nobody") (last-change 100))
+              (shadow-entry (name "guix-deleted-users") (last-change 100))))
   (call-with-values
       (lambda ()
         (user+group-databases (list (user-account

base-commit: 17f646aeba39f0d297f6c911d83b3bd9e88a227b
prerequisite-patch-id: 1f7c45cf2480f4e6f1e9563660e1b73a8682425e
prerequisite-patch-id: 0caac311875ee39cb48573657ebb960e90da6dfb
prerequisite-patch-id: 418285493d89ebf102175902d9b09a0174e88190
prerequisite-patch-id: 3c39eb839d9d3ff3fca6cd98621a5d5c411b7af4
prerequisite-patch-id: 8d5662e874c469f5ee496ef5181cf2d0a30ad1d8
prerequisite-patch-id: 26513c3b3b86963df718ee41d14a25d1cc6a8f3f
prerequisite-patch-id: 2b2497e2edec0afc48ebadd6f09f0c661c466127
prerequisite-patch-id: 2712efb97bf33985fd0658e4dd8e936dc08be5fe
prerequisite-patch-id: 9d2409b480a8bff0fef029b4b095922d4957e06f
prerequisite-patch-id: 51a32abca3efec1ba67ead59b8694c5ea3129ad3
prerequisite-patch-id: 7d55e3b39eb8803f058857d4412796b3f5dc0856
prerequisite-patch-id: 9092927761a340c07a99f5f3ed314a6add04cdee
prerequisite-patch-id: eafeeba1e6816dee3f8df671631bbeb5c373237a
-- 
2.37.3


[-- Attachment #1.1.3: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 929 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 236 bytes --]

^ permalink raw reply related	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2022-09-18 12:23 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-05  8:36 bug#36508: GDM files have incorrect owner after temporarily replacing with SDDM ison
2021-04-13 13:24 ` bug#36508: GDM files have incorrect owner after temporarily removing service Brendan Tildesley via Bug reports for GNU Guix
2021-04-13 20:51   ` Mark H Weaver
2021-04-14  4:31     ` Brendan Tildesley via Bug reports for GNU Guix
2021-04-15 18:09       ` Mark H Weaver
2021-04-14 10:32     ` Ludovic Courtès
2021-04-14 12:21       ` Brendan Tildesley via Bug reports for GNU Guix
2021-04-15 14:24         ` Ludovic Courtès
2021-04-15 18:30       ` Mark H Weaver
2021-04-15 20:05         ` Ludovic Courtès
2021-04-15 22:22           ` Mark H Weaver
2021-04-16 15:18             ` Ludovic Courtès
2021-04-17 16:16               ` Mark H Weaver
2021-04-15 23:04           ` Mark H Weaver
2021-04-16 15:14             ` Ludovic Courtès
2021-04-15 18:35       ` Mark H Weaver
2021-04-15 18:58       ` Mark H Weaver
2021-04-16 10:42         ` Maxime Devos
2021-04-17 16:28           ` Mark H Weaver
2022-09-18 12:22 ` bug#36508: [DRAFT PATCH] Stable allocation of uids, by keeping a historical mapping Maxime Devos

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).