Discussion:
Github systemd issue 6237
(too old to reply)
Alexander Bisogiannis
2017-07-04 16:59:23 UTC
Permalink
Raw Message
Hi all,

https://github.com/systemd/systemd/issues/6237

Apologies for asking here, but since the discussion is locked in Github I
thought to ask here.

This was marked as "not a bug", but in later comments the wording suggests
that systemd behaviour will change and if the username in a unit does not
exist systemd will ignore the unit, instead of running it as root.

My question is:

Is this a bug with a BZ against rhel/centos7 (as my understanding is that
this affects EL7 too)?

If there is no BZ and based on the wording of the second to last comment
by poettering, will this be fixed/changed in a future update?

I personally see this as a security issue and thus as a bug.

Again, apologies for asking here, but I cannot comment in the github
discussion due to the thread being locked to maintainers only.

Regards,
Abis.
Zbigniew Jędrzejewski-Szmek
2017-07-04 17:21:01 UTC
Permalink
Raw Message
Post by Alexander Bisogiannis
Hi all,
https://github.com/systemd/systemd/issues/6237
Apologies for asking here, but since the discussion is locked in Github I
thought to ask here.
This was marked as "not a bug", but in later comments the wording suggests
that systemd behaviour will change
No, there's nothing to suggest that in the comments.
It *might* change, but the comments do not say that.
Post by Alexander Bisogiannis
and if the username in a unit does not
exist systemd will ignore the unit, instead of running it as root.
Is this a bug with a BZ against rhel/centos7 (as my understanding is that
this affects EL7 too)?
If there is no BZ and based on the wording of the second to last comment
by poettering, will this be fixed/changed in a future update?
I personally see this as a security issue and thus as a bug.
If you need root permissions to create a unit, then it's not a
security issue. An annoyance at most.
(You do know that you're not supposed to copy&paste random stuff
from the internet as root, right?)
Post by Alexander Bisogiannis
Again, apologies for asking here, but I cannot comment in the github
discussion due to the thread being locked to maintainers only.
Yes, it's locked because of uninformative comments.

Zbyszek
Reindl Harald
2017-07-04 17:36:02 UTC
Permalink
Raw Message
Post by Zbigniew Jędrzejewski-Szmek
Post by Alexander Bisogiannis
Is this a bug with a BZ against rhel/centos7 (as my understanding is that
this affects EL7 too)?
If there is no BZ and based on the wording of the second to last comment
by poettering, will this be fixed/changed in a future update?
I personally see this as a security issue and thus as a bug.
If you need root permissions to create a unit, then it's not a
security issue. An annoyance at most.
(You do know that you're not supposed to copy&paste random stuff
from the internet as root, right?)
no - when there is a "User=" statement in the unitfile it's a strong
reason to refuse start that unit if that user don't exist instead
silently fall back to root and casting "0day" to a int 0 is just a
sloppy implementation with no good reason

frankly even PHP makes difference here

if($bla == "0day")
versus
if($bla === "0day")

the latter won't evaluate to 0 in no case
Zbigniew Jędrzejewski-Szmek
2017-07-04 18:39:15 UTC
Permalink
Raw Message
Post by Reindl Harald
Post by Zbigniew Jędrzejewski-Szmek
Post by Alexander Bisogiannis
Is this a bug with a BZ against rhel/centos7 (as my understanding is that
this affects EL7 too)?
If there is no BZ and based on the wording of the second to last comment
by poettering, will this be fixed/changed in a future update?
I personally see this as a security issue and thus as a bug.
If you need root permissions to create a unit, then it's not a
security issue. An annoyance at most.
(You do know that you're not supposed to copy&paste random stuff
from the internet as root, right?)
no - when there is a "User=" statement in the unitfile it's a strong
reason to refuse start that unit if that user don't exist instead
silently fall back to root and casting "0day" to a int 0 is just a
sloppy implementation with no good reason
It doesn't evaluate "0day" as 0 or cast anything, it (as designed)
finds that "0day" is not match the pattern for a valid user name and
rejects the whole line.

Essentially, User=0day is the same as Usre=0day and the same as User="my name is pretty!".

I do agree that we might want to completely reject unit files when
some crucial lines fail to parse, for example ExecStart or
WorkingDirectory or User, but it's not as obvious as one would think
at first.

When new configuration options are added, the same unit file can
almost always be used with older systemd, and it'll just warn & ignore
the parts it doesn't understand. Similarly, various configuration
options might be unavailable on some architectures and with some
compilation options. The current behaviour of warn&ignore provides
for "soft degradation" in those cases.

To do this properly, we would need to figure out which options are
a) important enough, b) supported on all compilation variants and
architectures, and then add a generic mechanism to make errors in
them fatal.

Zbyszek
Reindl Harald
2017-07-04 18:50:22 UTC
Permalink
Raw Message
Post by Zbigniew Jędrzejewski-Szmek
Post by Reindl Harald
Post by Zbigniew Jędrzejewski-Szmek
Post by Alexander Bisogiannis
Is this a bug with a BZ against rhel/centos7 (as my understanding is that
this affects EL7 too)?
If there is no BZ and based on the wording of the second to last comment
by poettering, will this be fixed/changed in a future update?
I personally see this as a security issue and thus as a bug.
If you need root permissions to create a unit, then it's not a
security issue. An annoyance at most.
(You do know that you're not supposed to copy&paste random stuff
from the internet as root, right?)
no - when there is a "User=" statement in the unitfile it's a strong
reason to refuse start that unit if that user don't exist instead
silently fall back to root and casting "0day" to a int 0 is just a
sloppy implementation with no good reason
It doesn't evaluate "0day" as 0 or cast anything, it (as designed)
finds that "0day" is not match the pattern for a valid user name and
rejects the whole line.
and this is simply *not true* until on each and every system you can't
create a user with that name, as long it is not rejected it is valid and
systemd is hardly the authoritiy to redefine it
Post by Zbigniew Jędrzejewski-Szmek
Essentially, User=0day is the same as Usre=0day and the same as User="my name is pretty!".
which is terrible
Post by Zbigniew Jędrzejewski-Szmek
I do agree that we might want to completely reject unit files when
some crucial lines fail to parse, for example ExecStart or
WorkingDirectory or User, but it's not as obvious as one would think
at first.
yes
Post by Zbigniew Jędrzejewski-Szmek
When new configuration options are added, the same unit file can
almost always be used with older systemd, and it'll just warn & ignore
the parts it doesn't understand. Similarly, various configuration
options might be unavailable on some architectures and with some
compilation options. The current behaviour of warn&ignore provides
for "soft degradation" in those cases.
frankly a new option on the left side is a completly different thing
than a invalid value - just silently continue with invalid values of
existing options is playing a danergous game in a crucial component like
systemd
Post by Zbigniew Jędrzejewski-Szmek
To do this properly, we would need to figure out which options are
a) important enough, b) supported on all compilation variants and
architectures, and then add a generic mechanism to make errors in
them fatal
when the value on the right side is invalid you have to fail with a
clear error message instead fire up something with undefined behavior,
in general but especially when it comes to security relevant things
Colin Guthrie
2017-07-05 08:52:35 UTC
Permalink
Raw Message
Post by Reindl Harald
Post by Zbigniew Jędrzejewski-Szmek
When new configuration options are added, the same unit file can
almost always be used with older systemd, and it'll just warn & ignore
the parts it doesn't understand. Similarly, various configuration
options might be unavailable on some architectures and with some
compilation options. The current behaviour of warn&ignore provides
for "soft degradation" in those cases.
frankly a new option on the left side is a completly different thing
than a invalid value - just silently continue with invalid values of
existing options is playing a danergous game in a crucial component like
systemd
It's a rare thing :p but I have to agree with you here!

