Skip to content

Commit 0b58ea9

Browse files
committed
hover article
1 parent d8d6ee7 commit 0b58ea9

File tree

3 files changed

+158
-0
lines changed

3 files changed

+158
-0
lines changed

content/blog/hover/diagram.png

14.8 KB
Loading

content/blog/hover/index.md

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
---
2+
title: Hover, the CLI tool to protect your home
3+
date: 2024-06-10T14:08:37Z
4+
tags: []
5+
draft: false
6+
summary: Never again run apps fearing they will polute your files.
7+
---
8+
9+
Hey! 👋
10+
11+
I wrote `hover-rs`, a very cool CLI tool. When you enter a `hover`, the arranges
12+
some private mount namespaces. Every modification to files (creation, deletion
13+
or modification) is lost when you exit hover.
14+
15+
![](./diagram.png)
16+
17+
18+
```
19+
$ hover # Enter hover by just running the command
20+
You are now hovering~
21+
A layer is covering your /home/ayats
22+
You can find your top layer in: /home/ayats/.cache/hover-rs/layer-2024-06-11-0635-evCxznv
23+
24+
$ touch foo # File "foo" is created under the hover
25+
26+
$ exit # Hover is just a subprocess
27+
28+
Leaving hover
29+
You can find your top layer in: /home/ayats/.cache/hover-rs/layer-2024-06-11-0635-evCxznv
30+
31+
$ file foo # File "foo" is gone
32+
foo: cannot open `foo' (No such file or directory)
33+
```
34+
35+
## A note on namespaces
36+
37+
When you call hover, it uses the
38+
[`clone`](https://man7.org/linux/man-pages/man2/clone.2.html) libc function,
39+
which creates a new subprocess from process. `clone` has some settings to
40+
customize how this process is created, and we use the namespace configuration.
41+
42+
"Linux Namespaces" or simply namespaces, are a special machinery of the Linux
43+
kernel that allows the developer to dissociate parts of the execution of a whole
44+
process. There are 5 different namespaces:
45+
46+
- User namespace
47+
- Mount namesapce
48+
- PID namespace
49+
- Network namesapce
50+
- IPC namesapce
51+
- UTS (domain name) namespace
52+
53+
These are the primitives that all the container runtimes, like Docker or
54+
Singularity, use the isolation of the container from the host system. For hover,
55+
we only use the first the first two.
56+
57+
The **mount namespace** lets us rearrange mountpoints in a subprocess, such that
58+
the parent process doesn't "see" these mounts. For hover, we arrange an
59+
`overlayfs` on top `$HOME`.
60+
61+
The **user namespace** is only used because only root can setup a mount
62+
namespace. With a user namespace, we can become root (can't fight with this
63+
logic, right?). In reality, inside a user namespace, we can remap user and group
64+
ids, such that some functionality is allowed through. For example, we can
65+
arrange a mount namespace, and calls to `id` we show `root`, but we are not able
66+
to modify files in `/etc`.
67+
68+
Another function that can arrange namespaces is
69+
[`unshare`](https://man7.org/linux/man-pages/man2/unshare.2.html), which has its
70+
own CLI tool that you can play with:
71+
72+
```
73+
$ unshare -Umr # -U => unshare user namespace
74+
# -r => map current user to root
75+
# -m => unshare mounts namespace
76+
77+
# id
78+
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)
79+
80+
# mount -t tmpfs tmpfs /var/empty
81+
82+
# findmnt -T /var/empty
83+
TARGET SOURCE FSTYPE OPTIONS
84+
/var/empty tmpfs tmpfs rw,relatime,uid=1000,gid=100
85+
86+
# exit
87+
88+
$ id
89+
uid=1000(ayats) gid=100(users) ...
90+
```
91+
92+
Once the new mounts are configured, you can `unshare`/`clone` again to become
93+
your original user and group.
94+
95+
## A note on overlayfs
96+
97+
"An overlay filesystem is a pseudo filesystem that implements a union mount for
98+
other filesystems."
99+
([`mount.8`](https://man7.org/linux/man-pages/man8/mount.8.html))
100+
101+
The overlayfs allows us to redirect writes into a path to another. The overlayfs
102+
is composed of a sandwhich with the following elements.:
103+
104+
- An upperdir: where new files or modifications are written to. For example,
105+
after we do a `touch foo`, the file is actually stored at `upperdir/foo`.
106+
- A lowerdir: the overlayfs shows a read-only of the lowerdir, which can be
107+
configured to be multiple directories stacked on top of each other.
108+
- The mountpoint: this is where the overlayfs is exposed.
109+
- A workdir: this is the most uninteresting. An implementation detail of
110+
overlayfs which we need to setup.
111+
112+
Overlayfs is also used by container runtimes like docker, to merge the read-only
113+
container image (lowerdir), with any files that you create, remove or modify
114+
within the container (upperdir). For example, you can do a `rm /usr/bin/cd`
115+
within a container of alpine, but the original image is left unmodified in your
116+
disk.
117+
118+
## Limitations
119+
120+
One of the problems of user namespaces, is that as an unprivileged user, you can
121+
only map 1 group. In my machine, my user is part of many groups, that within
122+
hover are unknown:
123+
124+
```
125+
$ id
126+
uid=1000(ayats) gid=100(users) groups=100(users),1(wheel),17(audio),19(uucp),26(video),27(dialout),57(networkmanager),62(systemd-journal),174(input),984(tss),994(incus-admin)
127+
128+
$ hover id
129+
uid=1000(ayats) gid=100(users) groups=100(users),65534(nogroup)
130+
```
131+
132+
This may be a problem if you interact with any of the programs that rely on this
133+
grups. One solution could be to code hover have a "rootful" mode, but that may
134+
defeat its purpose...
135+
136+
And of course, this relies on the Linux machinery, so it is not a thing on MacOS.
137+
138+
139+
## Installation
140+
141+
The hover repo provides a Nix flake where you can get the package from.
142+
143+
```
144+
nix build github:viperML/hover-rs
145+
```
146+
147+
I also build statically-linked binaries that are published into github releases:
148+
https://github.com/viperML/hover-rs/releases/tag/latest .
149+
150+
```
151+
$ curl -OL https://github.com/viperML/hover-rs/releases/download/latest/hover-static-x86_64-linux
152+
$ chmod +x hover-static-x86_64-linux
153+
$ ./hover-static-x86_64-linux
154+
```
155+
156+
Being a rust project, of course you can also build manually with `cargo`.
157+
158+
Have fun!
Loading

0 commit comments

Comments
 (0)