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

Reply via email to