I'd say if "User=-notauser" then silently failing and using root is
acceptable as per the usual semantics of "- prefix suppresses errors",
but "User=notauser" should fail IMO.

Col
--
Colin Guthrie
colin(at)mageia.org
http://colin.guthr.ie/

Day Job:
Tribalogic Limited http://www.tribalogic.net/
Open Source:
Mageia Contributor http://www.mageia.org/
PulseAudio Hacker http://www.pulseaudio.org/
Trac Hacker http://trac.edgewall.org/
Michael Chapman
2017-07-05 10:10:15 UTC
Permalink
Raw Message
Post by Colin Guthrie
Post by Reindl Harald
Post by Zbigniew Jędrzejewski-Szmek
When new configuration options are added, the same unit file can
almost always be used with older systemd, and it'll just warn & ignore
the parts it doesn't understand. Similarly, various configuration
options might be unavailable on some architectures and with some
compilation options. The current behaviour of warn&ignore provides
for "soft degradation" in those cases.
frankly a new option on the left side is a completly different thing
than a invalid value - just silently continue with invalid values of
existing options is playing a danergous game in a crucial component like
systemd
It's a rare thing :p but I have to agree with you here!
I'd say if "User=-notauser" then silently failing and using root is
acceptable as per the usual semantics of "- prefix suppresses errors",
but "User=notauser" should fail IMO.
I'm pretty sure you'll find that it does. Specifically, it will fail when
the child process for the command being executed attempts to map the
username to a UID.

The issue being discussed here is that systemd considers "0day" to be
_syntactically_ invalid for a username. See the valid_user_group_name()
function in basic/user-util.c.

