Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

systemd can't handle the process previlege that belongs to user name startswith number, such as 0day #6237

Closed
mapleray opened this issue Jun 29, 2017 · 37 comments

Comments

@mapleray
Copy link

mapleray commented Jun 29, 2017

Submission type

  • Bug report

systemd version the issue has been seen with

systemd 232

Used distribution

Linux ubuntu 4.10.0-19-generic #21-Ubuntu SMP Thu Apr 6 17:04:57 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

In case of bug report: Expected behaviour you didn't see

The process started by systemd should be user previlege

In case of bug report: Unexpected behaviour you saw

The process started by systemd was root previlege

In case of bug report: Steps to reproduce the problem

linux user's name : 0day
conf file: socat.service

[Unit]
Description=0day socat service
After=network.target

[Service]
User=0day
Restart=always
Type=simple
WorkingDirectory=/home/0day/
ExecStart=/usr/bin/socat TCP-LISTEN:18086,reuseaddr,fork EXEC:"/opt/run-elf"

[Install]
WantedBy=multi-user.target

and then use systemctl start socat.service to start process, but the previlege is root

P.S.
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

@poettering
Copy link
Member

Yes, as you found out "0day" is not a valid username. I wonder which tool permitted you to create it in the first place. Note that not permitting numeric first characters is done on purpose: to avoid ambiguities between numeric UID and textual user names.

systemd will validate all configuration data you drop at it, making it hard to generate invalid configuration. Hence, yes, it's a feature that we don't permit invalid user names, and I'd consider it a limitation of xinetd that it doesn't refuse an invalid username.

So, yeah, I don't think there's anything to fix in systemd here. I understand this is annoying, but still: the username is clearly not valid.

I hope that makes sense?

@mapleray
Copy link
Author

Yeah, thanks.

@divVerent
Copy link

Wouldn't it make sense to refuse User=0day then?

In fact, wouldn't it even make sense to refuse User=0x200 or User=01000 rather than User=512 (in other words, to only allow decimal canonical user IDs) for the same reason?

BTW: where does xinetd come in here?

@bloerwald
Copy link

I wonder which tool permitted you to create it in the first place.

It appears that el7 patches shadow-utils-4.1.5.1/libmisc/chkname.c so that it does allow that kind of usernames, explicitly removing the restrictions: https://gist.github.com/bloerwald/a482791395114fa82636e2ab207cdb11

While it does indeed seem to be a not-a-bug in systemd, one may want to make someone maintaining that el7 patch aware of that the combination of systemd and that patch does pose an issue.

A patch refusing any User= that are invalid would be a nice thing, even if it is not a bug, as noted by @divVerent. That would put the el7 maintainer at the position to explicitly remove that check as well, thinking about their patch allowing usernames without restrictions.

@nopil3os
Copy link

nopil3os commented Jul 1, 2017

I wonder which tool permitted you to create it in the first place.

useradd doesn't complain: screenshot

@ghost
Copy link

ghost commented Jul 1, 2017

Does the POSIX standard deny leading numbers for user names on *nix?

@Nothing4You
Copy link

Tested on Debian with shadow-utils 4.4 and adduser 3.115, only adduser complains, useradd doesn't.

# useradd -m 0day
# userdel -r 0day
userdel: 0day mail spool (/var/mail/0day) not found
# adduser 0day
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.

@RealDolos
Copy link

RealDolos commented Jul 1, 2017

Let's look if it's actually invalid... Probably not because:

3.276 Portable Filename Character Set
The set of characters from which portable filenames are constructed.
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9 . _ -
The last three characters are the period, underscore, and hyphen characters, respectively.

3.426 User Name
A string that is used to identify a user; see also User Database. To be portable across systems conforming to IEEE Std 1003.1-2001, the value is composed of characters from the portable filename character set. The hyphen should not be used as the first character of a portable user name.

http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_276

adduser will often refuse it tho, e.g. on debian with NAME_REGEX (calling itself "more conservative by default"), but you can still override that behavior.

So in my humble opinion, it's a valid name and thus systemd has a bug here.

Even if you assume leading numbers are not allowed, systemd running the unit under root is a bug too. It should refuse to run the unit, in particular in the light of:

systemd will validate all configuration data you drop at it
-- @poettering #6237 (comment)

This is clearly not the case, User=0day is clearly not properly validated and silently ignored and it's still a bug (or it's just put into something like atoi and will try to execute 1day as uid 1, not sure about that).

So either way, there is a bug here.

@redrifle
Copy link

redrifle commented Jul 1, 2017

hm yes I'll look into it

@rain-1
Copy link

rain-1 commented Jul 1, 2017

I think people are getting distracted with whether or not 0day is a valid name or not.

The real problem here is that the unit is run as root, despite "0day" not describing the root user, isn't it?

Can a systemd developer tell: Will a patch that gives an error in this case be accepted? I can get started on it if so.

@Nothing4You
Copy link

@rain-1 there's 2 bugs - one is that it is still running as root and the other is that it doesn't support usernames starting with numbers.

@rain-1
Copy link

