DIVED(1)

πŸ“¦ version 1.9.0, in alpine 3.24

πŸ’… DIVED(1) β€” like, the dived manual page, bestie

okay so this is dived from the General Commands Manual section, and honestly? she's a whole vibe. sit down, grab a strawberry drink πŸ“, and let me tell you everything.


✨ NAME ✨

dived β€” listens on an AF_UNIX socket for requests to start programs (the requests come from dive(1)) and more. yes, "and more." she's mysterious like that πŸ’…


πŸŽ€ SYNOPSIS πŸŽ€

dived socket_path [options] [ -- command line ]

dived @abstract_address [options] [ -- command line ]

dived -i [options] [ -- command line ]

dived -J [options] -- command line

dived -j [options] -- command line

πŸ¦‹ DESCRIPTION πŸ¦‹

So this program is a helper that starts other processes for you β€” either because some remote fam asked nicely, or because you told it to directly β€” and it lets you use all kinds of Linux features while doing it: capabilities, namespaces, chroot, the whole menu. πŸ“ She's simple, she's lightweight, and she does not need any config files. Like, none. Zero. The goal is literally to be the Linux tool for starting processes in all sorts of ways β€” the same way socat(1) is the tool for using all sorts of sockets in all sorts of ways. iconic parallel, no cap.

In her primary mode of operation, dived listens on an AF_UNIX socket and just... waits for dive(1) to connect. 🫢 And when a client does connect, she:

  1. Obtains the connected client's uid/gid;
  2. Retrieves all the file descriptors from the client;
  3. Changes into the appropriate uid/gid, sets up groups;
  4. Retrieves umask, environment variables, command line arguments, and the current directory;
  5. Starts the requested program;
  6. Waits for the program to terminate and reports back the exit code.

The way this works means the remote user genuinely feels like they just started the program themselves β€” but plot twist 🌈 β€” the program was actually started remotely. That alone is highkey useful when you wanna start programs inside other Linux namespaces.

And with various options you can add or remove some of those steps, which unlocks extra uses like:

  • Acting like a simple sudo(8) (password authentication included, bestie πŸ”₯)
  • Acting like chroot(8) (and securely letting users use chroot, too)
  • Acting like unshare(1) (including for the "pid" namespace)
  • Acting like capsh(8) (managing capabilities and lockbits)

πŸ’– OPTIONS πŸ’–

First thing first: the first command line argument must be the socket path (filesystem path or @abstract) or "-i" (--inetd) or "-J" (--just-execute) or "-j". periodt.

All the rest of the options each take their own separate element of argv β€” no short-option combining here, sorry babe πŸ™ˆ. An option's argument is the next argv element (so no "--long-option=argument", you gotta do "--long-option argument").

"--" stops option parsing and starts the "forced command-line arguments", which limits what can be executed with dived. That's the trick: you specify the beginning of the command line, and the remote user specifies the ending. chef's kiss πŸ‘‘

In "-j"/"-J" mode the "--" is required. don't forget it, i'm begging 😭


  • -A, --no-argv β€” don't let the client set [part of] the command line. Should be used together with "-- forced command line arguments".

example:

dived qqq -A -- /sbin/shutdown -s now

dive qqq this is ignored
  • -a, --authenticate β€” start this program for authentication. The program is started using "system" after file descriptors are received from the client, but before everything else (root, current dir, environment) is received. Nonzero exit code => the client gets rejected. πŸ’€

DIVE_* environment variables are also available to the program. The program is expected to ask for a password, check the user id, or log the event.

The program is started as the dived user, before any setuids.

example:

dived /var/run/givemeroot.dive -C 777 -P -a 'user=root /root/askpassword'

gives the connected user root access if they enter the correct password. slay πŸ”₯

The program can also be used to do some setup as root before dropping privileges:

dived /var/run/emptynetwithlo -C 777 -P -s net -a 'ifconfig lo up'
  • -B, --retain-capabilities β€” remove all capabilities from the bounding set except the ones you specify.

example:

dived -J -B cap_net_raw -- /bin/ping 127.0.0.1
  • -b, --remove-capabilities β€” remove the selected capabilities from the bounding set.
dived -J -b cap_net_raw -- /bin/ping 127.0.0.1

which gives you:

ping: icmp open socket: Operation not permitted