(In my opinion, we shouldn't be this restrictive. POSIX permits usernames
that start with a digit, and just because certain other utilities can't
deal with them doesn't mean systemd need forbid them.)

So the directive fails the syntactic check for User=, just like
Zbigniew's example of User="my name is pretty!".

I do think we ought to have a list of "critical" directives, such that any
syntactic error in those directives causes the unit load state to be
"error". For better or worse, people simply don't look at logs, so
they'll never notice that important directives in their units are being
ignored.
Reindl Harald
2017-07-05 10:17:33 UTC
Permalink
Raw Message
Post by Michael Chapman
Post by Colin Guthrie
Post by Reindl Harald
Post by Zbigniew Jędrzejewski-Szmek
When new configuration options are added, the same unit file can
almost always be used with older systemd, and it'll just warn & ignore
the parts it doesn't understand. Similarly, various configuration
options might be unavailable on some architectures and with some
compilation options. The current behaviour of warn&ignore provides
for "soft degradation" in those cases.
frankly a new option on the left side is a completly different thing
than a invalid value - just silently continue with invalid values of
existing options is playing a danergous game in a crucial component like
systemd
It's a rare thing :p but I have to agree with you here!
I'd say if "User=-notauser" then silently failing and using root is
acceptable as per the usual semantics of "- prefix suppresses errors",
but "User=notauser" should fail IMO.
I'm pretty sure you'll find that it does. Specifically, it will fail
when the child process for the command being executed attempts to map
the username to a UID.
The issue being discussed here is that systemd considers "0day" to be
_syntactically_ invalid for a username. See the valid_user_group_name()
function in basic/user-util.c.
yes and hence it should FAIL the service and not behave silently like
the left side of a param is unknown on a older version - a invalid VALUE
in a config has to fail until it's makred with a dash to silent be
ignored in case of errors
Post by Michael Chapman
(In my opinion, we shouldn't be this restrictive. POSIX permits
usernames that start with a digit, and just because certain other
utilities can't deal with them doesn't mean systemd need forbid them.)
that whole check is by all respect nonsense - if the user *exists* in
the system you can't pretend it's invalid - if it would be invalid it
could not have been created to begin with
Post by Michael Chapman
So the directive fails the syntactic check for User=, just like
Zbigniew's example of User="my name is pretty!".
I do think we ought to have a list of "critical" directives, such that
any syntactic error in those directives causes the unit load state to be
"error". For better or worse, people simply don't look at logs, so
they'll never notice that important directives in their units are being
ignored
and that is the problem - at least fall back to "nobody" but for the
sake of god not to root
Michael Chapman
2017-07-05 10:32:42 UTC
Permalink
Raw Message
Post by Michael Chapman
Post by Colin Guthrie
Post by Reindl Harald
Post by Zbigniew Jędrzejewski-Szmek
When new configuration options are added, the same unit file can
almost always be used with older systemd, and it'll just warn & ignore
the parts it doesn't understand. Similarly, various configuration
options might be unavailable on some architectures and with some
compilation options. The current behaviour of warn&ignore provides
for "soft degradation" in those cases.
frankly a new option on the left side is a completly different thing
than a invalid value - just silently continue with invalid values of
existing options is playing a danergous game in a crucial component like
systemd
It's a rare thing :p but I have to agree with you here!
I'd say if "User=-notauser" then silently failing and using root is
acceptable as per the usual semantics of "- prefix suppresses errors",
but "User=notauser" should fail IMO.
I'm pretty sure you'll find that it does. Specifically, it will fail when
the child process for the command being executed attempts to map the
username to a UID.
The issue being discussed here is that systemd considers "0day" to be
_syntactically_ invalid for a username. See the valid_user_group_name()
function in basic/user-util.c.
yes and hence it should FAIL the service and not behave silently like the
left side of a param is unknown on a older version - a invalid VALUE in a
config has to fail until it's makred with a dash to silent be ignored in case
of errors
That's really not what the dash means.

In the various Exec*= directives, a dash means that the command is allowed
to fail. Similarly, in WorkingDirectory= the dash means the directory need
not exist.

I do not believe there are any cases where a dash is used to side-step
_syntactic_ validation, nor do I think there should be.

Really, you should just think of the dashes as being part of the syntax
for the directives that support them.

As far as directives like User= go, there _may_ be a use for dash to mean
"do not change UIDs if the username turns out to not actually exist"...
but I would strongly advise against it.
Reindl Harald
2017-07-05 10:38:24 UTC
Permalink
Raw Message
Post by Michael Chapman
Post by Reindl Harald
Post by Michael Chapman
The issue being discussed here is that systemd considers "0day" to be
_syntactically_ invalid for a username. See the valid_user_group_name()
function in basic/user-util.c.
yes and hence it should FAIL the service and not behave silently like
the left side of a param is unknown on a older version - a invalid
VALUE in a config has to fail until it's makred with a dash to silent
be ignored in case of errors
That's really not what the dash means.
In the various Exec*= directives, a dash means that the command is
allowed to fail. Similarly, in WorkingDirectory= the dash means the
directory need not exist.
I do not believe there are any cases where a dash is used to side-step
_syntactic_ validation, nor do I think there should be.
Really, you should just think of the dashes as being part of the syntax
for the directives that support them.
As far as directives like User= go, there _may_ be a use for dash to
mean "do not change UIDs if the username turns out to not actually
exist"... but I would strongly advise against it
better than silently ignore a directive and run code as root which was
never intended to run as root because of questionable "we know better
what is valid then the underlying system which allowed to create that
user" - do it proper or fail but not start code as root and pretend you
are right

such issues closed as "not a bug" as well as
https://github.com/systemd/systemd/issues/5644 with comments like "Yeah,
it's a UNIX pitfall, but "rm -rf /foo/.*" will work the exact same way,
no?" which is not true for years make me afraid because it is a "to
begin with we are always right" attitude
Jonathan de Boyne Pollard
2017-07-05 18:34:46 UTC
Permalink
Raw Message
Post by Reindl Harald
at least fall back to "nobody"
That idea is wrong.

https://news.ycombinator.com/item?id=14681377#14682059
Reindl Harald
2017-07-05 22:49:30 UTC
Permalink
Raw Message
Post by Jonathan de Boyne Pollard
Post by Reindl Harald
at least fall back to "nobody"
That idea is wrong.
https://news.ycombinator.com/item?id=14681377#14682059
better than a stupid "i fall back to root because i think i make the
rules and not the underlying operating system where this user in fact
exists"
Jonathan de Boyne Pollard
2017-07-06 07:59:52 UTC
Permalink
Raw Message
at least fall back to “nobody”
That idea is wrong.
https://news.ycombinator.com/item?id=14681377#14682059
better than a stupid [...]
Not really, no. It's the same category of error, in fact: substituting an
account other than the one that the system administrator explicitly said to drop
privileges to.
Reindl Harald
2017-07-06 08:34:48 UTC
Permalink
Raw Message
Post by Jonathan de Boyne Pollard
at least fall back to “nobody”
That idea is wrong.
https://news.ycombinator.com/item?id=14681377#14682059
better than a stupid [...]
Not really, no. It's the same category of error, in fact: substituting
an account other than the one that the system administrator explicitly
said to drop privileges to.
yes, it's both nonsense, but when i only have the option to choose
between two types of nonsense i take the one which don't give root
permissions
Lennart Poettering
2017-07-10 10:55:27 UTC
Permalink
Raw Message
Post by Jonathan de Boyne Pollard
at least fall back to “nobody”
That idea is wrong.
https://news.ycombinator.com/item?id=14681377#14682059
better than a stupid [...]
Not really, no. It's the same category of error, in fact: substituting
an account other than the one that the system administrator explicitly
said to drop privileges to.
yes, it's both nonsense, but when i only have the option to choose between
two types of nonsense i take the one which don't give root permissions
The "nobody" user has special semantics on Linux: it's where things
are mapped to that can't be mapped otherwise. It's used by user
namspacing, by NFS and others. It's really not a good idea, to permit
random services to create and access files under that ID.

Lennart
--
Lennart Poettering, Red Hat
Reindl Harald
2017-07-10 10:57:03 UTC
Permalink
Raw Message
Post by Lennart Poettering
Post by Jonathan de Boyne Pollard
at least fall back to “nobody”
That idea is wrong.
https://news.ycombinator.com/item?id=14681377#14682059
better than a stupid [...]
Not really, no. It's the same category of error, in fact: substituting
an account other than the one that the system administrator explicitly
said to drop privileges to.
yes, it's both nonsense, but when i only have the option to choose between
two types of nonsense i take the one which don't give root permissions
The "nobody" user has special semantics on Linux: it's where things
are mapped to that can't be mapped otherwise. It's used by user
namspacing, by NFS and others. It's really not a good idea, to permit
random services to create and access files under that ID
and run it as root is a better idea?
seriously?
Oliver Neukum
2017-07-10 13:59:01 UTC
Permalink
Raw Message
Post by Reindl Harald
Post by Lennart Poettering
The "nobody" user has special semantics on Linux: it's where things
are mapped to that can't be mapped otherwise. It's used by user
namspacing, by NFS and others. It's really not a good idea, to permit
random services to create and access files under that ID
and run it as root is a better idea?
seriously?
This is moot. If you specify a user that is considered wrong for whatever
reason the service must fail. Whether we disagree about who decide what is
a valid user name also does not matter. You cannot substitute users for
any reason.

Regards
Oliver
Oliver Neukum
2017-07-06 06:53:02 UTC
Permalink
Raw Message
Post by Michael Chapman
I'm pretty sure you'll find that it does. Specifically, it will fail when
the child process for the command being executed attempts to map the
username to a UID.
The issue being discussed here is that systemd considers "0day" to be
_syntactically_ invalid for a username. See the valid_user_group_name()
function in basic/user-util.c.
What a valid username is, is defined in POSIX. If systemd wants
to support only a subset of those, fair enough, but then it must
totally fail anything that uses such a name. Falling back to
another user is not acceptable. It being root is especially bad.

Regards
Oliver
Zbigniew Jędrzejewski-Szmek
2017-07-06 18:10:44 UTC
Permalink
Raw Message
Post by Michael Chapman
Post by Colin Guthrie
Post by Reindl Harald
Post by Zbigniew Jędrzejewski-Szmek
When new configuration options are added, the same unit file can
almost always be used with older systemd, and it'll just warn & ignore
the parts it doesn't understand. Similarly, various configuration
options might be unavailable on some architectures and with some
compilation options. The current behaviour of warn&ignore provides
for "soft degradation" in those cases.
frankly a new option on the left side is a completly different thing
than a invalid value - just silently continue with invalid values of
existing options is playing a danergous game in a crucial component like
systemd
It's a rare thing :p but I have to agree with you here!
I'd say if "User=-notauser" then silently failing and using root is
acceptable as per the usual semantics of "- prefix suppresses errors",
but "User=notauser" should fail IMO.
I'm pretty sure you'll find that it does. Specifically, it will fail
when the child process for the command being executed attempts to
map the username to a UID.
The issue being discussed here is that systemd considers "0day" to
be _syntactically_ invalid for a username. See the
valid_user_group_name() function in basic/user-util.c.
(In my opinion, we shouldn't be this restrictive. POSIX permits
usernames that start with a digit, and just because certain other
utilities can't deal with them doesn't mean systemd need forbid
them.)
So the directive fails the syntactic check for User=, just like
Zbigniew's example of User="my name is pretty!".
I do think we ought to have a list of "critical" directives, such
that any syntactic error in those directives causes the unit load
state to be "error". For better or worse, people simply don't look
at logs, so they'll never notice that important directives in their
units are being ignored.
https://github.com/systemd/systemd/pull/6300

Zbyszek
Felipe Sateler
2017-07-05 14:45:41 UTC
Permalink
Raw Message
Post by Zbigniew Jędrzejewski-Szmek
Essentially, User=0day is the same as Usre=0day and the same as User="my name is pretty!".
I think this is the root of the disagreement. Systemd tries to allow
units written for version X to run on versions earlier than X. I think
that is a good idea, and I don't think anyone is claiming it isn't. Which
is why invalid lvalues should be warned about but ignored, and I don't
think anyone is disputing this.

OTOH, invalid rvalues are a different thing: systemd recognizes the
setting it is trying to apply, but it can't. I think the argument that
systemd should fail the unit here is strong. Or at least for a certain
subset of the settings.
Post by Zbigniew Jędrzejewski-Szmek
I do agree that we might want to completely reject unit files when some
crucial lines fail to parse, for example ExecStart or WorkingDirectory
or User, but it's not as obvious as one would think at first.
Indeed. Marking invalid rvalues as failing the unit does bring backwards-
compatibility issues. Suppose systemd X+1 adds a new @ shortcut for
SystemCallFilter: should systemd X fail a unit that uses it? The problem
would be the same as with User=0day, as the service would run with higher
privileges than expected.

A possibility would be to make systemd have its preemptive validations[1]
be fatal. Setting `User=idontexist` would then be equal to `User=whoa!`,
because neither of the usernames (should) exist.

[1] That is, validations for things it does not control itself. systemd
does not control the username format, the uid range, allowed directories,
etc, but rather validates against an external standard. That is, assume
that things that don't validate would fail at application time with a non-
ignorable EINVAL. This is different from things it defines itself, such
as @ settings for SystemCallFilter.
--
Saludos,
Felipe Sateler
Michael Chapman
2017-07-05 23:36:55 UTC
Permalink
Raw Message
Post by Felipe Sateler
Post by Zbigniew Jędrzejewski-Szmek
Essentially, User=0day is the same as Usre=0day and the same as User="my
name is pretty!".
I think this is the root of the disagreement. Systemd tries to allow
units written for version X to run on versions earlier than X. I think
that is a good idea, and I don't think anyone is claiming it isn't. Which
is why invalid lvalues should be warned about but ignored, and I don't
think anyone is disputing this.
OTOH, invalid rvalues are a different thing: systemd recognizes the
setting it is trying to apply, but it can't. I think the argument that
systemd should fail the unit here is strong. Or at least for a certain
subset of the settings.
Post by Zbigniew Jędrzejewski-Szmek
I do agree that we might want to completely reject unit files when some
crucial lines fail to parse, for example ExecStart or WorkingDirectory
or User, but it's not as obvious as one would think at first.
Indeed. Marking invalid rvalues as failing the unit does bring backwards-
SystemCallFilter: should systemd X fail a unit that uses it? The problem
would be the same as with User=0day, as the service would run with higher
privileges than expected.
A possibility would be to make systemd have its preemptive validations[1]
be fatal. Setting `User=idontexist` would then be equal to `User=whoa!`,
because neither of the usernames (should) exist.
[1] That is, validations for things it does not control itself. systemd
does not control the username format, the uid range, allowed directories,
etc, but rather validates against an external standard. That is, assume
that things that don't validate would fail at application time with a non-
ignorable EINVAL. This is different from things it defines itself, such
Note that the semantic validations you're talking about here -- things
like "does the user exist?" -- are _not_ preemptive. They are fatal: the
child process will exit unsuccessfully as the command is executed if the
settings will not be able to be applied.

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".
Reindl Harald
2017-07-05 23:43:32 UTC
Permalink
Raw Message
Post by Michael Chapman
Note that the semantic validations you're talking about here -- things
like "does the user exist?" -- are _not_ preemptive. They are fatal: the
child process will exit unsuccessfully as the command is executed if the
settings will not be able to be applied.
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, it even don't look but pretend it can't while it does which is the
worst type of operations possible - as long as "adduser" of the
underlying OS accepts and create "0pointer" systemd has *no business at
all* to pretend it can't
Zbigniew Jędrzejewski-Szmek
2017-07-06 02:52:54 UTC
Permalink
Raw Message
Post by Reindl Harald
Post by Michael Chapman
Note that the semantic validations you're talking about here --
things like "does the user exist?" -- are _not_ preemptive. They
are fatal: the child process will exit unsuccessfully as the
command is executed if the settings will not be able to be
applied.
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, it even don't look but pretend it can't while it does which is
the worst type of operations possible - as long as "adduser" of the
underlying OS accepts and create "0pointer" systemd has *no business
at all* to pretend it can't
Then it's good the that it doesn't ;)

