See basic information about dive in the readme file.
Examples
Simple remote process startup in unshare
# # Start dived in unshared network namespace
# unshare -n -- dived /var/run/qqq.socket -d
# dive /var/run/qqq.socket ip addr
1218: lo: <LOOPBACK> mtu 16436 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# dive /var/run/qqq.socket bash
# # Now we are inside that unshare
# ip link set lo up
# exit
exit
# # outside unshare again
# dive /var/run/qqq.socket bash
# ip addr
1218: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
# # our network configuration persisted
# # Start dived in unshared network namespace
# unshare -n -- dived /var/run/qqq.socket -d
# dive /var/run/qqq.socket ip addr
1218: lo: <LOOPBACK> mtu 16436 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
# dive /var/run/qqq.socket bash
# # Now we are inside that unshare
# ip link set lo up
# exit
exit
# # outside unshare again
# dive /var/run/qqq.socket bash
# ip addr
1218: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
# # our network configuration persisted
Use dived socket --unshare net
instead of unshare -n dived socket
on kernels around v2.6.32.
Network turn off switch
Let users start programs with network access disabled.
# umask 0000
# unshare -n -- dived /var/run/qqq2.socket -d
$ dive /var/run/qqq2.socket bash
$ ping 127.0.0.1
connect: Network is unreachable
$ id
$ uid=1000(vi) gid=1000(vi) groups=1000(vi),20(dialout),21(fax),...
"Poor man's sudo" example 1
Grant Alice access to Bob.
root# dived /var/run/alice2bob -d -C 700 -U alice:alice -u bob
alice$ HOME=/home/bob USER=bob dive /var/run/alice2bob bash
bob$ id
uid=1037(bob) gid=1045(bob) groups=1045(bob),1033(ololo)
bob$ exit
alice$
malice$ dive /var/run/alice2bob bash
connect: Permission denied
Poor man's suid-bit-less sudo example 2
Allow certain users execute certain programs (script in some directory) as root. Use client's command line arguments and filehandles, but not environment variables, current directory or controlling tty.
root# dived /var/run/suidless_sudo --detach --user root --no-csctty --chmod 777 --no-environment --no-chdir --no-umask -- /root/scripts/suidless_sudo
root# cat /root/scripts/suidless_sudo
#!/usr/bin/perl -w
use strict;
die("No script specified") if $#ARGV == -1;
my $script = $ARGV[0];
my $user = $ENV{"DIVE_USER"};
die ("No user") unless $user;
die ("Forbidden") unless $user eq "alice";
die ("Bad script name $script") unless ($script =~ /^([a-zA-Z0-9_]{1,64})$/);
exec "/root/scripts/allowed_scripts/$1"
alice$ dive /var/run/suidless_sudo ../../../bin/bash
Bad script name at /root/scripts/suidless_sudo line 8.
alice$ dive /var/run/suidless_sudo reboot
Reboot started
bob$ dive /var/run/suidless_sudo reboot
Forbidden at /root/scripts/suidless_sudo line 7.
bob$ DIVE_USER=alice dive /var/run/suidless_sudo reboot
Forbidden at /root/scripts/suidless_sudo line 7.
Ping without suidbit example 1
Allow users access to ping (but not to ping -f
) without suidbit:
root# cp /bin/ping /root/ping # loses suidbit
root# dived /var/run/pinger --detach --effective-user root --chmod 777 --no-environment --no-chdir -- /root/ping
alice$ dive /var/run/pinger 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_req=1 ttl=64 time=0.163 ms
64 bytes from 127.0.0.1: icmp_req=2 ttl=64 time=0.108 ms
^C
--- 127.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.108/0.135/0.163/0.029 ms
dive: Something failed with the server
alice$ dive /var/run/pinger -f 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
ping: cannot flood; minimal interval, allowed for user, is 200ms
Ping without suidbit example 2
Like previous one, but with minimal necessary capabilities for ping:
root# cp /bin/ping /root/ping
root# setcap =ei /root/ping
root# dived /var/run/pinger --detach --chmod 777 \
--no-environment --no-chdir \
--no-new-privs --set-capabilities cap_net_raw+ip -B cap_net_raw \
-- /root/ping
Authentication example
dived supports starting external programs for authentication. The program is started when file descriptors are already received from client, but environtment, controlling terminal (if any), root and current directories, user and umask are still original. Nonzero exit code from authentication program rejects the client.
root# dived @boblogin --detach --user bob --authenticate 'user=bob /root/askpassword' -- bash
alice$ HOME=/home/bob dive @boblogin
bob's Password:
bob$ exit
alice$ dive @boblogin
bob's Password:
Go away! (('Authentication failure', 7))
dive: Something failed with the server
alice$
"@boblogin" is abstract UNIX socket. "askpassword" program is included in source repository (uses python-pam).
Note that dived does not fully "login" user. It does not use PAM or set resource limits per `/etc/security/limits.conf` for example...
"Just run" example
There are many options in dived that affect what happens before the program begin execve'd. --just-execute option allow use them without messing with UNIX sockets.
In this mode dived works as poor man's:
- su : --user and/or --effective-user options
- chroot : --chroot option
- daemon : --children-daemon option
- capsh : --retain-capabilities/--remove-capabilities and --set-capabilities
- unshare : --unshare option
Remove ability to start suid-bit things
root# dived -J -S -T -X -- bash
root# su -l alice
alice$ ping 127.0.0.1
ping: icmp open socket: Operation not permitted
If you want just this feature without everything else from dive, use this: https://gist.github.com/vi/f977cc3097d47b07c3ad
Starting ping from user "nobody" with only cap_net_raw
root# setcap =ei /root/ping
root# dived -J -S -T -u nobody -X -c "= cap_net_raw+ip" -- /root/ping 127.0.0.1
Grant capability for opening port lower than 1024
Selectively enable particular capability for user/shell without messing with filesystem capabilities
It uses ambient capabilities which should be available starting from Linux 4.3
root# HOME=/home/vi USER=vi dived --just-execute \
--no-setsid --no-csctty \
--set-capabilities CAP_NET_BIND_SERVICE+ip \
--ambient-capabilities CAP_NET_BIND_SERVICE \
--user vi \
-- /bin/bash
vi$ cat /proc/self/status | grep Cap
CapInh: 0000000000000400
CapPrm: 0000000000000400
CapEff: 0000000000000400
CapBnd: 0000003fffffffff
CapAmb: 0000000000000400
vi$ nc -nvlp 1
listening on [any] 1 ...
^C
Starting another "init"
# usldived -J -S -T -P --unshare pid,fs -- /bin/bash
# mount -t proc proc /proc
bash: child setpgid (8275 to 8275): No such process
# ps aux
bash: child setpgid (8369 to 8369): No such process
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.0 4628 1904 pts/13 S 04:48 0:00 /bin/bash
root 5 0.0 0.0 4184 1100 pts/13 R+ 04:48 0:00 ps aux
# exit
#
inetd setup
dived can be called from inetd instead of opening the socket itself.
root# cat >> /etc/inetd.conf << EOF
/var/run/nobody.dive stream unix nowait nobody /usr/bin/dived dived -i -P
/var/run/shutdown.dive stream unix nowait root /usr/bin/dived dived -i -e root -T -E -A -H -O -M -- /sbin/shutdown -h now
EOF
root# /etc/init.d/openbsd-inetd reload
and everybody who can acess /var/run/*.dive
can shutdown the system (but not cancel the shutdown) or execute any commands from "nobody" user.
Pre-built binaries
Old versions, not all features may be present.14K | Download pre-built x86 dive |
26K | Download pre-built x86 dived |
34K | Download pre-built x86 static dive |
64K | Download pre-built x86 static dived (no capabilities support) |
11K | Download pre-built amd64 static dive |
24K | Download pre-built amd64 static dived (no capabilities support) |
33K | Download pre-built ARMel static dive |
48K | Download pre-built ARMel static dived (no capabilities support) |
25K | Download pre-built x86 Debian wheezy package |
27K | Download pre-built i386 Debian squeeze package |
27K | Download pre-built amd64 Debian squeeze package |
27K | Download pre-built armel Debian squeeze package |
You can also connect my debian repository for a source dive package:
gpg --keyserver pgp.mit.edu --recv 0xF30DBAED1DE672D2 && gpg --export F30DBAED1DE672D2 | apt-key add -
cat >> /etc/apt/sources.list.d/vi.list << \EOF
deb-src http://vi-server.org/debian vi vi
EOF
apt-get update -o Dir::Etc::sourcelist=sources.list.d/vi.list -o Dir::Etc::sourceparts=- -o APT::Get::List-Cleanup=0
apt-get source dive
apt-get build-dep dive
cd dive-*
dpkg-buildpackage -us -uc
dpkg -i ../dive*.deb