On Mon, 10 Jul 2017, Lennart Poettering wrote:
On Thu, 06.07.17 09:36, Michael Chapman (m...@very.puzzling.org) wrote:
User=0day fails a syntactic validation, not a semantic validation. systemd
never even checks to see whether the user exists when the unit is loaded.
And nor should it! The user must be allowed to not exist at unit-load time.
Contrary to some of the comments in this thread, there is no point in
systemd's operation where it goes "oh look, that user actually exists but
I'm going to pretend it doesn't".
Well, that's where we disagree: POSIX allows you to create a user
named "1000" that maps to a UID "1001". I find it very hard to swallow
that people actually defend that as a good concept, and claim that
systemd was negatively impacting security here by refusing this and
other ambiguous mappings.
I do think that User=1000 should always be treated as a UID, regardless of
whether there's a "1000" username on the system or not.
We need to validate the input we get, that's security 101. And POSIX
is *not* a good standard to strictly follow here and use for
validating user names, because it's *very* underdefined:
- It permits fully numeric names
- It makes no size restrictions (strictly reading the spec even permits
zero-length usernames!)
- It permits dots, which is conflicting with traditional chown syntax
- It permits dots at the beginning of usernames (which is dangerous
security-wise as this permits users to hide home directories)
- It permits naming users "-", which is often used as special "does
not apply" like value
Now, because this is so weakly defined, we hence do not follow POSIX
rules, but filter out more that might be dangerous. Specifically:
1. We do not permit empty usernames
2. We don't permit the first character to be numeric
(This also filters out fully numeric user names)
3. We do not permit dots in usernames, neither at the beginning nor in
the middle.
4. We do not permit "-" at the beginning of usernames (something which
POSIX explicitly suggests, btw)
5. We require that the user name fits in the utmp user name field, so
that we can always log properly about it.
I think 1, 4 and 5 are good things.
For 2 and 3, however, I'm not so sure.
Note that this isn't even as strict as other systems go. For example,
we do permit uppercase characters, and we do permit underscores.
Are these random rules we came up here? Nope. This actually matches
the various requirements enforced by the regex strings used by various
distros in one way or another. Moreover, if you type "valid linux user
name characters" into google, among the top links you'll find stuff
like this:
https://stackoverflow.com/questions/6949667/what-are-the-real-rules-for-linux-usernames-on-centos-6-and-rhel-6
or this:
https://unix.stackexchange.com/questions/157426/what-is-the-regex-to-validate-linux-users
Which generally suggest similar rules.
Now, I do think that systemd has the duty to complain about any system
user names outside of the safe range. Not only for security reasons,
but also for portability and compatibility reasons: I think we should
ensure that unit files remain portable, and hence we should try to
filter out early stuff that's unlikely going to work outside of the
local scope.
I'm curious as to what you consider portability and compatibility here.
There are some "obviously bad" usernames, like the empty string. We should
definitely prevent these from being used, and I do hope we can get systemd
to complain noisily should somebody try to use them.
But there are less obviously bad usernames, because -- as you point out --
they're _actually in use already_. I myself already have systems with
usernames that begin with a digit; I don't want those systems to suddenly
break just because I update the Linux release to something that runs
systemd. (In practice they probably won't break, since I'm unlikely to
write system units for these users. But the principle of the matter
stands.)
For these "less obviously bad" usernames, I think we should just rely on
getpwnam() doing its own validation -- that is, in systemd's child process
when it's spawning commands. After all, getpwnam() may have any kinds of
restrictions due to the system's NSS config... or it may not. We're not in
any place to second-guess what its limitations are.
So long as _we_ never treat a User= value incorrectly (which we don't, we
decide whether a it's a UID, a username, or an invalid value very early
on) everything should just work fine.
Obviously we should be encouraging software vendors and distributors to
use nice usernames. The portability and compatibility comes from them. But
if a sysadmin wants to run one of their own services as User=0day I don't
think we should be getting in the way of that -- they should know what the
portability issues are with that, if any.
We should also not pretend all was good if other tools make less
careful restrictions and permit usernames that cause ambiguities. Yes,
a lot of software is very sloppy with validating input, and yes, some
adduser/useradd implementations allow you to create a user called
"1000", but I am very sure that their sloppiness should not leak into
our codebase.
Also, do note that system users are different concepts than regular
users: system users are concepts required for system services which
are usually put together by developers, packagers and administrators
who hopefully understand these issues to some point and pick good
names instead.
And of course, note that systemd is open source. if you don't like the
restrictions we make, you can patch them out (or even use some other
project). But again, I think it's our duty to help build a more secure
ecosystem (and we do that by validating our input, by running systemd
services in sandboxes and so on), and hence these restrictions really
need to stay.
Sorry, but I really can't see how forbidding usernames like "joe.hacker"
or "0day" improves security. As you said, they're perfectly valid
usernames. All of the libc functions that deal with usernames already
handle them correctly.
systemd is in the lucky position that it has so few dependencies. For
instance, we don't have to worry that the chown utility may misinterpret
"joe.hacker", since systemd never invokes the chown utility. It's not one
of systemd's dependencies.
(I do accept though that it's a valid discussion whether systemd's
current behaviour of warning and skipping invalid User= rvalues is the
best choice, instead of erroring out completely.)
Lennart
_______________________________________________
systemd-devel mailing list
systemd-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/systemd-devel