# adduser 0pointer

adduser: Please enter a username matching the regular expression configured
via the NAME_REGEX configuration variable. Use the `--force-badname'
option to relax this check or reconfigure NAME_REGEX.

Zbyszek
Michael Chapman
2017-07-06 03:21:03 UTC
Permalink
Raw Message
Post by Zbigniew Jędrzejewski-Szmek
Post by Reindl Harald
well, it even don't look but pretend it can't while it does which is
the worst type of operations possible - as long as "adduser" of the
underlying OS accepts and create "0pointer" systemd has *no business
at all* to pretend it can't
Then it's good the that it doesn't ;)
# adduser 0pointer
adduser: Please enter a username matching the regular expression configured
via the NAME_REGEX configuration variable. Use the `--force-badname'
option to relax this check or reconfigure NAME_REGEX.
I know you really only brought this up to counter Reindl's comment, but I
think it's important to point out that adduser's behaviour here is due to
its default configuration -- not due to any fundamental "problems" with
particular usernames. It's not clear why adduser's developers thought it
was a good default.

I guess what I'm saying is that saying "systemd should not support
usernames that start with a digit, since adduser doesn't" is problematic
for at least two reasons. First, adduser can be reconfigured by the
sysadmin to allow such usernames; and second, systemd places *fewer*
restrictions on usernames than adduser's default configuration. systemd
allows usernames containing uppercase letters and underscores, for
instance.

To summarize my thoughts on this matter, I think it's fine to restrict
usernames, but only for _very_ good reason. Specifically, we should not
justify such restrictions simply because they exist in one form or another
in other utilities. valid_user_group_name() currently disallows dots, for
instance, and while I recognize that using dots in a username can
sometimes be problematic, it is not in and of itself invalid. If other
software can't handle dots in usernames, that's their problem. libc can,
and that's all that's required to support it in order to use it in User=
on most systems.

