Commit Graph

1275 Commits

Author SHA1 Message Date
Alejandro Colomar
45f34ee8c1 Remove libcrack support
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-11-25 21:24:38 -06:00
Alejandro Colomar
43b4e5a6c4 Remove FascistHistory() and FascistHistoryPw() calls
These functions don't seem to exist anymore.  I can't find them in
Debian, nor in a web search.  They probably were functions from an
ancient implementation of cracklib that doesn't exist anymore.

$ git remote -v
origin	git@github.com:cracklib/cracklib.git (fetch)
origin	git@github.com:cracklib/cracklib.git (push)
$ grep -rni fascisthistory
$ git log --grep FascistHistory
$ git log -S FascistHistory

Closes: <https://codesearch.debian.net/search?q=FascistHistory&literal=1>
Cc: Mike Frysinger <vapier@gentoo.org>
Acked-by: Michael Vetter <jubalh@iodoru.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-11-25 21:24:38 -06:00
Alejandro Colomar
bbf1d9a800 src/logoutd.c: Fix theoretical buffer overrun
ut_line doesn't hold a string.  It is a null-padded fixed-width array.
Luckily, I don't think there has ever existed a ut_line ("/dev/tty*")
that was 32 bytes long.  That would have resulted in a buffer overrun.
Anyway, do the right thing, which is copying into a temporary string.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-11-22 12:58:17 +01:00
Alejandro Colomar
f9fb855889 src/, lib/, tests/: Rename files defining strtcpy()
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-11-22 12:55:26 +01:00
Alejandro Colomar
090c019ada src/, lib/, tests/: Rename STRLCPY() to STRTCPY()
It is a wrapper around STRTCPY(), so use a proper name.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-11-22 12:55:26 +01:00
Serge Hallyn
fa68441bc4 Improve the login.defs unknown item error message
Closes #746

Only print the 'unknown item' message to syslog if we are
actually parsing a login.defs.  Prefix it with "shadow:" to make
it clear in syslog where it came from.

Also add the source filename to the console message.  I'm not
quite clear on the econf API, so not sure whether in that path we
will end up actually having the path, or printing ''.

Signed-off-by: Serge Hallyn <serge@hallyn.com>
2023-10-20 18:46:23 -05:00
Alejandro Colomar
d5e1c1e475 lib/, src/: Use xasprintf() instead of its pattern
Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-10-20 21:05:33 +02:00
Alejandro Colomar
ad3b31a59e lib/, src/: Use asprintf(3) instead of strlen(3)+malloc(3)+snprintf(3)
asprintf(3) is non-standard, but is provided by GNU, the BSDs, and musl.
That makes it portable enough for us to use.

This function is much simpler than the burdensome code for allocating
the right size.  Being simpler, it's thus safer.

I took the opportunity to fix the style to my preferred one in the
definitions of variables used in these calls, and also in the calls to
free(3) with these pointers.  That isn't gratuituous, but has a reason:
it makes those appear in the diff for this patch, which helps review it.
Oh, well, I had an excuse :)

Reviewed-by: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-10-20 21:05:33 +02:00
Dimitri John Ledkov
088fe2618f Fix badname option to be singular just like useradd.
Badnames still accepted, note that previously usage already stated
singular form, whilst manpage and real one was plural only.

Fixes: 45d6746219 ("src: correct "badname" option")

Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
2023-10-16 12:45:21 -05:00
Dimitri John Ledkov
2e45fff44b Fix mixed-whitespace
Signed-off-by: Dimitri John Ledkov <dimitri.ledkov@canonical.com>
2023-10-16 12:45:21 -05:00
Johannes Segitz
48aa12af31 useradd: Set proper SELinux labels for def_usrtemplate
Fixes: 74c17c716 ("Add support for skeleton files from /usr/etc/skel")

Signed-off-by: Johannes Segitz <jsegitz@suse.com>
2023-10-03 09:24:47 +02:00
Christian Göttsche
247a869ccd faillog: check for overflows
Check for arithmetic overflows when computing offsets to avoid file
corruptions for huge UIDs.

