Solved ZFS permission denied in jail with delegated user permissions.

from the jail, postgres user:

Code:
postgres(130)net:~ % zfs list
NAME            USED  AVAIL     REFER  MOUNTPOINT
jail           19.0G  1.74T      104K  /jail
jail/net       5.82G  4.18G     5.63G  /jail/net
jail/net/data   200M  4.18G      200M  /opt/env.d/5432/data
postgres(130)net:~ % zfs allow jail/net/data
---- Permissions on jail/net/data ------------------------------------
Local+Descendent permissions:
        user postgres clone,create,destroy,mount,snapshot
postgres(130)net:~ % zfs snap jail/net/data@5433
postgres(130)net:~ % zfs clone -o mountpoint=/home/postgres jail/net/data@5433 jail/net/data/5433
cannot create 'jail/net/data/5433': permission denied
postgres(130)net:~ % zfs destroy jail/net/data@5433

I have checked the following:

permissions on the mountpoint are postgres
clone command works fine in root
there is a bug from 2018 with a post in 2021: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=232021#add_comment
I did have some issues with inconsistent terminal behavior but i think i solved it by adding this to my devfs.rules:
Code:
add path pts unhide
add path 'pts/*' unhide
add path 'tty*' unhide
add path stdin unhide
add path stdout unhide
add path stderr unhide
add path fd unhide
add path 'fd/*' unhide

I have also tried:
Code:
root(130)net:/ # su - postgres
postgres(130)net:~ % zfs list
NAME            USED  AVAIL     REFER  MOUNTPOINT
jail           19.0G  1.74T      104K  /jail
jail/net       5.82G  4.18G     5.63G  /jail/net
jail/net/data   200M  4.18G      200M  /opt/env.d/5432/data
postgres(130)net:~ % zfs snap jail/net/data@5433
postgres(130)net:~ % zfs clone -o mountpoint=/opt/env.d/5433/data jail/net/data@5433 jail/net/data/5433
cannot create 'jail/net/data/5433': permission denied
postgres(130)net:~ % zfs allow jail/net/data
---- Permissions on jail/net/data ------------------------------------
Local+Descendent permissions:
        user postgres clone,create,destroy,mount,snapshot
postgres(130)net:~ % exit
logout
root(130)net:/ # zfs clone -o mountpoint=/opt/env.d/5433/data jail/net/data@5433 jail/net/data/5433
root(130)net:/ # su - postgres
postgres(130)net:~ % zfs destroy jail/net/data/5433
cannot unmount '/opt/env.d/5433/data': permission denied
postgres(130)net:~ % exit
logout
root(130)net:/ # zfs destroy jail/net/data/5433
root(130)net:/ # su - postgres
postgres(130)net:~ % zfs destroy jail/net/data@5433
 
/etc/sysctl.conf:
Code:
security.bsd.see_jail_proc=0
kern.randompid=1

# jail security
security.bsd.hardlink_check_gid=1
security.bsd.hardlink_check_uid=1
security.bsd.unprivileged_proc_debug=0
security.bsd.see_other_gids=0
security.bsd.see_other_uids=0
security.bsd.unprivileged_read_msgbuf=0   # prevents jails from reading console messages

security.jail.enforce_statfs=1
security.jail.mount_allowed=1
security.jail.mount_zfs_allowed=1
vfs.usermount=1

/etc/jail.conf
Code:
sysvmsg = new;          # prevent security issues with sysv memory being shared across jails and to host
sysvsem = new;          # leave all three uncommented to make sure shared memory is not used
sysvshm = new;          # this one also prevents problems with postgres starting
exec.clean;             # default jails will inherit environment vars from parent. this stops that.
path="/jail/$name";
host.hostname="$name.extendesk.com";
vnet;
vnet.interface="ng0_$name";
exec.start="sh /etc/rc";
exec.stop="sh /etc/rc.shutdown";
exec.prestart="jng bridge $name ix0";
exec.prestop="ifconfig ng0_$name -vnet $name";
exec.poststop="jng shutdown $name";
exec.poststop+="ngctl shutdown ng0_$name";
exec.consolelog="/var/log/$name.jail";
devfs_ruleset="1000"; # vnet rule set

# for zfs data dataset
allow.mount;
allow.mount.zfs;
enforce_statfs=1;
exec.poststart+="zfs jail $name jail/$name/data";
exec.poststop+="zfs unjail $name jail/$name/data";

net {host.hostname = "net.wfprod.com";
        allow.raw_sockets;
        allow.socket_af;}
n131 {}
 
zfs-allow should work, but maybe no one ever does this so this bug didn't get fixed.

I'm putting all my processes in an unprivileged user inside a jail. Do people just run jailed processes as root?

Postgres doesn't run as root so maybe I just can't do what I am trying to do.
 
ok, I added "mountpoint" as a permission and it allowed me to clone the snapshot.

However, it now shows "cannot mount 'jail/net/data/5433': Insufficient privileges"

Code:
root(130)net:/ # zfs allow -u postgres clone,create,destroy,mount,mountpoint,snapshot jail/net/data
root(130)net:/ # su - postgres
postgres(130)net:~ % zfs list -t snap
no datasets available
postgres(130)net:~ % zfs snap jail/net/data@5433
postgres(130)net:~ % zfs clone -o mountpoint=/opt/env.d/5433/data jail/net/data@5433 jail/net/data/5433
cannot mount 'jail/net/data/5433': Insufficient privileges
filesystem successfully created, but not mounted
postgres(130)net:~ % zfs mount jail/net/data/5433
cannot mount 'jail/net/data/5433': Insufficient privileges
 
ok, so having read man jail section enforce_statfs and section allow.mount.zfs it would appear that only priviledged users are allowed to do certain things regardless of zfs permissions. Upon first read i guess i thought they were talking about permissions, but now i think they were talking about root/wheel permissions.

I feel like this should be mentioned in man zfs-jail but I'll put it here.

My solution was to install /etc/sudoers and add the following line:
postgres ALL=NOPASSWD: /sbin/zfs

I execute all zfs commands with "sudo zfs ..." then I'm able to take advantage of all zfs permissions from a delegated, unprivileged user.

I have confirmed that I still cannot create a dataset outside of my permissions so it all seems to work securely.

of course another solution might be to add user to wheel but I needed to use zfs in a script.
 
Back
Top