But whether or not usernames are restricted, it's very important to alert
the sysadmin to the fact their unit file isn't being interpreted the way
they wrote it.
Lennart Poettering
2017-07-10 10:49:06 UTC
Permalink
Raw Message
Post by Michael Chapman
Post by Zbigniew Jędrzejewski-Szmek
Post by Reindl Harald
well, it even don't look but pretend it can't while it does which is
the worst type of operations possible - as long as "adduser" of the
underlying OS accepts and create "0pointer" systemd has *no business
at all* to pretend it can't
Then it's good the that it doesn't ;)
# adduser 0pointer
adduser: Please enter a username matching the regular expression configured
via the NAME_REGEX configuration variable. Use the `--force-badname'
option to relax this check or reconfigure NAME_REGEX.
I know you really only brought this up to counter Reindl's comment, but I
think it's important to point out that adduser's behaviour here is due to
its default configuration -- not due to any fundamental "problems" with
particular usernames. It's not clear why adduser's developers thought it was
a good default.
I guess what I'm saying is that saying "systemd should not support usernames
that start with a digit, since adduser doesn't" is problematic for at least
two reasons. First, adduser can be reconfigured by the sysadmin to allow
such usernames; and second, systemd places *fewer* restrictions on usernames
than adduser's default configuration. systemd allows usernames containing
uppercase letters and underscores, for instance.
Note one major difference between "adduser" and the unit file setting
"Unit=". The former is a tool you can create regular users with, while
the latter strictly applies to system users, as that's what system
services run as. And yes, different rules apply for system users than
for regular users.

And "0foobar" remains unportable and a bad idea, even if the user
bends his local system in the right way to make it accept it.
Post by Michael Chapman
To summarize my thoughts on this matter, I think it's fine to restrict
usernames, but only for _very_ good reason. Specifically, we should not
justify such restrictions simply because they exist in one form or another
in other utilities. valid_user_group_name() currently disallows dots, for
instance, and while I recognize that using dots in a username can sometimes
be problematic, it is not in and of itself invalid. If other software can't
handle dots in usernames, that's their problem. libc can, and that's all
that's required to support it in order to use it in User= on most
systems.
I am sorry, but you and I have very different understanding of
computer security. I do believe it is essential to validate all input,
and stick to safe input wherever we can.

I understand that you'd like to remove input validation from the
systemd codebase, and I welcome you to patch your local systemd
version for it, but please understand that in systemd upstream this is
not how things can work. Sorry.

Lennart
--
Lennart Poettering, Red Hat
Michael Chapman
2017-07-10 11:28:55 UTC
Permalink
Raw Message
Post by Lennart Poettering
Post by Michael Chapman
Post by Zbigniew Jędrzejewski-Szmek
Post by Reindl Harald
well, it even don't look but pretend it can't while it does which is
the worst type of operations possible - as long as "adduser" of the
underlying OS accepts and create "0pointer" systemd has *no business
at all* to pretend it can't
Then it's good the that it doesn't ;)
# adduser 0pointer
adduser: Please enter a username matching the regular expression configured
via the NAME_REGEX configuration variable. Use the `--force-badname'
option to relax this check or reconfigure NAME_REGEX.
I know you really only brought this up to counter Reindl's comment, but I
think it's important to point out that adduser's behaviour here is due to
its default configuration -- not due to any fundamental "problems" with
particular usernames. It's not clear why adduser's developers thought it was
a good default.
I guess what I'm saying is that saying "systemd should not support usernames
that start with a digit, since adduser doesn't" is problematic for at least
two reasons. First, adduser can be reconfigured by the sysadmin to allow
such usernames; and second, systemd places *fewer* restrictions on usernames
than adduser's default configuration. systemd allows usernames containing
uppercase letters and underscores, for instance.
Note one major difference between "adduser" and the unit file setting
"Unit=". The former is a tool you can create regular users with, while
the latter strictly applies to system users, as that's what system
services run as. And yes, different rules apply for system users than
for regular users.
And "0foobar" remains unportable and a bad idea, even if the user
bends his local system in the right way to make it accept it.
Post by Michael Chapman
To summarize my thoughts on this matter, I think it's fine to restrict
usernames, but only for _very_ good reason. Specifically, we should not
justify such restrictions simply because they exist in one form or another
in other utilities. valid_user_group_name() currently disallows dots, for
instance, and while I recognize that using dots in a username can sometimes
be problematic, it is not in and of itself invalid. If other software can't
handle dots in usernames, that's their problem. libc can, and that's all
that's required to support it in order to use it in User= on most
systems.
I am sorry, but you and I have very different understanding of
computer security. I do believe it is essential to validate all input,
and stick to safe input wherever we can.
That is a misrepresentation of my viewpoint.

I _do_ think systemd should validate all input. I think my other posts in
this thread make this clear: I want to see systemd complain noisily when
unit validation fails.

However, I do not think systemd should validate input more than it needs
to. Just because a particular value may (and _only_ may) cause problems
downstream of systemd does not mean that systemd should outright forbid
it. If it doesn't cause problems in systemd, it's not our business to
prevent its use.
Post by Lennart Poettering
I understand that you'd like to remove input validation from the
systemd codebase, and I welcome you to patch your local systemd
version for it, but please understand that in systemd upstream this is
not how things can work. Sorry.
Lennart
Lennart Poettering
2017-07-10 10:42:03 UTC
Permalink
Raw Message
Post by Michael Chapman
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.

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.

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.

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.

(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
--
Lennart Poettering, Red Hat
Reindl Harald
2017-07-10 10:53:05 UTC
Permalink
Raw Message
Post by Lennart Poettering
(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.)
and *that* is the real point of the whole issue - if one runs "adduser"
and the user got accepted and place it into a unit file you can't
expect that he notices that it get ignored by a random message in the syslog

and that is proven not to happen otherwise a ton of bugs and typos in
systemd-units whould not have made it into stable updates when at least
packagers would read their logs properly

well and with your sort of reactions to bugreports like
https://bugzilla.redhat.com/show_bug.cgi?id=1072368 it's no wonder that
some single warning get missed in the wood of messages
Michael Chapman
2017-07-10 11:15:31 UTC
Permalink
Raw Message
Post by Lennart Poettering
Post by Michael Chapman
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.
Post by Lennart Poettering
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
- 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
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.
Post by Lennart Poettering
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
https://stackoverflow.com/questions/6949667/what-are-the-real-rules-for-linux-usernames-on-centos-6-and-rhel-6
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.
Post by Lennart Poettering
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.
Post by Lennart Poettering
(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
Lennart Poettering
2017-07-10 11:58:50 UTC
Permalink
Raw Message
Post by Michael Chapman
Post by Lennart Poettering
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.
I want that units written on a system A are likely to work on a system
B. And this means that making use of concepts that are valid on A but
knowingly invalid on B is something we should complain loudly about.

Sure, there are always limitations to make things portable. But this
specific issue is an easy one, and a widely understood one (again:
google for it).
Post by Michael Chapman
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.)
Well, it took 3 years or so, until someone noticed the strict rules we
enforce. I seriously doubt that naming system users in such unsafe
ways is really that wide-spread usage.
Post by Michael Chapman
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.
Did I say that? I really don't think they are "perfectly valid"! They
are questionable on all levels. And if people use them for regular
users that's fine for them, but for system users I think stricter
requirements need to apply.

But anyway, I doubt we have to continue this here, we have different
understandings of security. I think validation is a good thing, and
filtering out dangerous strings early is a good thing.

People can always shoot themselves in the foot, and you have every
right to, but I really doubt this easy, well understood superficial
check is the right place to insist that the right to shooting yourself
in the foot is more important than the intention to secure things
down.

Lennart
--
Lennart Poettering, Red Hat
Michael Chapman
2017-07-10 12:23:30 UTC
Permalink
Raw Message
Post by Lennart Poettering
Post by Michael Chapman
Post by Lennart Poettering
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.
I want that units written on a system A are likely to work on a system
B. And this means that making use of concepts that are valid on A but
knowingly invalid on B is something we should complain loudly about.
Sure, there are always limitations to make things portable. But this
google for it).
Post by Michael Chapman
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.)
Well, it took 3 years or so, until someone noticed the strict rules we
enforce. I seriously doubt that naming system users in such unsafe
ways is really that wide-spread usage.
That _could_ be because people that have previously used such a username
hadn't looked in their logs and noticed that the User= directive wasn't
being applied. :-)
Post by Lennart Poettering
Post by Michael Chapman
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.
Did I say that? I really don't think they are "perfectly valid"! They
are questionable on all levels. And if people use them for regular
users that's fine for them, but for system users I think stricter
requirements need to apply.
But anyway, I doubt we have to continue this here, we have different
understandings of security. I think validation is a good thing, and
filtering out dangerous strings early is a good thing.
People can always shoot themselves in the foot, and you have every
right to, but I really doubt this easy, well understood superficial
check is the right place to insist that the right to shooting yourself
in the foot is more important than the intention to secure things
down.
Lennart
So be it. I'm fine with us remaining in disagreement... I just wish I
understood exactly what the security implications are in allowing such
usernames. I know my colleagues are going to ask me about this, and being
able to point at something and say "oh yeah, it breaks this specifically"
would be really handy.
Lennart Poettering
2017-07-10 15:03:09 UTC
Permalink
Raw Message
Post by Michael Chapman
Post by Lennart Poettering
Well, it took 3 years or so, until someone noticed the strict rules we
enforce. I seriously doubt that naming system users in such unsafe
ways is really that wide-spread usage.
That _could_ be because people that have previously used such a username
hadn't looked in their logs and noticed that the User= directive wasn't
being applied. :-)
Well: if you write a unit file, it's probably a good idea to test it
once before deploying it. I mean, it's not that we silently skip stuff
that was OK on sysvinit or so — that's because sysvinit of course never
supported dropping user IDs for you, you always had to do it yourself.

