16

I'm just beginning to learn about the init system, so I only know about the high level characteristics of both.

I have noticed a lot of fuss over systemd, even some people claiming that systemd was created to purposely introduce vunerabilities!

The argument I see most often is that systemd introduces a new, large (and unfamiliar) attack vector. On the other hand, it seems to me that a system like systemd is actually a good thing because it is standardized code as opposed to ad-hoc init scripts. In this respect, I see similarities to the kernel. Sure, everyone can create their own easy to read OS, but is it not better to reuse the same code so that a large number of eyeballs are monitoring it?

Am I on the right track here? Are there issues I am not considering?

  • 1
    "Systemd moves more logic into binaries..." This is the real problem with most systemd nay sayers. We simply will never be able to trust it, especially in this day and age of blatant corporate and government snooping. – Bill Peterson Mar 11 '18 at 14:25
  • @BillPeterson Well even ignoring blatant backdoors (which I think is unlikely), the memory unsafety and bugginess of C and such simply make debugging harder. – forest Mar 12 '18 at 3:24
18

(mostly) people don't inject vulnerabilities deliberately, they occur by accident. As the volume of code increases, the number of defects increases. But its not just size - the number of bugs increases with the complexity of the code and it increases faster than linearly. So more code is bad news for security.

The attack surface of systemd is massively larger than initd - the default configuration has multiple interfaces.

A big annoyance for me is the design philosophy; the intention is that systemd provides a more unified way for distributors to integrate services. But this means removing control over the system from syste admins (over and above the impact of replacing a complex but well understood eco-system). It deliberately makes it hard or impossible to achieve thing which could be done with initd (note that there are many options for service managers running under initd - djb daemontools, upstart, initng, rund, procd, openrc.... Most of which solve the paralellization / dependency problems that limit the sysv rc init system).

A lot of the logic of the start up of a unix system is implemented in shell scripts. This makes it much easier to not only reverse engineer the operation but also to instrument it and extend the capabilities. Systemd moves more logic into binaries and relies more on a complex and poorly documented configuration.

The combination of deliberately reducing the level of control by the system administrator and failing to support the system administrator in their task makes it more difficult for them to do their job - which encompasses assuring the security of the system.

A further consequence of all this complexity in PID 1 means that you should have to reboot your system a lot more frequently. In addition to the impact on availability this also means moving your system through a series of interim states - which can temporarily expose vulnerabilities which are difficult to detect on a homeostatic system. Using daemon-reexec to work around this brings a new set of problems.

The benevolent-dictator-for-life model seems to work well for the linux kernel, but that is not how the rest of the open source industry operates. Indeed it is perhaps the exception which proves the rule - that open source works because nobody is in charge, not despite nobody being in charge. Systemd assumes control over a lot of the functionality in a linux system, yet it operates as a relatively small community. And as per the pwnie award it appears to be somewhat inward looking: there are not a lot of eyeballs on the code: nobody is listening when concerns are raised about the code.

  • theregister.co.uk/2017/07/05/… It appears to be a total security risk. Is there a way to use something else instead with Ubuntu? – inf3rno Sep 18 '17 at 5:44
  • 1
    Note also that systemd makes certain kernel APIs mandatory, such as cgroups. The same applies to userspace, as it requires dbus. All these features would be better off disabled in many high-security scenarios, but systemd demands they be present. – forest Mar 12 '18 at 3:26
5

Systemd is actually a collection of several parts, and for a comparison to make sense, you have to compare the parts that actually correspond to each other.

Let's first look at SysV init: This is a very small program that is run as the first process after boot that does some very basic setup, then reads a configuration file (/etc/inittab) and starts one or more programs configured therein, optionally restarting them when they exit. It also opens some communication channels (/dev/initctl, signal handlers) that make it possible to change the current runlevel, a change of which will result in some other programs to be run, again as configured in /etc/inittab.

And that's it. Obviously, this doesn't have a large attack surface, simply because it does almost nothing. On the flipside, everything else that's required for actually managing a typical system is delegated to external programs: how to start and stop a specific service (e.g. web server, database, network...), dependencies between services (i.e. start the database first, only then the web server), more complex monitoring (watchdog functionality), privilege dropping and sandboxing, on-demand service activation (e.g. inetd), mounting filesystems, ... Systemd integrates much of this functionality and is therefore more complex.

Now, integrating these things in a central place has great potential to reduce the overall complexity and fragility and thereby make the system more secure. Take the various "sandboxing" features, including privilege dropping, restricting access to certain directories, private temp directories, settings separate namespaces, network isolation... For systemd, these are pretty easy to implement as part of setting up the services environment, which - as a service manager - must do anyway. In contrast, with SysV init, a separate program would have to be used; in practice this would be a set of shell scripts, or it would be integrated in the individual services, thus spreading the "risky" code over more places.

Additionally, systemd provides the system administrator with the means to setup these features easily (a few lines in a configuration file), relieving them from having to implement them themselves (which in some cases can even involve modifying and recompiling services!). Of course, in practice this means they aren't used at all. From a security point of view, the ini-style configuration format is also an advantage over the turing-complete shell scripts that are used with SysV init.

