From 7284d55db2c912e86c4c3effdfb2a9c4b198707b Mon Sep 17 00:00:00 2001 From: "Christian S.J. Peron" Date: Fri, 13 Nov 2026 01:16:37 -0500 Subject: [PATCH] Add support for sysv ipc --- README.md | 15 +++++++++++++++ src/cblock/launch.c | 9 ++++++++- .../fixtures/launchWithPseudoFs.yaml | 1 + src/cblock_warden/main.go | 4 ++++ src/cblock_warden/parse_test.go | 1 + src/cblockd/dispatch.c | 9 +++++++++ src/include/cblock/libcblock.h | 3 ++- src/libcblock/proto.c | 2 ++ src/shell/stage_launch.sh | 3 ++- 9 files changed, 44 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31174f7..024f740 100644 --- a/README.md +++ b/README.md @@ -510,3 +510,18 @@ cellblock needs a Vault token. Secrets are not available during `cblock build`. Do not put them in the build directory: the whole build context is copied to the cblockd host. + +### SysV shared memory + +Cellblocks cannot use SysV shared memory unless launched with +`--sysvshm` (`sysvshm: true` in the `cblock_warden` manifest). Some +services need it, PostgreSQL among them. The flag gives the jail its own +namespace (`sysvshm=new`): segments created in the cellblock are hidden +from the host's namespace and from other cellblocks, even ones running as +the same user ID. + +The kernel limits (`kern.ipc.shmmni`, `kern.ipc.shmall` and so on) are +shared by the whole system, so one cellblock can use them up for +everyone. With `kern.racct.enable=1` set at boot, RCTL rules such as +`jail::nshm:deny=8` and `jail::shmsize:deny=64m` cap each +cellblock. diff --git a/src/cblock/launch.c b/src/cblock/launch.c index fc8adac..9c945d1 100644 --- a/src/cblock/launch.c +++ b/src/cblock/launch.c @@ -52,6 +52,7 @@ struct launch_config { char *l_tag; char *l_ports; int l_host_networking; + int l_sysvshm; }; static struct option launch_options[] = { @@ -67,6 +68,7 @@ static struct option launch_options[] = { { "verbose", no_argument, 0, 'v' }, { "port", required_argument, 0, 'P' }, { "host-networking", no_argument, 0, 'H' }, + { "sysvshm", no_argument, 0, 'S' }, { 0, 0, 0, 0 } }; @@ -86,6 +88,7 @@ launch_usage(void) " -A, --no-attach Do not attach to container console\n" " -v, --verbose Launch container with verbosity enabled\n" " -H, --host-networking Use host networking instead of NAT/bridge\n" + " -S, --sysvshm Give the container its own SysV shared memory\n" ); exit(1); } @@ -120,6 +123,7 @@ launch_container(int sock, struct launch_config *lcp) vec_free(lcp->l_vec); } pl.p_verbose = lcp->l_verbose; + pl.p_sysvshm = lcp->l_sysvshm; snprintf(pl.p_tag, sizeof(pl.p_tag), "%s", lcp->l_tag); snprintf(pl.p_name, sizeof(pl.p_name), "%s", lcp->l_name); snprintf(pl.p_term, sizeof(pl.p_term), "%s", term); @@ -180,7 +184,7 @@ launch_main(int argc, char *argv [], int ctlsock) reset_getopt_state(); while (1) { option_index = 0; - c = getopt_long(argc, argv, "AHP:vN:Fpn:t:V:T", launch_options, + c = getopt_long(argc, argv, "AHP:vN:Fpn:t:V:TS", launch_options, &option_index); if (c == -1) { break; @@ -189,6 +193,9 @@ launch_main(int argc, char *argv [], int ctlsock) case 'H': lc.l_host_networking = 1; break; + case 'S': + lc.l_sysvshm = 1; + break; case 'P': vec_append(ports, optarg); break; diff --git a/src/cblock_warden/fixtures/launchWithPseudoFs.yaml b/src/cblock_warden/fixtures/launchWithPseudoFs.yaml index c22fe8a..7915449 100644 --- a/src/cblock_warden/fixtures/launchWithPseudoFs.yaml +++ b/src/cblock_warden/fixtures/launchWithPseudoFs.yaml @@ -4,4 +4,5 @@ cellblocks: fdescfs: true procfs: true tmpfs: true + sysvshm: true network: vlan0 diff --git a/src/cblock_warden/main.go b/src/cblock_warden/main.go index be5d31c..aa8f8fa 100644 --- a/src/cblock_warden/main.go +++ b/src/cblock_warden/main.go @@ -62,6 +62,7 @@ type Cellblock struct { Fdescfs bool `yaml:"fdescfs"` Procfs bool `yaml:"procfs"` Tmpfs bool `yaml:"tmpfs"` + Sysvshm bool `yaml:"sysvshm"` Volumes []Volume `yaml:"volumes"` Ports []PortMapping `yaml:"ports"` } @@ -143,6 +144,9 @@ func ProcessManifest(gcfg Config, prog string) ([]CmdVec, error) { if cb.Tmpfs { cmd.AddBool("tmpfs") } + if cb.Sysvshm { + cmd.AddBool("sysvshm") + } if len(cb.Volumes) > 0 { processVolumes(cb.Volumes, &cmd) } diff --git a/src/cblock_warden/parse_test.go b/src/cblock_warden/parse_test.go index b50378e..3c5793b 100644 --- a/src/cblock_warden/parse_test.go +++ b/src/cblock_warden/parse_test.go @@ -125,6 +125,7 @@ func TestLaunchCellblocks(t *testing.T) { "--fdescfs", "--procfs", "--tmpfs", + "--sysvshm", }, }, }, diff --git a/src/cblockd/dispatch.c b/src/cblockd/dispatch.c index 747bab4..f57c276 100644 --- a/src/cblockd/dispatch.c +++ b/src/cblockd/dispatch.c @@ -301,6 +301,15 @@ dispatch_launch_cblock(int sock) sprintf(buf, "CBLOCK_FS=%s", gcfg.c_underlying_fs); vec_append(env_vec, buf); + /* + * --sysvshm gives the jail its own SysV shared memory namespace. + * Without it the jail cannot use SysV shared memory at all. + */ + if (pl.p_sysvshm) { + vec_append(env_vec, "CBLOCK_SYSVSHM=new"); + } else { + vec_append(env_vec, "CBLOCK_SYSVSHM=disable"); + } vec_finalize(env_vec); sprintf(buf, "%s/lib/stage_launch.sh", gcfg.c_data_dir); vec_append(cmd_vec, "/bin/sh"); diff --git a/src/include/cblock/libcblock.h b/src/include/cblock/libcblock.h index fa01ef9..f88cf55 100644 --- a/src/include/cblock/libcblock.h +++ b/src/include/cblock/libcblock.h @@ -71,7 +71,7 @@ enum { * CBLOCK_PROTO_VERSION. Bump the version whenever the wire format changes. */ #define CBLOCK_PROTO_MAGIC 0x43424c4b /* "CBLK" */ -#define CBLOCK_PROTO_VERSION 1 +#define CBLOCK_PROTO_VERSION 2 /* * Maximum size of a single framed message. Console output larger than this @@ -125,6 +125,7 @@ struct cblock_launch { char p_ports[MAX_ARG_STRING]; char p_network[IF_NAMESIZE]; int p_verbose; + int p_sysvshm; }; struct cblock_signal_instance { diff --git a/src/libcblock/proto.c b/src/libcblock/proto.c index 7ff89f3..ab4b2c2 100644 --- a/src/libcblock/proto.c +++ b/src/libcblock/proto.c @@ -169,6 +169,7 @@ launch_enc(struct wire *w, const void *arg) wire_put_str(w, l->p_ports); wire_put_str(w, l->p_network); wire_put_u32(w, l->p_verbose); + wire_put_u32(w, l->p_sysvshm); } static void @@ -184,6 +185,7 @@ launch_dec(struct wire *w, void *arg) wire_get_str(w, l->p_ports, sizeof(l->p_ports)); wire_get_str(w, l->p_network, sizeof(l->p_network)); l->p_verbose = wire_get_int(w); + l->p_sysvshm = wire_get_int(w); } int diff --git a/src/shell/stage_launch.sh b/src/shell/stage_launch.sh index 1f91da2..5cf8d04 100755 --- a/src/shell/stage_launch.sh +++ b/src/shell/stage_launch.sh @@ -511,6 +511,7 @@ do_launch() "vnet.interface=$netif" \ "name=${image_name}-${instance_hostname}" \ "allow.chflags=1" \ + "sysvshm=${CBLOCK_SYSVSHM:-disable}" \ "osrelease=$(emit_os_release)" \ "path=${instance_root}" \ command="$@" @@ -531,7 +532,7 @@ do_launch() fi jailcmd="$jailcmd jail -c host.hostname=${instance_hostname} " jailcmd="$jailcmd name=${image_name}-${instance_hostname} " - jailcmd="$jailcmd allow.chflags=1 path=${instance_root} " + jailcmd="$jailcmd allow.chflags=1 sysvshm=${CBLOCK_SYSVSHM:-disable} path=${instance_root} " jailcmd="$jailcmd $netspec osrelease=$(emit_os_release) command=$@" eval $jailcmd fi