If your service is dropping privs on its own it's of course completely
between you and that service to name the user any way you like. But if
you tell systemd to do this for you and for the service, we do some
basic checking and validation, that's all. Or in other words: if I
write a unit file on my laptop here, and it works, then systemd is
supposed to give you the guarantee that it also works correctly on
my server system I deploy this on, too (to some degree at least), even
if it runs a slightly different Linux distro.
Post by Michael Chapman
So be it. I'm fine with us remaining in disagreement... I just wish I
understood exactly what the security implications are in allowing such
usernames. I know my colleagues are going to ask me about this, and being
able to point at something and say "oh yeah, it breaks this specifically"
would be really handy.
I am pretty sure it would be very welcome if somebody would do a
proper investigation and collect the precise restrictions different
systems in different versions enforce on naming users. And not just
across distro versions and their user name regexes, but also across
application software packages running on top of those distros. I am
not aware of any sufficiently comprehensive list of this.

On current Fedora, the current regex useradd enforces appears to be
this:

[a-zA-Z0-9._][a-zA-Z0-9._-]{0,30}[a-zA-Z0-9._-$]?

If I read things correctly at least... (the trailing $ appears to be a
special exception they added to be nice to Windows, dunno). And this
regex appears not to be configurable.

Lennart
--
Lennart Poettering, Red Hat
Zbigniew Jędrzejewski-Szmek
2017-07-10 15:29:45 UTC
Permalink
Raw Message
Post by Lennart Poettering
Post by Michael Chapman
Post by Lennart Poettering
Well, it took 3 years or so, until someone noticed the strict rules we
enforce. I seriously doubt that naming system users in such unsafe
ways is really that wide-spread usage.
That _could_ be because people that have previously used such a username
hadn't looked in their logs and noticed that the User= directive wasn't
being applied. :-)
Well: if you write a unit file, it's probably a good idea to test it
once before deploying it. I mean, it's not that we silently skip stuff
that was OK on sysvinit or so — that's because sysvinit of course never
supported dropping user IDs for you, you always had to do it yourself.
If your service is dropping privs on its own it's of course completely
between you and that service to name the user any way you like. But if
you tell systemd to do this for you and for the service, we do some
basic checking and validation, that's all. Or in other words: if I
write a unit file on my laptop here, and it works, then systemd is
supposed to give you the guarantee that it also works correctly on
my server system I deploy this on, too (to some degree at least), even
if it runs a slightly different Linux distro.
Post by Michael Chapman
So be it. I'm fine with us remaining in disagreement... I just wish I
understood exactly what the security implications are in allowing such
usernames. I know my colleagues are going to ask me about this, and being
able to point at something and say "oh yeah, it breaks this specifically"
would be really handy.
I am pretty sure it would be very welcome if somebody would do a
proper investigation and collect the precise restrictions different
systems in different versions enforce on naming users. And not just
across distro versions and their user name regexes, but also across
application software packages running on top of those distros. I am
not aware of any sufficiently comprehensive list of this.
On current Fedora, the current regex useradd enforces appears to be
[a-zA-Z0-9._][a-zA-Z0-9._-]{0,30}[a-zA-Z0-9._-$]?
If I read things correctly at least... (the trailing $ appears to be a
special exception they added to be nice to Windows, dunno). And this
regex appears not to be configurable.
Maybe the logic should be reversed: instead of trying to *enforce*
the most-strict name that works everywhere, just check that the name
is between 1 and 31 characters is length and not numeric, and relax
the restrictions on the exact characters in the user name, and *warn*
if the user name has "strange" characters:
Warning: user name "foo.bar" contains a dot which conflicts with chown user.group syntax
Warning: user name "0day" is not portable
Warning: user name "-user" looks like an option ;)
etc.

After all (as other people said) systemd has no such requirements
itself. It is true that such user names are confusing and
non-portable, but if the local admin has or wants to have such an
account for whatever reason, we don't really care.