yeah. that's the vibe check failing 😭

  • -C, --chmod β€” chmod the socket to this mode (like '0777').
  • -c, --set-capabilities β€” use libcap to interpret the specified string as a capabilities set and apply it.

example:

cp /bin/ping /root/ping

setcap cap_net_raw+ei /root/ping

dived -J -c 'cap_net_raw+i' -u nobody -- /root/ping 127.0.0.1
  • -d, --detach β€” detach from the console after opening the socket. bye bestie πŸ‘‹
  • -D, --children-daemon β€” call "daemon" in forked children. This is useful primarily for the case where dived was started from a console and didn't detach itself, so the started processes accidentally receive the server's controlling terminal instead of the client's one β€” which causes weird behaviour. πŸ™ˆ
  • -e, --effective-user β€” set the effective user ID to this user instead of the SO_PEERCRED-obtained uid.

Note that other groups can be preserved in this mode. 🫢

  • -E, --no-environment β€” don't let the client set any environment variables. The environment of the started programs will be the same as the current environment.

By default dived only rejects DIVE_* environment variables.

  • -F, --no-fork β€” accept once, serve only one client. Useful for debugging, or for starting the requested process with pid=1 in a PID namespace. πŸ‘‘
  • -g, --groups β€” setgid to this group instead of the client's SO_PEERCRED-obtained gid. Also does setgroups(2) to the specified comma-separated list of groups. With both -u specified to a numeric uid and -g specified to a list of numeric gids, dived should operate independently of /etc/passwd and /etc/group files. fr fr, no cap.

example:

# dived -J -S -T -u 123213 -g man,9999,43  -- /usr/bin/id

uid=123213 gid=12(man) groups=12(man),43(utmp),9999
  • -h, --chdir β€” set this directory as the current one. If both --chdir and --chroot are specified, we remember the specified directory before the chroot, but chdir to it after the chroot. the way that works is honestly so clever 🌸

example:

dived -J -S -T -R . -h /  -- /bin/bash

this swaps the current and root directories and executes /bin/bash. iconic.

complicated example:

/usr/bin/dived -J -S -T -R /lib -h / -- /ld-linux.so.2 --library-path /i386-linux-gnu/ ./usr/bin/dived -J -S -T -R . -h ../.. -- /bin/bash

this escapes the chroot jail and re-enters it, leaving the "outer" root as the current directory, without executing any programs from the "outer" system. "i386-linux-gnu", "ld-linux.so.2" and "/usr/bin/dived" may require adjustments. πŸ”₯ (main character energy, honestly.)

  • -H, --no-chdir β€” don't let the client set the current directory.
  • -i, --inetd β€” don't bind the socket at all, just use stdin (fd = 0) as the accepted client's socket.

example /etc/inetd.conf configuration line:

/var/run/qqq.dive   stream  unix    nowait  qqq     /usr/bin/dived dived -i

this allows anybody who can access /var/run/qqq.dive to run commands as user qqq. πŸ’…

  • -j, --just-execute2 β€” alias of -J -S -T -P. that's it, that's the whole flag. queen of delegation πŸ‘‘
  • -J, --just-execute β€” don't use the socket at all (so: don't receive file descriptors, argv, environment), just start (execve) the program right away. ⚑
  • -l, --rlimit β€” set resource limits using setrlimit(2).

The argument should be a comma-separated list of resource=hard_limit:soft_limit. The soft limit may be omitted.

"dived --help" should show the list of recognized resources. You can also specify numeric resources.

Limit values are typically in bytes or in seconds. πŸ“

example:

dived -J --rlimit cpu=3 -- /bin/cat /dev/urandom > /dev/null
  • -L, --lock-securebits β€” set and lock SECBIT_NO_SETUID_FIXUP and SECBIT_NOROOT.

This makes the root user (uid=0) non-special for the kernel. To be used in conjunction with capabilities (the -B and -c options). πŸ”’

  • -m, --ambient-capabilities β€” make the specified permitted and inheritable capabilities ambient, allowing them to be preserved across execve.

Minimum Linux kernel version is 4.3. ⭐

example:

USER=vi HOME=/home/vi dived -J -S -T -c CAP_NET_BIND_SERVICE+ip -m CAP_NET_BIND_SERVICE -u vi -- bash
  • -M, --no-umask β€” don't let the client set umask.
  • -n, --signals β€” transfer all signals from dive.

