1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-08 11:36:03 +01:00

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.
This commit is contained in:
Jean-François Roche 2025-11-04 14:59:41 +00:00
parent 7d5567a8d7
commit 4f85cfe824

View file

@ -5,17 +5,23 @@
# include <sandbox.h>
# include <sys/ipc.h>
# include <sys/shm.h>
# include <sys/msg.h>
# include <sys/sem.h>
/* This definition is undocumented but depended upon by all major browsers. */
extern "C" int
sandbox_init_with_parameters(const char * profile, uint64_t flags, const char * const parameters[], char ** errorbuf);
/* Darwin IPC cleanup structures and constants */
/* Darwin IPC structures and constants */
# define IPCS_MAGIC 0x00000001
# define IPCS_SHM_ITER 0x00000002
# define IPCS_SEM_ITER 0x00000020
# define IPCS_MSG_ITER 0x00000200
# define IPCS_SHM_SYSCTL "kern.sysv.ipcs.shm"
# define IPCS_MSG_SYSCTL "kern.sysv.ipcs.msg"
# define IPCS_SEM_SYSCTL "kern.sysv.ipcs.sem"
struct IPCS_command
struct IpcsCommand
{
uint32_t ipcs_magic;
uint32_t ipcs_op;
@ -223,10 +229,13 @@ struct DarwinDerivationBuilder : DerivationBuilderImpl
void cleanupSysVIPCForUser(uid_t uid)
{
struct IPCS_command ic;
struct shmid_ds shm_ds;
struct IpcsCommand ic;
size_t ic_size = sizeof(ic);
// IPC ids to cleanup
std::vector<int> shm_ids, msg_ids, sem_ids;
{
struct shmid_ds shm_ds;
ic.ipcs_magic = IPCS_MAGIC;
ic.ipcs_op = IPCS_SHM_ITER;
ic.ipcs_cursor = 0;
@ -243,13 +252,76 @@ struct DarwinDerivationBuilder : DerivationBuilderImpl
if (shm_ds.shm_perm.uid == uid) {
int shmid = shmget(shm_ds.shm_perm._key, 0, 0);
if (shmid != -1) {
if (shmctl(shmid, IPC_RMID, NULL) == 0)
debug("removed shared memory segment with shmid %d (key: 0x%x)", shmid, shm_ds.shm_perm._key);
shm_ids.push_back(shmid);
}
}
}
}
for (auto id : shm_ids) {
if (shmctl(id, IPC_RMID, NULL) == 0)
debug("removed shared memory segment with shmid %d", id);
}
{
struct msqid_ds msg_ds;
ic.ipcs_magic = IPCS_MAGIC;
ic.ipcs_op = IPCS_MSG_ITER;
ic.ipcs_cursor = 0;
ic.ipcs_data = &msg_ds;
ic.ipcs_datalen = sizeof(msg_ds);
while (true) {
memset(&msg_ds, 0, sizeof(msg_ds));
if (sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size) != 0) {
break;
}
if (msg_ds.msg_perm.uid == uid) {
int msgid = msgget(msg_ds.msg_perm._key, 0);
if (msgid != -1) {
msg_ids.push_back(msgid);
}
}
}
}
for (auto id : msg_ids) {
if (msgctl(id, IPC_RMID, NULL) == 0)
debug("removed message queue with msgid %d", id);
}
{
struct semid_ds sem_ds;
ic.ipcs_magic = IPCS_MAGIC;
ic.ipcs_op = IPCS_SEM_ITER;
ic.ipcs_cursor = 0;
ic.ipcs_data = &sem_ds;
ic.ipcs_datalen = sizeof(sem_ds);
while (true) {
memset(&sem_ds, 0, sizeof(sem_ds));
if (sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size) != 0) {
break;
}
if (sem_ds.sem_perm.uid == uid) {
int semid = semget(sem_ds.sem_perm._key, 0, 0);
if (semid != -1) {
sem_ids.push_back(semid);
}
}
}
}
for (auto id : sem_ids) {
if (semctl(id, 0, IPC_RMID) == 0)
debug("removed semaphore with semid %d", id);
}
}
void killSandbox(bool getStats) override
{
DerivationBuilderImpl::killSandbox(getStats);