Zbyszek
Lennart Poettering
2017-07-10 16:36:47 UTC
Permalink
Raw Message
Post by Zbigniew Jędrzejewski-Szmek
Post by Lennart Poettering
On current Fedora, the current regex useradd enforces appears to be
[a-zA-Z0-9._][a-zA-Z0-9._-]{0,30}[a-zA-Z0-9._-$]?
If I read things correctly at least... (the trailing $ appears to be a
special exception they added to be nice to Windows, dunno). And this
regex appears not to be configurable.
Maybe the logic should be reversed: instead of trying to *enforce*
the most-strict name that works everywhere, just check that the name
is between 1 and 31 characters is length and not numeric, and relax
the restrictions on the exact characters in the user name, and *warn*
Warning: user name "foo.bar" contains a dot which conflicts with chown user.group syntax
Warning: user name "0day" is not portable
Warning: user name "-user" looks like an option ;)
etc.
After all (as other people said) systemd has no such requirements
itself. It is true that such user names are confusing and
non-portable, but if the local admin has or wants to have such an
account for whatever reason, we don't really care.
I don't think things are that simple. We do our user name validation
in two places: for User=/Group= and for sysusers.d drop-ins. In both
cases the setting may have the effect of registering users in the
system user database (in the first case if DynamicUser= is used, in
the latter case if the user doesn't exist yet), and I am pretty sure
we shouldn't register users in the system user databases that aren't
portable.

I mean, again, systemd is the one defining both interfaces:
User=/Group= as well as sysusers.d, and I am pretty sure we should
make sure when they are used they are used in a reasonably safe and
sound and portable way. We want that people can write unit files and
run them everywhere and they work reasonably well. I think it's not
too much to ask from people to follow some simple basic rules when
making use of User=/Group=. We aren't really taking away anything
there, we aren#t really strict on something that was previously less
strict, simply because User=/Group= isn't a sysvinit concept, it's
genuinely a systemd concept.

Hence, it's not really a matter of consuming weird stuff local admins
created. It's a lot more than that: we *create* that stuff, possibly
leaving it around for good, and unit files are supposed to be
portable between systems.

Compare this with logind: we do not validate the user name passed to
us from PAM for new login sessions the same way as we do for
User=/Group=/sysusers.d. In the logind/PAM case the interface isn't
designed by us, PAM doesn't validate its input particularly carefully,
and we should probably just accept what PAM accepts as we don't create
anything here: we just consume what's listed in the user database.

Logging more verbosely about this is good, and maybe making this fatal
instead of just a warning might be good too, but just permitting it
sounds wrong to me.

Lennart
--
Lennart Poettering, Red Hat
Lennart Poettering
2017-07-10 16:40:00 UTC
Permalink
Raw Message
Post by Lennart Poettering
Post by Zbigniew Jędrzejewski-Szmek
After all (as other people said) systemd has no such requirements
itself. It is true that such user names are confusing and
non-portable, but if the local admin has or wants to have such an
account for whatever reason, we don't really care.
I don't think things are that simple. We do our user name validation
in two places: for User=/Group= and for sysusers.d drop-ins. In both
cases the setting may have the effect of registering users in the
system user database (in the first case if DynamicUser= is used, in
the latter case if the user doesn't exist yet), and I am pretty sure
we shouldn't register users in the system user databases that aren't
portable.
Or to say this differently: User=/Group=/sysusers.d shouldn't be
something you can create users with that for example ArchLinux'
useradd command wouldn't allow you to create.

Lennart
--
Lennart Poettering, Red Hat
Zbigniew Jędrzejewski-Szmek
2017-07-10 17:45:05 UTC
Permalink
Raw Message
Post by Lennart Poettering
Post by Lennart Poettering
Post by Zbigniew Jędrzejewski-Szmek
After all (as other people said) systemd has no such requirements
itself. It is true that such user names are confusing and
non-portable, but if the local admin has or wants to have such an
account for whatever reason, we don't really care.
I don't think things are that simple. We do our user name validation
in two places: for User=/Group= and for sysusers.d drop-ins. In both
cases the setting may have the effect of registering users in the
system user database (in the first case if DynamicUser= is used, in
the latter case if the user doesn't exist yet), and I am pretty sure
we shouldn't register users in the system user databases that aren't
portable.
Or to say this differently: User=/Group=/sysusers.d shouldn't be
something you can create users with that for example ArchLinux'
useradd command wouldn't allow you to create.
I can see it both ways, but yeah, it never came up before and
personally I never had the need (or even whim) to create a user that
systemd would reject. So I'd like to #6300 to go in, and apart
from that I'm happy with the status quo, and I merged #6321 now.

Zbyszek
Lennart Poettering
2017-07-10 18:24:06 UTC
Permalink
Raw Message
Post by Zbigniew Jędrzejewski-Szmek
Post by Lennart Poettering
Post by Lennart Poettering
Post by Zbigniew Jędrzejewski-Szmek
After all (as other people said) systemd has no such requirements
itself. It is true that such user names are confusing and
non-portable, but if the local admin has or wants to have such an
account for whatever reason, we don't really care.
I don't think things are that simple. We do our user name validation
in two places: for User=/Group= and for sysusers.d drop-ins. In both
cases the setting may have the effect of registering users in the
system user database (in the first case if DynamicUser= is used, in
the latter case if the user doesn't exist yet), and I am pretty sure
we shouldn't register users in the system user databases that aren't
portable.
Or to say this differently: User=/Group=/sysusers.d shouldn't be
something you can create users with that for example ArchLinux'
useradd command wouldn't allow you to create.
I can see it both ways, but yeah, it never came up before and
personally I never had the need (or even whim) to create a user that
systemd would reject. So I'd like to #6300 to go in, and apart
from that I'm happy with the status quo, and I merged #6321 now.
BTW, one more reference point to the discussion: shadow-utils upstream
enforces this regex apparently:

[a-z_][a-z0-9_-]*$?

The trailing $ thing appears to be a more recent addition, some
Windows thing. A minimum length of 1 is enforced, but apparently no
max length limit (neither _SC_LOGIN_NAME_MAX nor UT_NAMESIZE-1).

Fedora/RH deviate from that though and explicitly patch this out, replacing this
with the more relaxed regex mentioned earlier:

https://src.fedoraproject.org/cgit/rpms/shadow-utils.git/tree/shadow-4.1.5.1-goodname.patch

It appears our rules are hence pretty close to shadow-util's original
ones with the exeption of the max size limit and the Windows $ thing,
which really shouldn't apply to our system service users I figure.

Lennart
--
Lennart Poettering, Red Hat
Carlos Silva
2017-07-10 16:05:29 UTC
Permalink
Raw Message
On Mon, Jul 10, 2017 at 4:03 PM, Lennart Poettering
Post by Lennart Poettering
On current Fedora, the current regex useradd enforces appears to be
[a-zA-Z0-9._][a-zA-Z0-9._-]{0,30}[a-zA-Z0-9._-$]?
So, it *does* allow for usernames starting with numbers...
Jan Synacek
2017-07-10 13:16:43 UTC
Permalink
Raw Message
On Mon, Jul 10, 2017 at 12:42 PM, Lennart Poettering
Post by Lennart Poettering
Now, because this is so weakly defined, we hence do not follow POSIX
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.
Is this documented somewhere? If not, it would be great to have it
documented. I'm pretty sure that this exact paragraph would be ok.

Cheers,
--
Jan Synacek
Software Engineer, Red Hat
Lennart Poettering
2017-07-10 13:58:21 UTC
Permalink
Raw Message
Post by Jan Synacek
On Mon, Jul 10, 2017 at 12:42 PM, Lennart Poettering
Post by Lennart Poettering
Now, because this is so weakly defined, we hence do not follow POSIX
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.
Is this documented somewhere? If not, it would be great to have it
documented. I'm pretty sure that this exact paragraph would be ok.
There's a longer (and not entirely complete) comment about this in the
sources, but other than that it's not explicitly documented.

If you prep a patch that adds this to the User=/Group= man page, this
would certainly be welcome. However, it should be reworded, as we
shouldn't say "We" there, and probably drop explicit references to
POSIX and utmp there, and instead just dryly state the accepted
character set + minimum and maximum string lengths.

Lennart
--
Lennart Poettering, Red Hat
Lennart Poettering
2017-07-10 14:41:48 UTC
Permalink
Raw Message
Post by Lennart Poettering
Post by Jan Synacek
On Mon, Jul 10, 2017 at 12:42 PM, Lennart Poettering
Post by Lennart Poettering
Now, because this is so weakly defined, we hence do not follow POSIX
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.
Is this documented somewhere? If not, it would be great to have it
documented. I'm pretty sure that this exact paragraph would be ok.
There's a longer (and not entirely complete) comment about this in the
sources, but other than that it's not explicitly documented.
If you prep a patch that adds this to the User=/Group= man page, this
would certainly be welcome. However, it should be reworded, as we
shouldn't say "We" there, and probably drop explicit references to
POSIX and utmp there, and instead just dryly state the accepted
character set + minimum and maximum string lengths.
I have posted a PR documenting this just now:

https://github.com/systemd/systemd/pull/6321

Lennart
--
Lennart Poettering, Red Hat
Jan Synacek
2017-07-11 10:41:07 UTC
Permalink
Raw Message
On Mon, Jul 10, 2017 at 4:41 PM, Lennart Poettering
Post by Lennart Poettering
Post by Lennart Poettering
Post by Jan Synacek
On Mon, Jul 10, 2017 at 12:42 PM, Lennart Poettering
Post by Lennart Poettering
Now, because this is so weakly defined, we hence do not follow POSIX
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.
Is this documented somewhere? If not, it would be great to have it
documented. I'm pretty sure that this exact paragraph would be ok.
There's a longer (and not entirely complete) comment about this in the
sources, but other than that it's not explicitly documented.
If you prep a patch that adds this to the User=/Group= man page, this
would certainly be welcome. However, it should be reworded, as we
shouldn't say "We" there, and probably drop explicit references to
POSIX and utmp there, and instead just dryly state the accepted
character set + minimum and maximum string lengths.
https://github.com/systemd/systemd/pull/6321
Thanks for the fast response!
--
Jan Synacek
Software Engineer, Red Hat
Alexander Bisogiannis
2017-07-04 21:23:01 UTC
Permalink
Raw Message
If you need root permissions to create a unit, then it's not a security
issue. An annoyance at most.
The fact that you need to be root to create a unit file is irrelevant.

Systemd is running a service as a different user to what is defined in
the unit file.
This is a bug and a local security issue, especially because it will run
said service as root.

It might not warrant a CVE, although in my line of work this is
considered a security issue, but it is a bug and needs fixing.

The fix is to refuse to run the service, period.

Is there any other place I can go to open a bug, or do I need to go to
the upstream "vendor" bugzila?

Regards,
Abis.
Kai Krakow
2017-07-07 19:55:28 UTC
Permalink
Raw Message
Am Tue, 4 Jul 2017 21:23:01 +0000 (UTC)
Post by Alexander Bisogiannis
Post by Zbigniew Jędrzejewski-Szmek
If you need root permissions to create a unit, then it's not a
security issue. An annoyance at most.
The fact that you need to be root to create a unit file is irrelevant.
Systemd is running a service as a different user to what is defined
in the unit file.
This is a bug and a local security issue, especially because it will
run said service as root.
It might not warrant a CVE, although in my line of work this is
considered a security issue, but it is a bug and needs fixing.
The fix is to refuse to run the service, period.
There's nothing to fix because it already works that way: If you give
it a valid user name that does not exists, the system refuses to start
the unit with "user not found".

If you give it an invalid user name (leading digits, disallowed
characters), then it complains with a warning and continues to run as
if you specified no user (thus it runs as root).

The bug here is that a leading number will "convert" to the number and
it actually runs with the UID specified that way: 0day = 0, 7days = 7.
But this is not really a security concern as only root can create units
that contain a user - except you open exploits for that: But then you
have other problems then that.

Conclusion: Not a security issue. If you trick an admin into accepting
unit files without validating the contents, you are having other issues
than an issue with systemd.
Post by Alexander Bisogiannis
Is there any other place I can go to open a bug, or do I need to go
to the upstream "vendor" bugzila?
Maybe open a new issue and suggest that the current "conversion" should
be upgraded from a warning to a fatal error. Give examples of behavior
you get and behavior you expect. Also give counter examples of behavior
that works as you expect. Don't try to troll, after all it's the
developers forum and it only works if people stay with the facts.
Otherwise it becomes unusable, nobody wants that.

Best way to get it into one of the next releases is to prepare a pull
request that fixes the issue.
--
Regards,
Kai

Replies to list-only preferred.
Michael Chapman
2017-07-08 01:39:02 UTC
Permalink
Raw Message
On Sat, 8 Jul 2017, Kai Krakow wrote:
[...]
Post by Kai Krakow
The bug here is that a leading number will "convert" to the number and
it actually runs with the UID specified that way: 0day = 0, 7days = 7.
No, this is not the case. Only all-digit User= values are treated as UIDs.
Kai Krakow
2017-07-08 06:05:44 UTC
Permalink
Raw Message
Am Sat, 8 Jul 2017 11:39:02 +1000 (AEST)
Post by Michael Chapman
[...]
Post by Kai Krakow
The bug here is that a leading number will "convert" to the number
and it actually runs with the UID specified that way: 0day = 0,
7days = 7.
No, this is not the case. Only all-digit User= values are treated as
Then behavior is "correct".
--
Regards,
Kai

Replies to list-only preferred.
Kai Krakow
2017-07-08 06:10:05 UTC
Permalink
Raw Message
Am Sat, 8 Jul 2017 08:05:44 +0200
Post by Kai Krakow
Am Sat, 8 Jul 2017 11:39:02 +1000 (AEST)
Post by Michael Chapman
[...]
Post by Kai Krakow
The bug here is that a leading number will "convert" to the number
and it actually runs with the UID specified that way: 0day = 0,
7days = 7.
No, this is not the case. Only all-digit User= values are treated as
Then behavior is "correct".
Or in other words: The original bug description is wrong. The bug isn't
with non-existent users. That works fine.
--
Regards,
Kai

Replies to list-only preferred.
Michael Chapman
2017-07-08 06:29:37 UTC
Permalink
Raw Message
Post by Kai Krakow
Am Sat, 8 Jul 2017 08:05:44 +0200
Post by Kai Krakow
Am Sat, 8 Jul 2017 11:39:02 +1000 (AEST)
Post by Michael Chapman
[...]
Post by Kai Krakow
The bug here is that a leading number will "convert" to the number
and it actually runs with the UID specified that way: 0day = 0,
7days = 7.
No, this is not the case. Only all-digit User= values are treated as
Then behavior is "correct".
Or in other words: The original bug description is wrong. The bug isn't
with non-existent users. That works fine.
That is correct.

There's a lot of misinformation floating around with this issue -- there's
a tendency amongst some parts of the Linux community to jump on the
systemd-bashing bandwagon without fully understanding the problems. The
best thing we can do to counter this is to ascertain the facts, decide
what if anything needs to be fixed, and discuss the best way to move
forward with that.
Reindl Harald
2017-07-08 07:45:15 UTC
Permalink
Raw Message
Post by Michael Chapman
Post by Kai Krakow
Am Sat, 8 Jul 2017 08:05:44 +0200
Post by Kai Krakow
Am Sat, 8 Jul 2017 11:39:02 +1000 (AEST)
Post by Michael Chapman
[...]
Post by Kai Krakow
The bug here is that a leading number will "convert" to the number
and it actually runs with the UID specified that way: 0day = 0,
7days = 7.
No, this is not the case. Only all-digit User= values are treated as
Then behavior is "correct".
Or in other words: The original bug description is wrong. The bug isn't
with non-existent users. That works fine.
That is correct.
There's a lot of misinformation floating around with this issue --
there's a tendency amongst some parts of the Linux community to jump on
the systemd-bashing bandwagon without fully understanding the problems.
The best thing we can do to counter this is to ascertain the facts,
decide what if anything needs to be fixed, and discuss the best way to
move forward with that
why in the world do you not read the bugreport itself?
https://github.com/systemd/systemd/issues/6237

the decription is *not* about non-existent users so top spread FUD about
"systemd-bashing bandwagon without fully understanding the problems"
when you even don't read the bugreport you are talking about
_________________________________

how does that sound like talking about non-existing users?

I searched google and found that it was not right to named a linux user
with 0day, it should satisfy "^[a-z][-a-z0-9]*\$ , but when I use xinted
to start the service, it can handle the previlege rightly with linux
user 0day
Reindl Harald
2017-07-08 02:43:22 UTC
Permalink
Raw Message
Post by Kai Krakow
Am Tue, 4 Jul 2017 21:23:01 +0000 (UTC)
Post by Alexander Bisogiannis
Post by Zbigniew Jędrzejewski-Szmek
If you need root permissions to create a unit, then it's not a
security issue. An annoyance at most.
The fact that you need to be root to create a unit file is irrelevant.
Systemd is running a service as a different user to what is defined
in the unit file.
This is a bug and a local security issue, especially because it will
run said service as root.
It might not warrant a CVE, although in my line of work this is
considered a security issue, but it is a bug and needs fixing.
The fix is to refuse to run the service, period.
There's nothing to fix because it already works that way: If you give
it a valid user name that does not exists, the system refuses to start
the unit with "user not found"
and if you give a invalid username it has to do the same - PERIOD

systemd is directly after the kernel the most important and lowest level
stuff on a setup and hence can't be handeled like some random stuff
Loading...