Post

Linux命名空间【IPC】

Linux命名空间【IPC】

什么是 IPC Namespace?

IPC NamespaceLinux内核中的一种命名空间,用于隔离进程间通信资源。它主要隔离以下两类IPC机制:

  • System V IPC:消息队列(msgget)、信号量(semget)、共享内存(shmget
  • POSIX 消息队列

通过 IPC Namespace,不同命名空间中的进程拥有各自独立的 IPC 资源,相互隔离,互不干扰。


IPC Namespace 的作用

  • 实现容器(如 Docker)中进程间通信的隔离,防止容器之间的 IPC 资源冲突
  • 多租户环境中保护资源,提升安全性
  • 支持多个进程组独立管理和清理自己的 IPC 资源

IPC Namespace 的创建与使用

创建 IPC Namespace 通常通过 Linux 系统调用 clone()unshare(),在创建新进程或切换命名空间时指定 CLONE_NEWIPC 标志。


IPC Namespace 示例代码(C 语言)

下面的代码演示:

  1. 创建一个新进程,进入新的 IPC Namespace
  2. 在新的 IPC Namespace 中创建一个 System V 消息队列
  3. 父进程依然在原始 IPC Namespace 中,不能访问子进程的消息队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
c


复制编辑
#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>

#define STACK_SIZE (1024 * 1024)  // 1MB

struct msgbuf {
    long mtype;
    char mtext[100];
};

// 子进程函数:运行在新的 IPC Namespace
int child_func(void *arg) {
    printf("子进程 PID: %d,进入新的 IPC Namespace\n", getpid());

    // 创建消息队列
    int msgid = msgget(IPC_PRIVATE, 0666 | IPC_CREAT);
    if (msgid == -1) {
        perror("msgget");
        return -1;
    }
    printf("子进程创建消息队列 ID: %d\n", msgid);

    // 发送一条消息
    struct msgbuf msg = {1, "Hello from child IPC namespace!"};
    if (msgsnd(msgid, &msg, strlen(msg.mtext) + 1, 0) == -1) {
        perror("msgsnd");
        return -1;
    }
    printf("子进程发送消息成功\n");

    // 等待父进程结束
    sleep(5);

    // 删除消息队列
    if (msgctl(msgid, IPC_RMID, NULL) == -1) {
        perror("msgctl IPC_RMID");
        return -1;
    }
    printf("子进程删除消息队列\n");

    return 0;
}

int main() {
    char *stack = malloc(STACK_SIZE);
    if (!stack) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
    char *stack_top = stack + STACK_SIZE;

    // 创建子进程,使用 CLONE_NEWIPC 创建新的 IPC Namespace
    pid_t child_pid = clone(child_func, stack_top, CLONE_NEWIPC | SIGCHLD, NULL);
    if (child_pid == -1) {
        perror("clone");
        free(stack);
        exit(EXIT_FAILURE);
    }

    printf("父进程 PID: %d,子进程 PID: %d\n", getpid(), child_pid);

    // 父进程等待子进程结束
    waitpid(child_pid, NULL, 0);

    free(stack);
    printf("父进程结束\n");
    return 0;
}

编译运行说明

1
2
3
4
5
6
bash


复制编辑
gcc -o ipc_ns ipc_ns.c
sudo ./ipc_ns

需要 sudo 权限,因为 CLONE_NEWIPC 需要特权。


程序执行效果说明

  • 子进程会进入新的 IPC Namespace,创建一个消息队列,发送消息,并在退出前删除它。
  • 父进程依然在原来的 IPC Namespace,无法访问或看到子进程新建的消息队列。
  • 这验证了 IPC Namespace 的隔离效果。

总结

  • IPC Namespace 让容器或进程组可以独立管理自己的 IPC 资源。
  • 它是实现容器隔离的重要命名空间之一。
  • 使用 cloneunshare 携带 CLONE_NEWIPC 标志即可创建新的 IPC Namespace。
This post is licensed under CC BY 4.0 by the author.