summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile22
-rw-r--r--README.md243
-rw-r--r--voidnsrun.c9
-rw-r--r--voidnsundo.c6
4 files changed, 211 insertions, 69 deletions
diff --git a/Makefile b/Makefile
index 479dbe7..15bdbd0 100644
--- a/Makefile
+++ b/Makefile
@@ -6,15 +6,13 @@ LDFLAGS =
INSTALL = /usr/bin/env install
PREFIX = /usr/local
-all: voidnsrun voidnsundo
-
test: testserver testclient
-voidnsrun: voidnsrun.o utils.o
- $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+run: voidnsrun.o utils.o
+ $(CC) $(CFLAGS) -o voidnsrun $^ $(LDFLAGS)
-voidnsundo: voidnsundo.o utils.o
- $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+undo: voidnsundo.o utils.o
+ $(CC) $(CFLAGS) -o voidnsundo $^ $(LDFLAGS)
testserver: test/testserver.o utils.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
@@ -22,9 +20,13 @@ testserver: test/testserver.o utils.o
testclient: test/testclient.o utils.o
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
-install: voidnsrun voidnsundo
- $(INSTALL) voidnsrun voidnsundo $(PREFIX)/bin
- chmod u+s $(PREFIX)/bin/voidnsrun $(PREFIX)/bin/voidnsundo
+install-run: run
+ $(INSTALL) voidnsrun $(PREFIX)/bin
+ chmod u+s $(PREFIX)/bin/voidnsrun
+
+install-undo: undo
+ $(INSTALL) voidnsundo $(PREFIX)/bin
+ chmod u+s $(PREFIX)/bin/voidnsundo
clean:
rm -f *.o test/*.o voidnsrun voidnsundo testserver testclient
@@ -32,4 +34,4 @@ clean:
%.o: %.c
$(CC) $(CFLAGS) -c $^ -I. -o $@
-.PHONY: all install clean distclean \ No newline at end of file
+.PHONY: run undo install-run install-undo clean \ No newline at end of file
diff --git a/README.md b/README.md
index 7d3eca9..bb437bf 100644
--- a/README.md
+++ b/README.md
@@ -1,86 +1,168 @@
# voidnsrun
-**voidnsrun** is utility for launching programs in an isolated namespace with
-alternative `/usr` tree. Its primary goal is to run glibc programs in
-musl-libc Void Linux environments or vice-versa.
+**voidnsrun** is utility for launching programs in an isolated mount namespace
+with alternative `/usr` tree. Its primary goal is to run glibc programs in
+musl-libc Void Linux environments (or vice-versa, but who needs that?).
It creates a new private mount namespace, transparently substitutes `/usr` and
-some other directories with directories from your alternative root using bind
+some other directories with directories from your glibc container using bind
mounts, and launches your program.
+**voidnsundo**, to the contrary, is utility for launching programs in the parent
+mount namespace from within the mount namespace created by **voidnsrun**.
+
## Installation
-Just clone the repo, and then:
+### Creating glibc container
+As per the [Void documentation](https://docs.voidlinux.org/installation/musl.html#glibc-chroot),
+perform glibc base system installation to a separate new directory:
```
-$ make
-$ sudo make install
+# mkdir /glibc
+# XBPS_ARCH=x86_64 xbps-install --repository=http://alpha.de.repo.voidlinux.org/current -r /glibc -S base-voidstrap
```
-Note that installed binary must be owned by root and have suid bit. `make install`
-should handle it.
+### Installing voidnsrun
-## Usage
+Clone the repo, and then:
```
-voidnsrun [OPTIONS] PROGRAM [ARGS]
+make run
+sudo make install-run
+```
-Options:
- -m <path>: add bind mount
- -r <path>: altroot path. If this option is not present,
- VOIDNSRUN_DIR environment variable is used.
- -h: print this help
- -v: print version
+This will install **voidnsrun** to `/usr/local/bin`.
+
+Export path to the container:
+```
+export VOIDNSRUN_DIR=/glibc
+```
+
+Also export path to **voidnsundo**:
+```
+export VOIDNSUNDO_BIN=/usr/local/bin/voidnsundo
```
-**voidnsrun** needs to know the path to your alternative root directory and it can
-read it from the `VOIDNSRUN_DIR` environment variable or you can use `-r`
-argument to specify it.
+You may want to add these exports to your `~/.bashrc` or similar script.
-You may want to add something like this to your `~/.bashrc` or similar script:
+### Installing voidnsundo
+**voidnsundo** is supposed to be used from within the glibc container, so it has
+to be linked with glibc. First, let's use just installed **voidnsrun** to install
+build dependencies into the container:
```
-export VOIDNSRUN_DIR=/glibc
+sudo voidnsrun -r /glibc xbps-install -Su
+sudo voidnsrun -r /glibc xbps-install make gcc
```
-By default, **voidnsrun** binds these paths from alternative root to the new
-namespace:
-- `/usr`
-- `/var/db/xbps`
-- `/etc/xbps.d`
+Then enter the container (the current working directory will be preserved by
+**voidnsrun** 1.2 or higher) and build, then install **voidnsundo**:
+```
+voidnsrun bash
+make clean
+make undo
+sudo make install-undo
+```
-But if you're launching `xbps-install`, `xbps-remove` or `xbps-reconfigure`
-and using **voidnsrun** version 1.1 or newer, this is what it will bind:
-- `/usr`
-- `/var`
-- `/etc`
+This will install **voidnsundo** to `/usr/local/bin` in the container (which is
+`/glibc/usr/local/bin` in reality).
-If you want to bind something else, use the `-m` argument.
+Type `exit` or `Ctrl+D` to exit the container.
-## Example
+## Usage
-Let's imagine you want to use some proprietary glibc app on your
-musl-libc Void Linux box. Let it be Vivaldi browser for the example. You
-unpacked it to `/opt/vivaldi` and it doesn't work, obviously.
+### voidnsrun
+```
+Usage: voidnsrun [OPTIONS] PROGRAM [ARGS]
-First, you need to perform an alternative glibc base system installation to a
-separate new directory:
+Options:
+ -r <path>: Container path. When this option is not present,
+ VOIDNSRUN_DIR environment variable is used.
+ -m <path>: Add bind mount. You can add up to 50 paths.
+ -u <path>: Add undo bind mount. You can add up to 50 paths.
+ -U <path>: Path to voidnsundo. When this option is not present,
+ VOIDNSUNDO_BIN environment variable is used.
+ -i: Don't treat missing source or target for added mounts as error.
+ -V: Enable verbose output.
+ -h: Print this help.
+ -v: Print version.
```
-# mkdir /glibc
-# XBPS_ARCH=x86_64 xbps-install --repository=http://alpha.de.repo.voidlinux.org/current -r /glibc -S base-voidstrap
+
+**voidnsrun** needs to know the path to your glibc installation directory (or
+"container"), it can read it from the `VOIDNSRUN_DIR` environment variable or
+you can use `-r` argument to specify it.
+
+By default, **voidnsrun** binds only `/usr` from the container. But if you're
+launching `xbps-install`, `xbps-remove` or `xbps-reconfigure`and using
+**voidnsrun** version 1.1 or higher, it will bind `/usr`, `/var` and `/etc`.
+
+To bind something else, use the `-m` option. You can add up to 50 binds as of
+version 1.2.
+
+There's also the `-u` option. It adds bind mounts of the **voidnsundo** binary
+inside the namespace. See more about this below in the **voidnsundo** bind mode
+section. Just like with the `-m` option, you can add up to 50 binds as of version
+1.2.
+
+To bind the **voidnsundo** binary, **voidnsrun** has to know its path, and, like
+with the container's path, it reads it from the `VOIDNSUNDO_BIN` environment
+variable and from the `-U` option.
+
+### voidnsundo
+
```
+Usage: voidnsundo [OPTIONS] PROGRAM [ARGS]
-Export path to this installation for **voidnsrun**:
+Options:
+ -V: Enable verbose output.
+ -h: Print this help.
+ -v: Print version.
```
-export VOIDNSRUN_DIR=/glibc
+
+**voidnsundo** can be used in two modes.
+
+One is the **"normal" node**, when you invoke it like `voidnsundo <PROGRAM> [ARGS]`
+and your `PROGRAM` will be launched from and in the original mount namespace.
+
+For example, if you don't have a glibc version of firefox installed (so there's
+no `/usr/bin/firefox` in the container), but you want to launch the "real" (the
+one installed in your root musl system) firefox while being in the mount
+namespace, just do `voidnsundo /usr/bin/firefox`.
+
+The other mode is the **"bind" mode**. While in the container, and therefore in
+the new mount namespace, you can bind mount **voidnsundo** to any path (don't
+worry: it won't be visible outside the namespace), and, when invoked by that
+path, it will launch the corresponding executable in your parent (root)
+namespace.
+
+For example, being in the container, you can do this:
+```
+touch /usr/bin/firefox
+mount --bind /usr/local/bin/voidnsundo /usr/bin/firefox
```
+and while there was no `/usr/bin/firefox` in the glibc container, after this,
+when you'll launch `/usr/bin/firefox`, the "real" firefox from the root musl
+system will be launched.
+
+The creation of this bind mounts of **voidnsundo** can be automated by using
+`-u` option of **voidnsrun**.
+
+## Examples
-Try launching your app:
+This section contains some real examples of how to use some proprietary glibc
+apps on your musl-libc Void Linux box.
+
+### Vivaldi
+
+The first example is the Vivaldi browser. Let's assume you unpacked it to
+`/opt/vivaldi` (from rpm or deb package) and, obviously, it doesn't work.
+
+Try launching it with **voidnsrun**:
```
-voidnsrun /opt/vivaldi/vivaldi
+$ voidnsrun /opt/vivaldi/vivaldi
```
-It won't work just yet:
+It won't work just yet, but it's a start:
```
/opt/vivaldi/vivaldi: error while loading shared libraries: libgobject-2.0.so.0: cannot open shared object file: No such file or directory
```
@@ -99,7 +181,7 @@ glib-devel-2.66.2_1 /usr/share/gdb/auto-load/usr/lib/libgobject-2.0.so.0.6600.2-
libglib-devel-2.66.2_1 /usr/lib/libgobject-2.0.so -> /usr/lib/libgobject-2.0.so.0
```
-Sync repos and install `glib`. You can use **voidnsrun** for this purpose too.
+Sync repos and install `glib`:
```
$ sudo voidnsrun -r /glibc xbps-install -Su
$ sudo voidnsrun -r /glibc xbps-install glib
@@ -113,9 +195,46 @@ $ voidnsrun /opt/vivaldi/vivaldi
As you can see, it no longer complains about missing `libgobject-2.0.so.0`, now
it's `libnss3.so`. Repeat steps above for all missing dependencies, and in the
-end, it will work. (If it's not, then something's still missing. In particular,
-make sure to install fonts related packages: `xorg-fonts`, `freetype`,
-`fontconfig`, `libXft`.)
+end, it will work.
+
+Note that, for some reason, it doesn't complain about missing font related
+libraries, such as freetype, so make sure to install them too, as well as some
+base fonts:
+```
+$ sudo voidnsrun -r /glibc xbps-install freetype fontconfig libXft xorg-fonts
+```
+
+If you're noticing performance issues with Vivaldi, check the `vivaldi://gpu`
+page. If it turns out that hardware acceleration is unavailable, you're missing
+some packages again. I don't know which ones exactly, but installing `xorg-minimal`
+should fix it.
+
+### PhpStorm
+
+**PhpStorm** and other JetBrains IDEs should just work like this (of course,
+replace `/opt/PhpStorm` with real path on your machine):
+```
+voidnsrun /opt/PhpStorm/bin/phpstorm.sh
+```
+
+But it is only at first glance, everything works. After some time you may
+notice all kinds of weird stuff caused by the fact that it runs inside the
+"container" with different `/usr`. For instance, if you open built-in terminal
+window, it will work, but... it will not be the shell you expect, it will be
+glibc-linked shell from the container. Some programs that you have
+installed on your root musl system will not be available there (like, it won't be
+able to launch a browser because there's no browser), other may not work as
+expected.
+
+In general, all programs that launch other programs will suffer from this. To
+overcome this, the **voidnsundo** utility has been written and `-u` option added
+to **voidnsrun**.
+
+To fix the built-in PhpStorm's terminal and the ability to launch browser as shown
+in the above example, launch it like so:
+```
+voidnsrun -u /bin/bash -u /usr/bin/firefox /opt/PhpStorm/bin/phpstorm.sh
+```
## FAQ
@@ -130,10 +249,32 @@ Defaults env_keep += "VOIDNSRUN_DIR"
A: If you installed fonts on your main system, applications that run in the mount
namespace can't see them because of custom `/usr` directory. You need to install
-them again into the altroot directory.
+them again into the container directory.
+
+Some workaround to bind-mount `/usr/share/fonts` from the root system to the
+namespace may be introduced in future, if Linux will allow such hacks.
+
+## Security
+
+**voidnsrun** and **voidnsundo** are setuid applications, meaning they are
+actually started as root and then dropping privileges when they can. setuid is
+generally bad, it's a common attack vector that allows local privilege
+escalation by exploiting unsafe code of setuid programs.
+
+While these utilities have been written with this thought in mind, don't trust
+me. Read the code, it's not too big. Place yourself in attacker's shoes and try
+to find a hole. For every new discovered vulnerability in these utilities that
+would allow privilege escalation or something similar I promise to pay $25 in
+Bitcoin. Contact me if you find something.
## Changelog
+#### 1.2
+
+- Added **voidnsundo** utility for spawning programs in the parent mount
+ namespace from withing the namespace created by **voidnsrun**.
+- Restore current working directory after changing namespace.
+
#### 1.1
- Bind whole `/etc` and `/var` when launching `xbps-install`, `xbps-remove` or
diff --git a/voidnsrun.c b/voidnsrun.c
index d82d00e..8516343 100644
--- a/voidnsrun.c
+++ b/voidnsrun.c
@@ -34,12 +34,11 @@ void usage(const char *progname)
" -r <path>: Container path. When this option is not present,\n"
" " CONTAINER_DIR_VAR " environment variable is used.\n"
" -m <path>: Add bind mount. You can add up to %d paths.\n"
- " -u <path>: Add undo utility bind mount. You can add up to %d paths.\n"
- " -U <path>: Undo program path. When this option is not present,\n"
+ " -u <path>: Add undo bind mount. You can add up to %d paths.\n"
+ " -U <path>: Path to " VOIDNSUNDO_NAME ". When this option is not present,\n"
" " UNDO_BIN_VAR " environment variable is used.\n"
- " -i: Don't treat missing source or target for an added mount\n"
- " as an error.\n"
- " -V: Verbose output.\n"
+ " -i: Don't treat missing source or target for added mounts as error.\n"
+ " -V: Enable verbose output.\n"
" -h: Print this help.\n"
" -v: Print version.\n",
USER_LISTS_MAX, USER_LISTS_MAX);
diff --git a/voidnsundo.c b/voidnsundo.c
index 89dfefc..6720b8d 100644
--- a/voidnsundo.c
+++ b/voidnsundo.c
@@ -24,9 +24,9 @@ void usage(const char *progname)
printf("Usage: %s [OPTIONS] PROGRAM [ARGS]\n", progname);
printf("\n"
"Options:\n"
- " -V: Verbose output.\n"
- " -h: Print this help.\n"
- " -v: Print version.\n");
+ " -V: Enable verbose output.\n"
+ " -h: Print this help.\n"
+ " -v: Print version.\n");
}
int main(int argc, char **argv)