rain-1 commented Jul 1, 2017

I see! please make a separate issue to track the second bug (usernames starting with numbers).

@RealDolos
Copy link

RealDolos commented Jul 1, 2017

Actually, fix the incorrect user name handling thereby fixing the run-as-root issue too. And we kinda made an issue about that already, namely THIS one.

@julian-klode
Copy link
Contributor

This is a severe security issue that should be fixed, and assigned a CVE, and not not-a-bug.

@rain-1
Copy link

rain-1 commented Jul 1, 2017

@julian-klode you might have misunderstood this bug, it cannot be used for priv. esc.

@julian-klode
Copy link
Contributor

@rain-1 If the process starts, and you expect it to start a user and not as root, then that is a security issue, because your service suddenly runs as root (and you might not notice it until it is too late).

@pRiVi
Copy link

pRiVi commented Jul 1, 2017

So many bugs and issues, and all the time the poettering ignorance... I just cannot stand it...

It does not matter if its free, if you carry such things with it. Sadly the only way leaving it is using devuan...

@RealDolos
Copy link

RealDolos commented Jul 1, 2017

Seems the stuff is parsed using:

Meaning indeed, User=1day will try to run with UID 1 as well

Edit: See other comments following up on this probably not being the case after all.

@UgnilJoZ
Copy link

UgnilJoZ commented Jul 1, 2017

@RealDolos My systemd v232 says: Invalid user/group name or numeric ID, ignoring: 7oz and starts the service as root also. Likely because the 7oz as a whole is not a valid number.

# /etc/systemd/system/test.service
[Service]
ExecStart=/bin/id
User=7oz

@red-hood
Copy link

red-hood commented Jul 1, 2017

If a user name is indeed allowed to be made up of digits alone, there has to be a way to distinguish it from a UID. I propose to specify the information in the same way GNU coreutiles does, by appending a + whenever a UID is meant, and otherwise try to resolve to a username first.

See also: https://www.gnu.org/software/coreutils/manual/coreutils.html#Disambiguating-names-and-IDs

@RealDolos
Copy link

@UgnilJoZ do you actually have a user with uid 7?

@UgnilJoZ
Copy link

UgnilJoZ commented Jul 1, 2017

@RealDolos Yes, I just created one for testing ;)

@julian-klode
Copy link
Contributor

@RealDolos safe_atou checks that it is a valid number, and not a number with something at the end, so the warning here makes sense. But then the bug report is incomplete, because systemd does at least warn about it. I'm not sure it makes sense to start a service if the specified user is invalid, though.

@RealDolos
Copy link

RealDolos commented Jul 1, 2017

@julian-klode

I'm not sure it makes sense to start a service if the specified user is invalid, though.

That one is easy, in my humble opinion: Same as systemd should not pick and run some random binary when the specified ExecStart is invalid, it shouldn't run a service under a random uid if it cannot find the specified user (uid 0 being the random uid fairly picked by the Debian PRNG, of course)

PS: Sorry, @julian-klode, only saw just now that you're actually a Debian dev. My Debian PRNG quip wasn't meant to personally target you.

@red-hood
Copy link

red-hood commented Jul 1, 2017

In

