Skip to content

Commit 7d5567a

Browse files
committed
Fix macOS IPC cleanup using sysctl: shared memory segments
In Linux, IPC objects are automatically cleaned up when the IPC namespace is destroyed. On Darwin, since there are no IPC namespaces, the IPC objects may sometimes persist after the build user's processes are killed. This patch modifies the cleanup logic to use sysctl calls to identify and remove left over shm segments associated with the build user. Fixes: #12548
1 parent 3ed42cd commit 7d5567a

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

src/libstore/unix/build/darwin-derivation-builder.cc

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,27 @@
33
# include <spawn.h>
44
# include <sys/sysctl.h>
55
# include <sandbox.h>
6+
# include <sys/ipc.h>
7+
# include <sys/shm.h>
68

79
/* This definition is undocumented but depended upon by all major browsers. */
810
extern "C" int
911
sandbox_init_with_parameters(const char * profile, uint64_t flags, const char * const parameters[], char ** errorbuf);
1012

13+
/* Darwin IPC cleanup structures and constants */
14+
# define IPCS_MAGIC 0x00000001
15+
# define IPCS_SHM_ITER 0x00000002
16+
# define IPCS_SHM_SYSCTL "kern.sysv.ipcs.shm"
17+
18+
struct IPCS_command
19+
{
20+
uint32_t ipcs_magic;
21+
uint32_t ipcs_op;
22+
uint32_t ipcs_cursor;
23+
uint32_t ipcs_datalen;
24+
void * ipcs_data;
25+
};
26+
1127
namespace nix {
1228

1329
struct DarwinDerivationBuilder : DerivationBuilderImpl
@@ -204,6 +220,44 @@ struct DarwinDerivationBuilder : DerivationBuilderImpl
204220
posix_spawn(
205221
NULL, drv.builder.c_str(), NULL, &attrp, stringsToCharPtrs(args).data(), stringsToCharPtrs(envStrs).data());
206222
}
223+
224+
void cleanupSysVIPCForUser(uid_t uid)
225+
{
226+
struct IPCS_command ic;
227+
struct shmid_ds shm_ds;
228+
size_t ic_size = sizeof(ic);
229+
230+
ic.ipcs_magic = IPCS_MAGIC;
231+
ic.ipcs_op = IPCS_SHM_ITER;
232+
ic.ipcs_cursor = 0;
233+
ic.ipcs_data = &shm_ds;
234+
ic.ipcs_datalen = sizeof(shm_ds);
235+
236+
while (true) {
237+
memset(&shm_ds, 0, sizeof(shm_ds));
238+
239+
if (sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size) != 0) {
240+
break;
241+
}
242+
243+
if (shm_ds.shm_perm.uid == uid) {
244+
int shmid = shmget(shm_ds.shm_perm._key, 0, 0);
245+
if (shmid != -1) {
246+
if (shmctl(shmid, IPC_RMID, NULL) == 0)
247+
debug("removed shared memory segment with shmid %d (key: 0x%x)", shmid, shm_ds.shm_perm._key);
248+
}
249+
}
250+
}
251+
}
252+
253+
void killSandbox(bool getStats) override
254+
{
255+
DerivationBuilderImpl::killSandbox(getStats);
256+
if (buildUser) {
257+
auto uid = buildUser->getUID();
258+
cleanupSysVIPCForUser(uid);
259+
}
260+
}
207261
};
208262

209263
} // namespace nix

0 commit comments

Comments
 (0)