A Note on SYSVIPC and Jails on FreeBSD


The previous blogpost on jails claimed that there were “known problems” with allowing sysvipc inside jails on FreeBSD and called out postgres as a programm that requires allow.sysvipc when run inside a jail, which creates security problems. As it turns out, the release of FreeBSD-11 has seen improvements in the way sysvipc can be used in jails and it seems worthwile to take a quick look at this.

If even a quick look is too much time for you, here’s an even shorter TL;DR:

Don’t use allow.sysvipc=1, instead set sysvmsg, sysvsem and sysvshm to "new", if you need to use sysvipc inside a jail.

The “Classic” Situation:

By default, jails do not permit any of the sysvipc mechanisms available on a usual FreeBSD system. The reason for this is that access to sysvipc permits a jail to access the global (system-wide) sysvipc space. The only thing that prevents a program in one jail to access the shared sysv ressources of another jail (or even the host system itself) is the UID of the processes (as far as the author can tell). This means that the only way to securely run apps that require sysvipc inside jails is to ensure that they have uids different from any other user on the systems.

This collides with the fact that packages (such as the postgres-package) usually create system users with the same uid/gid everywhere. Hence, running different instances of such a programm without creating extra user accounts may have security consequences down the road.

Releases prior to 10.4 and 11 had one simple option to enable sysvipc in jails:

allow.sysvipc = 1;

While this can be set on a per-jail basis, it still suffers from the shortcomings described above.

Example:

If we have postgres running inside a jail, then running ipcs would show something like:

pgsql01 / # ipcs
Message Queues:
T           ID          KEY MODE        OWNER    GROUP

Shared Memory:
T           ID          KEY MODE        OWNER    GROUP
m        65536      5432001 --rw------- postgres postgres

Semaphores:
T           ID          KEY MODE        OWNER    GROUP

The output on the host would be identical (but the uid/gid would be displayed numerically in absence of the postgres-user in /etc/passwd). If sysvipc has not been enabled for a jail then the same command would show no information in SYSv ressources:

test01 / # ipcs
Message Queues:
T           ID          KEY MODE        OWNER    GROUP

Shared Memory:
T           ID          KEY MODE        OWNER    GROUP

Semaphores:
T           ID          KEY MODE        OWNER    GROUP

However, as soon as we enter a jail where allow.sysvipc has been set to 1 then ipcs would again show all available ressources, even if they belong to a different jail:

test02 / # ipcs
Message Queues:
T           ID          KEY MODE        OWNER    GROUP

Shared Memory:
T           ID          KEY MODE        OWNER    GROUP
m        65536            0 --rw------- postgres postgres

Semaphores:
T           ID          KEY MODE        OWNER    GROUP

SYSVIPC in Modern Jails:

In FreeBSD-11 and (at least according to the manpage in FreeBSD-10.4, the allow.sysvipc option was deprecated in favor of three seperate parameters: sysvmsg, sysvsem and sysvshm, which oddly do not fall in the allow subcategory of options.

These settings allow (again either globally or on a per-jail basis) to enable access to the different IPC ressoures and offer a new configuration option:

sysvshm = ["disable"|"inherit"|"new"];

The default “disable” disables access to this type of ressource. The “inherit” option reflects the old default, where the jail inherits the same IPC “namespace” as the system, resulting in the classic situation described above.

However, setting any of these options to "new" means that the jail will get it’s own namespace for this ressource, which seems to fix any of the problems described above.

Example:

If we have two instances of postgresql, each running inside its own jail, then the “classic” allow.sysvipc-method would yield the following ipcs-output in each of the jails:

pgsql02 / # ipcs
Message Queues:
T           ID          KEY MODE        OWNER    GROUP

Shared Memory:
T           ID          KEY MODE        OWNER    GROUP
m        65536            0 --rw------- postgres postgres
m       589825      5432001 --rw------- postgres postgres

Semaphores:
T           ID          KEY MODE        OWNER    GROUP

With the new method, it suffices to set sysvshm = "new"; for the jails in question. In this case, each jail can only see its own information:

pgsql01 / # ipcs
Message Queues:
T           ID          KEY MODE        OWNER    GROUP

Shared Memory:
T           ID          KEY MODE        OWNER    GROUP
m       131072      5432001 --rw------- postgres postgres

Semaphores:
T           ID          KEY MODE        OWNER    GROUP
pgsql02 / # ipcs
Message Queues:
T           ID          KEY MODE        OWNER    GROUP

Shared Memory:
T           ID          KEY MODE        OWNER    GROUP
m       655361      5432001 --rw------- postgres postgres

Semaphores:
T           ID          KEY MODE        OWNER    GROUP

Interestingly, the host on which the jails are running would still be able to see both “namespaces”:

~ # ipcs
Message Queues:
T           ID          KEY MODE        OWNER    GROUP

Shared Memory:
T           ID          KEY MODE        OWNER    GROUP
m       131072            0 --rw------- 770      770
m       655361            0 --rw------- 770      770

Semaphores:
T           ID          KEY MODE        OWNER    GROUP

Acknowledgements:

The use of sysvshm was first suggested to us by Harald Eilertsen (@harald@quitter.no). Thanks!