Refactor the file lookup into a separate function.
2023-09-29 09:20:43 +02:00
Vasil Velichkov
bef4da47be groupadd: Improve error message when opening group file fails.
Both gr_open and sgr_open are using commonio_open function and when
there is a failure this function sets errno accordingly.
2023-09-04 16:04:42 +02:00
Alejandro Colomar
7c45a6e8ba lib/agetpass.h: Move prototypes to dedicated header
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-04 08:57:18 -05:00
Alejandro Colomar
e7a292ed4f Use bzero(3) instead of its pattern
It was blessed by POSIX.1-2001, and GCC says that it won't go away,
possibly ever.

memset(3) is dangerous, as the 2nd and 3rd arguments can be accidentally
swapped --who remembers what's the order of the 2nd and 3rd parameters
to memset(3) without checking the manual page or some code that uses
it?--.  Some recent compilers may be able to catch that via some
warnings, but those are not infalible.  And even if compiler warnings
could always catch that, the time lost in fixing or checking the docs is
lost for no clear gain.  Having a sane API that is unambiguous is the
Right Thing (tm); and that API is bzero(3).

If someone doesn't believe memset(3) is error-prone, please read the
book "Unix Network Programming", Volume 1, 3rd Edition by Stevens, et
al., Section 1.2.  See a stackoverflow reference in the link below[1].

bzero(3) had a bad fame in the bad old days, because some ancient
systems (I'm talking of many decades ago) shipped a broken version of
bzero(3).  We can assume that all systems in which current shadow utils
can be built, have a working version of bzero(3) --if not, please fix
your broken system; don't blame the programmer--.

One reason that some use today to avoid bzero(3) in favor of memset(3)
is that memset(3) is more often used; but that's a circular reasoning.
Even if bzero(3) wasn't supported by the system, it would need to be
invented.  It's the right API.

Another reason that some argue is that POSIX.1-2008 removed the
specification of bzero(3).  That's not a problem, because GCC will
probably support it forever, and even if it didn't, we can redefine it
like we do with memzero().  bzero(3) is just a one-liner wrapper around
memset(3).

Link: [1] <https://stackoverflow.com/a/17097978>
Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
24367027d6 Use STRLCPY() instead of its pattern
This makes it harder to make mistakes while editing the code.  Since the
sizeof's can be autocalculated, let the machine do that.  It also
reduces the cognitive load while reading the code.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
3029883888 passwd: Replace STRFCPY() by STRLCPY()
The variables are only being read as strings (char *), so data after the
'\0' can't be leaked.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
7bfcf1724c gpasswd: Replace STRFCPY() by STRLCPY()
The variable is only being read as a string (char *), so data after the
'\0' can't be leaked.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
fcc25a03cd login: Replace STRFCPY() by STRLCPY()
The variable is only being read as a string (char *), so data after the
'\0' can't be leaked.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
6dacb154e5 su: Replace STRFCPY() by STRLCPY()
The variables are only being read as strings (char *), so data after the
'\0' can't be leaked.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
3e0913f119 sulogin: Replace STRFCPY() by STRLCPY()
The variable is only being read as a string (char *), so data after the
'\0' can't be leaked.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
2ffc1a76f5 chsh: Replace STRFCPY() by STRLCPY()
The variables are only being read as strings (char *), so data after the
'\0' can't be leaked.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
8e33195c8e chfn: Replace STRFCPY() by STRLCPY()
The variables are only being read as strings (char *), so data after the
'\0' can't be leaked.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
5579b40e35 chage: Replace STRFCPY() by STRLCPY()
The variables are only being read as strings (char *), so data after the
'\0' can't be leaked.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
b1b5c46668 Use ZUSTR2STP() instead of its pattern
Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
02b1471d5b Call zustr2stp() where appropriate
These calls were intending to copy from a NUL-padded (possibly
non-NUL-terminated) character sequences contained in fixed-width arrays,
into a string, where extra padding is superfluous.  Use the appropriate
call, which removes the superfluous work.  That reduces the chance of
confusing maintainers about the intention of the code.

While at it, use the appropriate third parameter, which is the size of
the source buffer, and not the one of the destination buffer.  As a side
effect, this reduces the use of '-1', which itself reduces the chance of
off-by-one bugs.

Also, since using sizeof() on an array is dangerous, use SIZEOF_ARRAY().

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
f3ee47fe3f Use MEMZERO() instead of its pattern
This patch implicitly adds the safety of SIZEOF_ARRAY(), since the calls
were using sizeof() instead.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
328958ca01 sizeof.h: Move sizeof()-related macros to their own header
Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
6b11077f09 memzero.h: Move memzero() and strzero() to their own header
Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-09-01 09:39:23 +02:00
Alejandro Colomar
093fb605f9 lib: Merge libmisc into libshadow
The separation was unnecessary, and caused build problems.  Let's go
wild and obliterate the library.  The files are moved to libshadow.

Scripted change:

$ find libmisc/ -type f \
| grep '\.[chy]$' \
| xargs mv -t lib;

Plus updating the Makefile and other references.  While at it, I've
sorted the sources lists.

Link: <https://github.com/shadow-maint/shadow/pull/792>
Reported-by: David Seifert <soap@gentoo.org>
Cc: Sam James <sam@gentoo.org>
Cc: Christian Bricart <christian@bricart.de>
Cc: Michael Vetter <jubalh@iodoru.org>
Cc: Robert Förster <Dessa@gmake.de>
[ soap tested the Gentoo package ]
Tested-by: David Seifert <soap@gentoo.org>
Acked-by: David Seifert <soap@gentoo.org>
Acked-by: Serge Hallyn <serge@hallyn.com>
Acked-by: Iker Pedrosa <ipedrosa@redhat.com>
Acked-by: <lslebodn@fedoraproject.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-08-31 08:55:26 +02:00
Christian Göttsche
931e7c0c2f login: use strlcpy to always NUL terminate
login.c:728:25: warning: ‘strncpy’ specified bound 256 equals destination size [-Wstringop-truncation]

Reviewed-by: Alejandro Colomar <alx@kernel.org>
2023-08-21 14:05:18 -05:00
Christian Göttsche
856ffcfa5e Drop unnecessary cast to same type 2023-08-21 11:43:30 +02:00
Christian Göttsche
35edae5892 Declare usage and failure handler noreturn
Assist static analyzers in understanding final code paths.
2023-08-21 11:43:18 +02:00
Alejandro Colomar
f45498a6c2 libmisc/write_full.c: Improve write_full()
Documentation:

-  Correct the comment documenting the function:

   write_full() doesn't write "up to" count bytes (which is write(2)'s
   behavior, and exactly what this function is designed to avoid), but
   rather exactly count bytes (on success).