if (parse_uid(*username, &u) >= 0) {
, the entry is first parsed as a UID, and only if that fails, a lookup for the username is done. To be compliant, this order has to be changed.

@red-hood
Copy link

red-hood commented Jul 1, 2017

The line which does the hard-coded fallback to root is here:

if (r < 0)

@julian-klode
Copy link
Contributor

@red-hood That's not even remotely true - the code is for ConditionUser, and the line mentioned says that if the user could not be parsed (< 0) that the condition is not met (return 0 => false) - and chasing it down step by step in issue comments is not helping anyone.

@divVerent
Copy link

divVerent commented Jul 1, 2017 via email

@kentfredric
Copy link

Now how can this broader issue be fixed? Hard. Very hard. Making a valid User= directive mandatory would be a good start - but this is horribly backwards incompatible

Maybe a systemd config option that turns such warning cases into errors? Or like, a config file that enumerates the kinds of errors that should be fatal instead of warnings?

@mbiebl
Copy link
Contributor

mbiebl commented Jul 2, 2017

Sigh, since this now attracting the trolls, I'm locking the conversation.

@systemd systemd locked and limited conversation to collaborators Jul 2, 2017
@systemd systemd deleted a comment from jrmithdobbs Jul 2, 2017
@systemd systemd deleted a comment from sergeyfrolov Jul 2, 2017
@poettering
Copy link
Member

Just to summarize things:

  1. systemd is not the one coming up with the restrictions on user names, and while some distributions are less restrictive, many do enforce the same restrictions as we do. In order to make systemd unit files portable between systems we'll hence enforce something that resembles more the universally accepted set, rather than accept the most liberal set possible.
  2. User= in unit files is about system users, not regular users, and I am pretty sure we should enforce a stricter regime about system users than regular users.
  3. In systemd we generally follow the rule that when we encounter a unit setting that does not validate syntax-wise we'll log about it and ignore it, for compat reasons. We do the same for User= here as for all other options. Note that if you specify a valid user name but where the user doesn't exist, then we'll instead fail the service on start, because in that case there's not just something wrong with the syntax the service author used but actually something inconsistent on the system, and that should be considered fatal.

@martinpitt
Copy link
Contributor

Agreed about 1 and 2, but I disagree about 3. Setting User=nonexistinguser is syntactically correct, just not semantically. It's perfectly legitimate and consistent to ignore unkonwn keys such as Userr=foo, but we don't have a policy to ignore unknown/invalid values. For example, if a unit has Requires=nonexisting.service, it rightfully fails; we don't just ignore nonexisting.service. For the same reason, a unit with User=nonexistinguser should fail instead of silently running as root. That's the security relevant bit that we ought to fix.

I agree that not handling user names that start with digits can be considered "not a bug".

@poettering
Copy link
Member

For the same reason, a unit with User=nonexistinguser should fail instead of silently running as root.

That's exactly what happens, and what I wrote above: if the username is valid but the user doesn't exist we'll let the unit fail on start. If the username is already invalid syntax-wise we'll log about it but proceed.

Hence, if you write:

User=000fooo...@!

Then we'll ignore the assignment altogether (but log about it), since it's syntactically invalid. But if you specify:

User=waldo

and the user "waldo" does not exist (though it is syntactically valid), then we'll accept the setting, but as soon as you actually try to start the unit it will fail with "user not found".

@martinpitt
Copy link
Contributor

Thanks @poettering for the clarification!

@haraldh
Copy link
Member

haraldh commented Jul 10, 2017

@haraldh
Copy link
Member

haraldh commented Jul 11, 2017

User @roland found that usernames that contain unicode characters also cause this bug.

The bug also affects usernames that contain unicode characters, which can be created with "useradd" without difficulties:

# useradd -m pöttering
# id pöttering
uid=1002(pöttering) gid=1003(pöttering) Gruppen=1003(pöttering)

# cat /etc/systemd/system/test-unicode.service
[Service]
User = pöttering
ExecStart = /usr/bin/touch /tmp/foo

# ls -l /tmp/foo
ls: cannot access '/tmp/foo': No such file or directory
# systemctl daemon-reload
# systemctl start test-unicode.service
# ls -l /tmp/foo
-rw-r--r-- 1 root root 0 Jul 3 17:56 /tmp/foo

Why it may be unlikely that an admin creates a username starting with a zero and wants to run a service with it I think this eventually might happen with usernames that contains umlauts or acute accents.

@poettering
Copy link
Member

poettering commented Jul 11, 2017

@haraldh we stick to the portable set, that the majority of distros agrees on, and umlauts in user names don't work on fedora, nor arch... I am pretty sure it works on a small minority of distros only. here's the output i get on fedora:

# adduser züpp
adduser: invalid user name 'züpp'

Note that fedora/rhel explicitly patch our the upstream rules of shadow-utils:

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

Note that neither the upstream nor the fedora rules actually accept umlauts in usernames.

Anyway, systemd is not a tool for generic user management, it's a tool for service management. We make restrictions on the username you may make use of to keep things safe and portable between distributions, hence we stick to the set of user names that are portable, and complain about all others.

I am happy with changing our rules, but before we do that, please work with the POSIX, shadow-utils, libuser communities, as well with the other Linux distributions to come up with a single unified set of rules, and then we are happy to adopt that too in systemd. But until then, I think it's better for systemd to stick to the rules that only permit names that are portable to all of these systems. After all systemd not only consumes these names, it also potentially creates them (via sysusers.d or when DynamicUser=1 is used), and we should make sure systemd cannot beused as a vehicle for creating users that are otherwise not allowed.

Also: don't forget we don't break people's stuff with this, User=/Group= knew no counterpart in sysvinit, because priv dropping had to be implemented by the daemons manually there. If you do decide to let systemd do the priv dropping for you, we politely ask you to use portable names, so that the unit files work everywhere. And the rules we enforce are neither crazy nor random, they are the common core every distro accepts.

fbuihuu pushed a commit to fbuihuu/systemd that referenced this issue Nov 29, 2017
If an error is encountered in any of the Exec* lines, WorkingDirectory,
SELinuxContext, ApparmorProfile, SmackProcessLabel, Service (in .socket
units), User, or Group, refuse to load the unit. If the config stanza
has support, ignore the failure if '-' is present.

For those configuration directives, even if we started the unit, it's
pretty likely that it'll do something unexpected (like write files
in a wrong place, or with a wrong context, or run with wrong permissions,
etc). It seems better to refuse to start the unit and have the admin
clean up the configuration without giving the service a chance to mess
up stuff.

Note that all "security" options that restrict what the unit can do
(Capabilities, AmbientCapabilities, Restrict*, SystemCallFilter, Limit*,
PrivateDevices, Protect*, etc) are _not_ treated like this. Such options are
only supplementary, and are not always available depending on the architecture
and compilation options, so unit authors have to make sure that the service
runs correctly without them anyway.

Fixes systemd#6237, systemd#6277.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests