Page MenuHomeFreeBSD

Make it possible to use any executable as init.
AbandonedPublic

Authored by trasz on Aug 2 2017, 8:08 PM.
Tags
None
Referenced Files
Unknown Object (File)
Feb 20 2024, 3:52 PM
Unknown Object (File)
Jan 3 2024, 2:47 AM
Unknown Object (File)
Dec 23 2023, 2:40 PM
Unknown Object (File)
Dec 20 2023, 8:28 AM
Unknown Object (File)
Nov 1 2023, 1:15 AM
Unknown Object (File)
Sep 15 2023, 9:26 AM
Unknown Object (File)
Sep 9 2023, 4:46 PM
Unknown Object (File)
Jul 29 2023, 1:34 AM
Subscribers

Details

Reviewers
emaste
kib
Summary

Make it possible to use any executable as init. In particular,
this allows one to set "init_path=/bin/sh" in the loader(8) prompt.

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 10831
Build 11223: arc lint + arc unit

Event Timeline

sys/kern/init_main.c
681

Depending on the type of the console, this could have quite spectacular effects. E.g. the boot could hang at this point if console is a serial port and CLOCAL is not set (and it is typically not set on ports). The thread would wait for the modem control indicating link.

There is a reason why init exists and handles ttys specially.

I would suggest a different approach for this, since ability to run a shell without configuring tty port in init in single-user mode is sometimes useful. Create a program which opens /dev/console for fds 0,1,2 and execs /bin/sh or whatever specified by some kenv var. The program would be specified as init substitute.

The crusial difference with your approach is that open of /dev/console only happens when user explicitly asked for it.

Add O_NONBLOCK and do some cleanups.

I agree that a separate application would be more elegant. However, it would make it more complicated from the user point of view - the approach I took doesn't require the user to learn anything new; the init_path option existed since forever, and there are no special userspace tools to remember about. Also, we kind of already have that: it should be possible to get init(8) to do exactly that, although I don't exactly know how.

Anyway, I've added the O_NONBLOCK flag, which should fix the problem you've described, while still working in the common case.

sys/kern/init_main.c
681

I've added O_NONBLOCK there, does this fix the issue?

I agree that a separate application would be more elegant. However, it would make it more complicated from the user point of view - the approach I took doesn't require the user to learn anything new; the init_path option existed since forever, and there are no special userspace tools to remember about. Also, we kind of already have that: it should be possible to get init(8) to do exactly that, although I don't exactly know how.

Get init to do what ?

It is very common for people who get into situation with a broken init and who know about init_path to write wrappers which open right terminal and spawn shell. I think that this is the only safe way to implement this functionality. The kernel code you are adding is ugly and unsafe.

sys/kern/init_main.c
681

No, it only prevents blocking, it does not make non-CLOCAL tty operational.

If your init is broken, your theoretical wrapper would probably be broken in the exact same way. It's just another moving part that can cause problems. Moving it into the kernel, on the other hand, is intuitive to the user.

sys/kern/init_main.c
681

Are you absolutely sure? Looking at the sys/kern/tty.c:ttydev_open(), it seems you'll never have non-CLOCAL /dev/console.

If your init is broken, your theoretical wrapper would probably be broken in the exact same way. It's just another moving part that can cause problems. Moving it into the kernel, on the other hand, is intuitive to the user.

Theoretically everything can be broken. But init(8) unable to spawn the emergency shell often caused by problems which can be solved by other binary. Your changes aim to start /bin/sh (or similar program), which can be also broken.

My experience with broken init(8) really falls into the following categories:

  1. init inode either corrupted or evacuated somewhere in lost+found.
  2. nosecure console
  3. broken rtld or libc or some other lib which is required to spawn shell.

In the first case, chances of some binary to survive are approximately same as /bin/sh. Second case is the most often and in fact most likely benefit receiver of your change. Third case means that new binary should be part of /rescue.

That said, my _opinion_ on the changes, besides the issues I pointed out, is that they are too naive and fall outside of accepted kernel code. IMO the best route is to create e.g. /rescue/init_shell which can be pointed by init_path directly and which would keep users and me happy.

sys/kern/init_main.c
681

Can you explain ?

sys/kern/init_main.c
681

FWIW, O_NONBLOCK should be in effect after the open(2) as well, which obviously must cause funny behaviour of read(2) done by the shell on stdin.

In other words, I suspect that this code was not tested.

Of course it's been tested. Shells use the nonblocking mode anyways, though, so they work just fine.

Having said that - yeah, you're right. I'll reimplement it as a part of init(8) instead.