nss-systemd: ensure returned strings point into provided buffer
authorMichael Catanzaro <mcatanzaro@redhat.com>
Wed, 8 Sep 2021 21:51:16 +0000 (16:51 -0500)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 12 Oct 2021 15:57:37 +0000 (17:57 +0200)
commit5e44156893515e031491346f7cac960c9317ccd0
treedc2c71e8e3e47757df23e8a4c9852d6064008f72
parentfd864f9df70662a636bee5307d85a2762b8f236f
nss-systemd: ensure returned strings point into provided buffer

Jamie Bainbridge found an issue where glib's g_get_user_database_entry()
may crash after doing:

```
error = getpwnam_r (logname, &pwd, buffer, bufsize, &pw);
// ...
pw->pw_name[0] = g_ascii_toupper (pw->pw_name[0]);
```

in order to uppercase the first letter of the user's real name. This is
a glib bug, because there is a different codepath that gets the pwd from
vanilla getpwnam instead of getpwnam_r as shown here. When the pwd
struct is returned by getpwnam, its fields point to static data owned by
glibc/NSS, and so it must not be modified by the caller. After much
debugging, Jamie Bainbridge has fixed this in https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2244
by making a copy of the data before modifying it, and that resolves all
problems for glib. Yay!

However, glib is crashing even when getpwnam_r is used instead of
getpwnam! According to getpwnam_r(3), the strings in the pwd struct are
supposed to be pointers into the buffer passed by the caller, so glib
should be able to safely edit it directly in this case, so long as it
doesn't try to increase the size of any of the strings.

Problem is various functions throughout nss-systemd.c return synthesized
records declared at the top of the file. These records are returned
directly and so contain pointers to static strings owned by
libsystemd-nss. systemd must instead copy all the strings into the
provided buffer.

This crash is reproducible if nss-systemd is listed first on the passwd
line in /etc/nsswitch.conf, and the application looks up one of the
synthesized user accounts "root" or "nobody", and finally the
application attempts to edit one of the strings in the returned struct.
All our synthesized records for the other struct types have the same
problem, so this commit fixes them all at once.

Fixes #20679

(cherry picked from commit 47fd7fa6c650d7a0ac41bc89747e3b866ffb9534)
(cherry picked from commit 055ba736e12255cf79acc81aac382344129d03c5)
src/nss-systemd/nss-systemd.c