-  While fixing the documentation, take the time to add a man-page-like
   comment as in other APIs.  Especially, since we'll have to document
   a few other changes from this patch, such as the modified return
   values.

-  Partial writes are still possible on error.  It's the caller's
   responsibility to handle that possibility.

API:

-  In write(2), it's useful to know how many bytes were transferred,
   since it can have short writes.  In this API, since it either writes
   it all or fails, that value is useless, and callers only want to know
   if it succeeded or not.  Thus, just return 0 or -1.

Implementation:

-  Use `== -1` instead of `< 0` to check for write(2) syscall errors.
   This is wisdom from Michael Kerrisk.  This convention is useful
   because it more explicitly tells maintainers that the only value
   which can lead to that path is -1.  Otherwise, a maintainer of the
   code might be confused to think that other negative values are
   possible.  Keep it simple.

-  The path under `if (res == 0)` was unreachable, since the loop
   condition `while (count > 0)` precludes that possibility.  Remove the
   dead code.

-  Use a temporary variable of type `const char *` to avoid a cast.

-  Rename `res`, which just holds the result from write(2), to `w`,
   which more clearly shows that it's just a very-short-lived variable
   (by it's one-letter name), and also relates itself more to write(2).
   I find it more readable.

-  Move the definition of `w` to the top of the function.  Now that the
   function is significantly shorter, the lifetime of the variable is
   clearer, and I find it more readable this way.

Use:

-  Also use `== -1` to check errors.

Cc: Christian Göttsche <cgzones@googlemail.com>
Cc: Serge Hallyn <serge@hallyn.com>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-08-18 20:35:15 -05:00
Christian Göttsche
969549fdf0 Add wrapper for write(2)
write(2) may not write the complete given buffer.  Add a wrapper to
avoid short writes.
2023-08-04 17:15:42 -05:00
Iker Pedrosa
f2155fadf1 logoutd: add missing <utmp.h> include
Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-08-02 10:13:28 -05:00
Iker Pedrosa
50affc546f src: add SELINUX library
With the recent changes both login and su compilation fail because there
are some missing dependencies from SELINUX library. Thus, add LIBSELINUX
to su and login for those cases where the library is used.

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-08-02 10:13:28 -05:00
Iker Pedrosa
3b7cc05387 lib: replace USER_NAME_MAX_LENGTH macro
Replace it by `sysconf(_SC_LOGIN_NAME_MAX)`, which is the maximum
username length supported by the kernel.

Resolves: https://github.com/shadow-maint/shadow/issues/674

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-08-02 10:13:28 -05:00
Iker Pedrosa
1f368e1c18 utmp: update update_utmp()
Remove `utmp` structure as an argument and include its logic inside the
function. This will help remove any reference to utmp from login.

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-08-02 10:13:28 -05:00
Iker Pedrosa
6b7108e347 utmp: move update_utmp
The functionality from this function is related to utmp. Restrict access
to `setutmp()` to the same file.

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-08-02 10:13:28 -05:00
Michael Vetter
a692c880f1 chsh: warn if root sets a shell not listed in /etc/shells
Print a warning even for the root user if the provided shell isn't
listed in /etc/shells, but continue to execute the action.
In case of non root user exit.

See https://github.com/shadow-maint/shadow/issues/535
2023-07-27 12:35:27 -05:00
Vegard Nossum
9df4801e0b newgrp: fix potential string injection
Since newgrp is setuid-root, any write() system calls it does in order
to print error messages will be done as the root user.

Unprivileged users can get newgrp to print essentially arbitrary strings
to any open file in this way by passing those strings as argv[0] when
calling execve(). For example:

    $ setpid() { (exec -a $1$'\n:' newgrp '' 2>/proc/sys/kernel/ns_last_pid & wait) >/dev/null; }
    $ setpid 31000
    $ readlink /proc/self
    31001

This is not a vulnerability in newgrp; it is a bug in the Linux kernel.

However, this type of bug is not new [1] and it makes sense to try to
mitigate these types of bugs in userspace where possible.

[1]: https://lwn.net/Articles/476947/

Signed-off-by: Vegard Nossum <vegard.nossum@oracle.com>
2023-07-21 23:32:19 -05:00
Todd Zullinger
2643f27b36 lastlog: fix alignment of Latest header
b1282224 (Add maximum padding to fit IPv6-Addresses, 2020-05-24) pads
the From field header using `maxIPv6Addrlen - 3`.  This leaves the
Latest field header misaligned.  Subtract 4 (the length of "From").
2023-07-18 10:49:13 -05:00
Iker Pedrosa
03251ffbc0 usermod: conditionally build lastlog functionality
Resolves: https://github.com/shadow-maint/shadow/issues/674

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-07-15 07:39:53 -05:00
Iker Pedrosa
d60595d8f2 useradd: conditionally build lastlog functionality
Resolves: https://github.com/shadow-maint/shadow/issues/674

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-07-15 07:39:53 -05:00
Iker Pedrosa
84a10ca019 login: conditionally build lastlog functionality
Resolves: https://github.com/shadow-maint/shadow/issues/674

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-07-15 07:39:53 -05:00
Iker Pedrosa
1bdcfa8d37 lastlog: stop building by default
Created a new configuration option `--enable-lastlog` to conditionally
build the lastlog binary. By default the option is disabled.

Resolves: https://github.com/shadow-maint/shadow/issues/674

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
2023-07-15 07:39:53 -05:00
Bernd Kuhls
29da702491 Fix yescrypt support
Fixes build error:
newusers.c: In function 'update_passwd':
newusers.c:433:21: error: 'sflg' undeclared (first use in this function); did you mean 'rflg'?

introduced by
5cd04d03f9
which forgot to define sflg for these configure options:

--without-sha-crypt --without-bcrypt --with-yescrypt
2023-07-12 08:31:51 -05:00
Jeffrey Bencteux
53a17c1742 chgpasswd: fix segfault in command-line options
Using the --sha-rounds option without first giving a crypt method via the --crypt-method option results in comparisons with a NULL pointer and thus make chgpasswd segfault:

$ chgpasswd -s 1
zsh: segmentation fault  chgpasswd -s 1

Current patch add a sanity check before these comparisons to ensure there is a defined encryption method.
2023-06-22 14:51:34 -05:00
Alejandro Colomar
65c88a43a2 gpasswd(1): Fix password leak
How to trigger this password leak?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When gpasswd(1) asks for the new password, it asks twice (as is usual
for confirming the new password).  Each of those 2 password prompts
uses agetpass() to get the password.  If the second agetpass() fails,
the first password, which has been copied into the 'static' buffer
'pass' via STRFCPY(), wasn't being zeroed.

agetpass() is defined in <./libmisc/agetpass.c> (around line 91), and
can fail for any of the following reasons:

-  malloc(3) or readpassphrase(3) failure.

   These are going to be difficult to trigger.  Maybe getting the system
   to the limits of memory utilization at that exact point, so that the
   next malloc(3) gets ENOMEM, and possibly even the OOM is triggered.
   About readpassphrase(3), ENFILE and EINTR seem the only plausible
   ones, and EINTR probably requires privilege or being the same user;
   but I wouldn't discard ENFILE so easily, if a process starts opening
   files.

-  The password is longer than PASS_MAX.

   The is plausible with physical access.  However, at that point, a
   keylogger will be a much simpler attack.

And, the attacker must be able to know when the second password is being
introduced, which is not going to be easy.

How to read the password after the leak?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Provoking the leak yourself at the right point by entering a very long
password is easy, and inspecting the process stack at that point should
be doable.  Try to find some consistent patterns.

Then, search for those patterns in free memory, right after the victim
leaks their password.

Once you get the leak, a program should read all the free memory
searching for patterns that gpasswd(1) leaves nearby the leaked
password.

On 6/10/23 03:14, Seth Arnold wrote:
> An attacker process wouldn't be able to use malloc(3) for this task.
> There's a handful of tools available for userspace to allocate memory:
>
> -  brk / sbrk
> -  mmap MAP_ANONYMOUS
> -  mmap /dev/zero
> -  mmap some other file
> -  shm_open
> -  shmget
>
> Most of these return only pages of zeros to a process.  Using mmap of an
> existing file, you can get some of the contents of the file demand-loaded
> into the memory space on the first use.
>
> The MAP_UNINITIALIZED flag only works if the kernel was compiled with
> CONFIG_MMAP_ALLOW_UNINITIALIZED.  This is rare.
>
> malloc(3) doesn't zero memory, to our collective frustration, but all the
> garbage in the allocations is from previous allocations in the current
> process.  It isn't leftover from other processes.
>
> The avenues available for reading the memory:
> -  /dev/mem and /dev/kmem (requires root, not available with Secure Boot)
> -  /proc/pid/mem (requires ptrace privileges, mediated by YAMA)
> -  ptrace (requires ptrace privileges, mediated by YAMA)
> -  causing memory to be swapped to disk, and then inspecting the swap
>
> These all require a certain amount of privileges.

How to fix it?
~~~~~~~~~~~~~~

memzero(), which internally calls explicit_bzero(3), or whatever
alternative the system provides with a slightly different name, will
make sure that the buffer is zeroed in memory, and optimizations are not
allowed to impede this zeroing.

This is not really 100% effective, since compilers may place copies of
the string somewhere hidden in the stack.  Those copies won't get zeroed
by explicit_bzero(3).  However, that's arguably a compiler bug, since
compilers should make everything possible to avoid optimizing strings
that are later passed to explicit_bzero(3).  But we all know that
sometimes it's impossible to have perfect knowledge in the compiler, so
this is plausible.  Nevertheless, there's nothing we can do against such
issues, except minimizing the time such passwords are stored in plain
text.

Security concerns
~~~~~~~~~~~~~~~~~

We believe this isn't easy to exploit.  Nevertheless, and since the fix
is trivial, this fix should probably be applied soon, and backported to
all supported distributions, to prevent someone else having more
imagination than us to find a way.

Affected versions
~~~~~~~~~~~~~~~~~

All.  Bug introduced in shadow 19990709.  That's the second commit in
the git history.

Fixes: 45c6603cc8 ("[svn-upgrade] Integrating new upstream version, shadow (19990709)")
Reported-by: Alejandro Colomar <alx@kernel.org>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Iker Pedrosa <ipedrosa@redhat.com>
Cc: Seth Arnold <seth.arnold@canonical.com>
Cc: Christian Brauner <christian@brauner.io>
Cc: Balint Reczey <rbalint@debian.org>
Cc: Sam James <sam@gentoo.org>
Cc: David Runge <dvzrv@archlinux.org>
Cc: Andreas Jaeger <aj@suse.de>
Cc: <~hallyn/shadow@lists.sr.ht>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-06-10 20:35:50 -05:00