As for the development model behind systemd: I see this as an advantage compared to the alternative, because there is one central place where development (and extensive testing!) happens, which is in contrast to the previous mixture of mostly distribution specific code. Even the SysV init core itself differed between distributions, because its upstream can be considered dead. And contrary to what others say, systemd upstream is actually very responsive and open to reasonable change requests.

That said, I can see one situation where things are different, which is when the features provided by systemd aren't needed, for example if you want to build a router or a simple network gateway where the set of required services is known beforehand and will never change. Even there, you might want to take advantage of the easy-to-use sandboxing features, and this is anyway a special case that doesn't apply for the vast majority of systems.

  • 3
    How many of the benefits you describe above could not have been achieved by replacing (or adding) an abstraction layer between init and the daemon? (such as DJB's daemontools, procer, monit and others do) – symcbean Aug 21 '17 at 16:12
  • 1
    I guess most, though at the cost of higher complexity (depending on how you'd implement it), and without any security benefit. In the simplest case, PID 1 would just fork and exec the "real" init and do nothing afterwards, which is pretty pointless. Alternatively, the management of service state (including setting up the environment) could be moved to one dedicated process per service, but then you'd lose the ability to reexec init without losing state... (Note that the actual functionality contained in systemd PID 1 is already pretty small, most features use external helpers where feasible.) – Marc Schütz Aug 22 '17 at 8:31
-1

As for the eyeballs thing - historically the init RC scripts at the core of RHEL and such, the basic "SYS V" init clone, was not something that was written with extreme robustness in mind, it's not like they did a whiteboarded state machine design in there. And you'd not have been able to just send patches for it in most major distros. If there's no written out spec and real sw design on your init, you'll find people are afraid to change it.

Yet, the impact of fragility was quite low, as was the size of the single tasks. Run a script. Run the next one. Don't have any temporary files. Be stateless internally except for a run counter that makes things go either towards the desired "target" or down towards the opposite.

There was no interfaces except the init command, or telinit. In a proper unix, a init 0 simpy ends init, leaving you in limbo. Linux (for convenience and to ease live for people who don't read a manual) had already gone far away from the simplistic design, and there seems to never have been the consideration (sorry) that the init clone should be kind of "MIL-SPEC" quality.

Now we're having the same thing, and again those concerns are not the upmost, but now it takes a vastly larger part in processing tasks, in how it interfaces with the kernel, in that it is accessible to non-root users and in that it processes input outside of when a startup task is done.

Those are mere differences. The problem is that again such aspects as hardening or failing safe / failing operative state seem not considered as core things. There are some measures to that direction (i.e. if resolved automatically respawns if it gets dropped out by malicious traffic) but not a lot.

Now lets assume the development process and responsiveness on concerns would change. That would be cool. (having worked with a few alternate inits I don't think it would happen, since none of the others have been hostile in any way)

Then we're left with one problem: The many-eyeballs thing is questionable. In the normal init system, due to the lack of interfaces, the "attack vector" is getting an init script in place, which only root can do. Then it's allowed to do whatever it deems necessary, and you're at the mercy of the author as far as i.e. dropping privs goes. If he knows how to use su, it'll be su, if he doesn't then it'll be sudo, and so on. But the only way he'll attack your init system is if he puts something in there that overwrites the binary/script. He'll not even easily "persist" inside it, since any variable he'd export would be squashed when the next script is run. The language (sh, ideally, POSIX only) is to the point where you got a sec hole for every 10 years, and normally none at all. And, I wanna stress that a bit - there's just too little to attack and no way he can get an attack it after the system is up.

Those differences are there. They can be cause for worry or not. But the "shared code base" argument is mostly moot. The argument that you get rid of bad priv-drop wrappers has two discussion points. one, that those are either bad design (local nat is a thing) or necessities (ssh) and two, that in the sw world we've learned that for any security related issue we need to prioritize it among our worst issues, and rather overdo solving it than not. This is not happening.

Right now few people are looking for exploits, but it's not like this is an interesting topic for sec researchers. Once that happens and meets with a billions-of-installed devices-not-getting-patched base, I'm a bit worried. We might have benefits in the tech world. For the people who benefit from whatever our systems do, there's benefits insofar as automatically restarting services is becoming more common (because apparently it was just too hard to read up on daemontools for non-HA setups), but I don't wanna be around and need to justify if we repeat some shit like CodeRed right in our init.

Show me how to shut down that now as opposed to the footprint of a single(!) shell script being run on boot. The countermeasure has gotten a tad more complicated. And as for daemon-reexec I'm still wondering why a zypper ps -s would still see old systemd parts in memory afterwards.

I've skipped comparing to SMF - which one of the systemd devs called "Solaris" or some parallels to AIX, like binary logging and SRC. SMF had a very open, inclusive, thoughtful and documented design process and I think that's the big differences lie. No idea how that will ever be mended.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.