Skip to content

Commit 4f85cfe

Browse files
committed
fix(darwin): extend IPC cleanup to message queues and semaphores
Previously, only shared memory segments were cleaned up. This could lead to leaked message queues and semaphore sets when builds use System V IPC, exhausting kernel IPC limits over time. This commit extends the cleanup to all three System V IPC types: 1. Shared memory segments 2. Message queues 3. Semaphores Additionally, we stop removing IPC objects during iteration, as it could corrupt the kernel's iterator state and cause some objects to be skipped. The new implementation uses a two-pass approach where we list first and then remove them in a separate pass. The IPC IDs are now extracted during iteration using actual system calls (shmget, msgget, semget) rather than being looked up later, ensuring the objects exist when we capture their IDs.
1 parent 7d5567a commit 4f85cfe

File tree

1 file changed

+90
-18
lines changed

1 file changed

+90
-18
lines changed

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

Lines changed: 90 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,23 @@
55
# include <sandbox.h>
66
# include <sys/ipc.h>
77
# include <sys/shm.h>
8+
# include <sys/msg.h>
9+
# include <sys/sem.h>
810

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

13-
/* Darwin IPC cleanup structures and constants */
15+
/* Darwin IPC structures and constants */
1416
# define IPCS_MAGIC 0x00000001
1517
# define IPCS_SHM_ITER 0x00000002
18+
# define IPCS_SEM_ITER 0x00000020
19+
# define IPCS_MSG_ITER 0x00000200
1620
# define IPCS_SHM_SYSCTL "kern.sysv.ipcs.shm"
21+
# define IPCS_MSG_SYSCTL "kern.sysv.ipcs.msg"
22+
# define IPCS_SEM_SYSCTL "kern.sysv.ipcs.sem"
1723

18-
struct IPCS_command
24+
struct IpcsCommand
1925
{
2026
uint32_t ipcs_magic;
2127
uint32_t ipcs_op;
@@ -223,31 +229,97 @@ struct DarwinDerivationBuilder : DerivationBuilderImpl
223229

224230
void cleanupSysVIPCForUser(uid_t uid)
225231
{
226-
struct IPCS_command ic;
227-
struct shmid_ds shm_ds;
232+
struct IpcsCommand ic;
228233
size_t ic_size = sizeof(ic);
234+
// IPC ids to cleanup
235+
std::vector<int> shm_ids, msg_ids, sem_ids;
236+
237+
{
238+
struct shmid_ds shm_ds;
239+
ic.ipcs_magic = IPCS_MAGIC;
240+
ic.ipcs_op = IPCS_SHM_ITER;
241+
ic.ipcs_cursor = 0;
242+
ic.ipcs_data = &shm_ds;
243+
ic.ipcs_datalen = sizeof(shm_ds);
244+
245+
while (true) {
246+
memset(&shm_ds, 0, sizeof(shm_ds));
247+
248+
if (sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size) != 0) {
249+
break;
250+
}
251+
252+
if (shm_ds.shm_perm.uid == uid) {
253+
int shmid = shmget(shm_ds.shm_perm._key, 0, 0);
254+
if (shmid != -1) {
255+
shm_ids.push_back(shmid);
256+
}
257+
}
258+
}
259+
}
229260

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);
261+
for (auto id : shm_ids) {
262+
if (shmctl(id, IPC_RMID, NULL) == 0)
263+
debug("removed shared memory segment with shmid %d", id);
264+
}
265+
266+
{
267+
struct msqid_ds msg_ds;
268+
ic.ipcs_magic = IPCS_MAGIC;
269+
ic.ipcs_op = IPCS_MSG_ITER;
270+
ic.ipcs_cursor = 0;
271+
ic.ipcs_data = &msg_ds;
272+
ic.ipcs_datalen = sizeof(msg_ds);
235273

236-
while (true) {
237-
memset(&shm_ds, 0, sizeof(shm_ds));
274+
while (true) {
275+
memset(&msg_ds, 0, sizeof(msg_ds));
238276

239-
if (sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size) != 0) {
240-
break;
277+
if (sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size) != 0) {
278+
break;
279+
}
280+
281+
if (msg_ds.msg_perm.uid == uid) {
282+
int msgid = msgget(msg_ds.msg_perm._key, 0);
283+
if (msgid != -1) {
284+
msg_ids.push_back(msgid);
285+
}
286+
}
241287
}
288+
}
289+
290+
for (auto id : msg_ids) {
291+
if (msgctl(id, IPC_RMID, NULL) == 0)
292+
debug("removed message queue with msgid %d", id);
293+
}
294+
295+
{
296+
struct semid_ds sem_ds;
297+
ic.ipcs_magic = IPCS_MAGIC;
298+
ic.ipcs_op = IPCS_SEM_ITER;
299+
ic.ipcs_cursor = 0;
300+
ic.ipcs_data = &sem_ds;
301+
ic.ipcs_datalen = sizeof(sem_ds);
302+
303+
while (true) {
304+
memset(&sem_ds, 0, sizeof(sem_ds));
242305

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);
306+
if (sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size) != 0) {
307+
break;
308+
}
309+
310+
if (sem_ds.sem_perm.uid == uid) {
311+
int semid = semget(sem_ds.sem_perm._key, 0, 0);
312+
if (semid != -1) {
313+
sem_ids.push_back(semid);
314+
}
248315
}
249316
}
250317
}
318+
319+
for (auto id : sem_ids) {
320+
if (semctl(id, 0, IPC_RMID) == 0)
321+
debug("removed semaphore with semid %d", id);
322+
}
251323
}
252324

253325
void killSandbox(bool getStats) override

0 commit comments

Comments
 (0)