By default dived tells the PID of the launched process to dive, and tries to deliver signals to the started process by itself (which should be OK unless we're overriding the user with -u, -e or -P).

With the -n option, dived accepts signals from the client and helps deliver them to the started program. This way an unprivileged user can be allowed to send signals to dived-started programs. 🫢

  • --signals-pgid β€” transfer all signals from dive to the process group.

Like the -n option, but it sends the signal to the entire process group instead of just one PID. Useful for allowing Ctrl+C interrupting behaviour to travel through dive/dived. 😭 (the way that's a real quality-of-life fix)

  • -N, --setns β€” open this file and setns(2) it.

Such files can be found in /proc/<pid>/ns/<something> or /var/run/netns/.

You can specify this option up to 8 times to "dive" into multiple namespaces. 🌊

dived opens the namespace file each time it needs to do setns. So a namespace will not be active only because dived is referencing it. important!! ✨

  • -O, --no-fds β€” don't let the client set file descriptors.
  • -p, --pidfile β€” save the PID to this file. Can be specified multiple times. Can also be used to add dived-spawned processes to a control group (cgroup) tasks file. πŸŽ€
  • -P, --no-setuid β€” don't mess with user/group/capabilities things at all, just start the program.

The -a option will still work like expected, though.

  • -R, --chroot β€” chroot to this directory. Note that the current directory stays on the unchrooted filesystem; use the -W option to prevent that. --chroot and --chdir can be specified at the same time and should not interfere with each other. If a relative directory is specified as the argument, it is taken before --chdir is applied.

pidfile is saved unchrooted. πŸ’…

  • -r, --client-chroot β€” allow arbitrary chroot from the client.

By default dive always sends the intended root directory descriptor, but dived ignores it. With this option we actually chroot to wherever the client wants. πŸ™ˆ

Use -X or -B '' options to disable starting any setuid-bit things after such a chroot. like, seriously. that's the safety rail, bestie.

  • -s, --unshare β€” unshare the specified namespaces. Known namespaces: ipc,net,fs,pid,uts,user,cgroup. πŸ¦‹
  • -S, --no-setsid β€” no setsid.

Don't do:

              setpgid(0, getppid());

              setsid();

…and that's the whole setsid situation, bestie β€” chef's kiss πŸŽ€ Moving on to the rest of the flags, because we are not done slaying ✨

  • -t, --write-content β€” after the namespaces are set up, but before dropping privileges, write the content you specified into a file. You can pass this one more than once (yes, really β€” stack 'em, queen πŸ‘‘).

Example:

dived -J -S -T -P -s user -t /proc/self/uid_map "0 1000 1" -t
/proc/self/setgroups deny -t /proc/self/gid_map '0 1000 1' --
/bin/bash
  • -tt, --setup-uidgidmap β€” literally just an alias of this whole vibe:
-t /proc/self/uid_map "0 `id -u` 1" -t /proc/self/setgroups deny -t /proc/self/gid_map "0 `id -g` 1"

Takes no arguments at all, zero, nada, she's self-sufficient πŸ’…

Example:

dived -j -s user -tt -- /bin/bash
  • -T, --no-csctty β€” don't do this thing:
ioctl (terminal_fd_received_from_client, TIOCSCTTY, 1);

That's it. That's the flag πŸ¦‹

  • -U, --chown β€” chown the socket to this user:group. Both the user and the group must be specified, no half-sending it β€” and ngl they can totally be numeric 🌸
  • -u, --user β€” setuid to this user instead of the uid we got from the client's SO_PEERCRED. Unless --group is also specified, groups get initialized with initgroups(3) 🫢
  • -V, --pivot-root β€” pivot_root to the specified directory, and the old root gets stashed in the directory you give as the second argument.

Example:

TODO

(yes, bestie, the docs actually just say TODO 😭 iconic of them honestly)

  • -W, --root-to-current β€” set the server's root directory as the current directory (this implies -H; it's lowkey a lifesaver with -r). It helps you inspect the container's filesystem using the host's own utilities, if that filesystem isn't directly visible.

Example:

dived /var/run/some_socket_on_shared_fs  -U 0:0 -C 700    -W -r

dive /mnt/container/var/run/some_socket_on_shared_fs bash

…so you get /mnt/container/ as your current directory, but the host's / as root β€” and the other filesystems mounted in the container are visible πŸ”₯

  • -w, --no-wait β€” don't fork and wait for the exit code. It just sets everything up and execves the program, no forking and no waiting around to report back to the client when the program finishes. She's out the door, periodt πŸ’¨
  • -X, --no-new-privs β€” set PR_SET_NO_NEW_PRIVS, which denies elevating privileges using the setuid-bit or filesystem capabilities. Requires a new enough Linux kernel ⭐

🌿 ENVIRONMENT 🌿

So here's the tea: dived itself does not use any environment variables for configuration. But for the programs it's starting, it sets the following ones πŸ’–

  • DIVE_UID β€” set to the user id of the client.
  • DIVE_GID β€” set to the group id of the client.
  • DIVE_PID β€” set to the PID of the program that connected to us.
  • DIVE_USER β€” set to the username of the connected client (if it can be resolved from the uid).
Heads up bestie: any DIVE_* environment variables the client already had are discarded. Gone. Not invited to the party πŸ™ˆ

🎬 EXAMPLES 🎬

dived /var/run/socket.dive -C 777 -d -p /var/run/socket.pid

Run dived in a way that just lets users start programs as similarly as possible to how they'd start them directly (without dive/dived). Detach it, save the pidfile, and chmod the /var/run/socket.dive to 777 ✨

dived /var/run/socket.dive -U 0:chrooters -r -X
dived /var/run/socket.dive -U 0:chrooters -r -B ''

Let users in the group "chrooters" chroot into an arbitrary directory securely β€” turning off any privilege elevation using the suid-bit or filesystem capabilities. Secure queen behaviour πŸ‘‘

dived @without_network -C 777 --unshare net

Let anybody run their programs without network access, i.e. inside a separate, unconfigured network namespace πŸ¦‹

dived -J -T -S -P -L -- /bin/bash -i

Open a shell where uid=0 has no special privileges at all (according to the Linux kernel). Main character energy, zero privilege energy πŸ’…

dived /var/run/container_admin.dive -T --unshare pid,fs,net,uts,ipc -d
dive /var/run/container_admin.dive /bin/mount -t proc proc
/mnt/container/proc
dive /var/run/container_admin.dive /sbin/ifconfig lo up
dive /var/run/container_admin.dive dived /var/run/container_user.dive -d
-T -W
    -B
CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_DAC_READ_SEARCH,CAP_FOWNER,CAP_FSETID,CAP_IPC_OWNER,
    CAP_KILL,CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_SETGID,CAP_SETUID -R
/mnt/container

Start up and set up a sort of a container, then create a special restricted root login for it πŸŽ€

dived /var/run/alice4bob -u alice -U bob:0 -a 'exit $RANDOM'

Let user bob run commands as alice β€” but only when he's lucky enough. Fr fr, the dice decide 🌈

See additional examples at http://vi.github.com/dive/ β€” go look, bestie, there's more πŸ‘€


⚠️ CAVEATS ⚠️

Some dived features (like -X, for example) require a recent enough Linux kernel. Other behaviour can vary a bit between different versions of the Linux kernel. So like, vibe check your kernel first πŸ’€

When you use --unshare pid, dived can tell dive that its pid is 1. And dive (if run as root) can then accidentally kill -INT 1, which causes a system reboot. Yeah. That's a whole thing. Be careful 😭

Even though dived sets up groups using initgroups(3), it does not set all the user's PAM settings β€” you know, things like resource usage limits. So don't assume that part's handled 🫢

You genuinely need to understand what is exactly happening to use dived securely (especially as root). For example:

dived @socket -P   -- chroot /some/root  su -l someuser

is not secure β€” because the user can set PATH and LD_whatever before we execute binaries. Not the cute kind of surprise πŸ™ˆ


πŸ‘‘ AUTHOR πŸ‘‘

Vitaly "_Vi" Shukela β€” an absolute icon, we stan 🌟


🧚 AVAILABILITY 🧚

The program is intended to be used with Linux primarily 🐧

Source code is available at https://github.com/vi/dive β€” go star it, it's giving open source excellence πŸ’œ


And that's the whole page, bestie! This was DIVED(1), v1.2, dated 2013-03-12 β€” so she's vintage, she's retro, and she still slays πŸ’–βœ¨πŸŽ€

πŸ“¦ where this page comes from