Linux ns 5. IPC Namespace 详解
文章目录
- 1. 简介
- 2. 源码分析
- 2.1 copy_ipcs()
- 2.2 ipcget()
- 2.3 ipc_check_perms()
- 2.4 相关系统调用
- 参考文档:
1. 简介
进程间通讯的机制称为 IPC(Inter-Process Communication)。Linux 下有多种 IPC 机制:管道(PIPE)、命名管道(FIFO)、信号(Signal)、消息队列(Message queues)、信号量(Semaphore)、共享内存(Share Memory)、内存映射(Memory Map)、套接字(Socket)。
其中的三种消息队列(Message queues)、信号量(Semaphore)、共享内存(Share Memory)被称为 XSI IPC,他们源自于 UNIX System V IPC。
Linux 的 IPC Namespace 主要就是针对 XSI IPC 的,和其他 IPC 机制无关。
我们用简单操作来熟悉一下 IPC Namespace 的概念:
1、查看普通进程的 IPC namespace :
pwl@ubuntu:~$ sudo ls -l /proc/$$/ns
[sudo] password for pwl:
total 0
lrwxrwxrwx 1 root root 0 3月 14 10:53 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 3月 14 10:53 ipc -> 'ipc:[4026531839]'
lrwxrwxrwx 1 root root 0 3月 14 10:53 mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 root root 0 3月 14 10:53 net -> 'net:[4026531993]'
lrwxrwxrwx 1 root root 0 3月 14 10:53 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 3月 14 10:53 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 3月 14 10:53 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 3月 14 10:53 uts -> 'uts:[4026531838]'
pwl@ubuntu:~$ ipcs------ Message Queues --------
key msqid owner perms used-bytes messages ------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 262144 pwl 600 67108864 2 dest
0x00000000 360449 pwl 600 524288 2 dest ------ Semaphore Arrays --------
key semid owner perms nsems pwl@ubuntu:~$
2、创建新的 IPC namespace 并查看:
pwl@ubuntu:~$ sudo unshare --ipc
[sudo] password for pwl:
root@ubuntu:~#
root@ubuntu:~# ls -l /proc/$$/ns
total 0
lrwxrwxrwx 1 root root 0 3月 14 10:55 cgroup -> 'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 3月 14 10:55 ipc -> 'ipc:[4026532643]'
lrwxrwxrwx 1 root root 0 3月 14 10:55 mnt -> 'mnt:[4026531840]'
lrwxrwxrwx 1 root root 0 3月 14 10:55 net -> 'net:[4026531993]'
lrwxrwxrwx 1 root root 0 3月 14 10:55 pid -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 3月 14 10:55 pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 3月 14 10:55 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 3月 14 10:55 uts -> 'uts:[4026531838]'
root@ubuntu:~# ipcs------ Message Queues --------
key msqid owner perms used-bytes messages ------ Shared Memory Segments --------
key shmid owner perms bytes nattch status ------ Semaphore Arrays --------
key semid owner perms nsems root@ubuntu:~#
2. 源码分析
2.1 copy_ipcs()
在进程创建或者 unshare()/setns() 系统调用时,如果设置了 CLONE_NEWIPC
标志会调用 copy_ipcs() 创建一个新的 IPC namespace。其中的核心是创建一个新的 struct ipc_namespace
结构,相当于创建了一个新的 XSI IPC 域:
copy_ipcs() → create_ipc_ns():static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,struct ipc_namespace *old_ns)
{struct ipc_namespace *ns;struct ucounts *ucounts;int err;err = -ENOSPC;ucounts = inc_ipc_namespaces(user_ns);if (!ucounts)goto fail;err = -ENOMEM;/* (1) 分配新的ipc_namespace数据结构 */ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);if (ns == NULL)goto fail_dec;err = ns_alloc_inum(&ns->ns);if (err)goto fail_free;ns->ns.ops = &ipcns_operations;refcount_set(&ns->count, 1);ns->user_ns = get_user_ns(user_ns);ns->ucounts = ucounts;/* (2) 初始化信号量sem对应的idr池和一些参数 */err = sem_init_ns(ns);if (err)goto fail_put;/* (3) 初始化消息msg对应的idr池和一些参数 */err = msg_init_ns(ns);if (err)goto fail_destroy_sem;/* (4) 初始化共享内存shm对应的idr池和一些参数 */err = shm_init_ns(ns);if (err)goto fail_destroy_msg;/* (5) 初始化消息队列mq对应的一些参数 */err = mq_init_ns(ns);if (err)goto fail_destroy_shm;return ns;
}
2.2 ipcget()
三种 XSI IPC 的实现机制也是非常类似的,IPC namespace 提供了对应的3个 idr 池 ns->ids[3]
,每新建一个 XSI IPC 对象,会从对应的 idr 池中分配一个 key
。
以信号量 sem 为例,来分析一下这个过程:
SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
{struct ipc_namespace *ns;/* (1) 构造 ipc_ops 参数 */static const struct ipc_ops sem_ops = {.getnew = newary,.associate = sem_security,.more_checks = sem_more_checks,};struct ipc_params sem_params;/* (2) 构造 ipc namespace 参数 */ns = current->nsproxy->ipc_ns;if (nsems < 0 || nsems > ns->sc_semmsl)return -EINVAL;/* (3) 构造 ipc_params 参数 */sem_params.key = key;sem_params.flg = semflg;sem_params.u.nsems = nsems;/* (4) 根据key查询已有的ipcp,或者创建新的ipcp */return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
}↓ipcget() → ipcget_public()↓static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,const struct ipc_ops *ops, struct ipc_params *params)
{struct kern_ipc_perm *ipcp;int flg = params->flg;int err;/** Take the lock as a writer since we are potentially going to add* a new entry + read locks are not "upgradable"*/down_write(&ids->rwsem);/* (4.1) 根据key在信号量 idr 池 `ns->ids[IPC_SEM_IDS]`中查找对应的ipcp */ipcp = ipc_findkey(ids, params->key);if (ipcp == NULL) {/* key not used */if (!(flg & IPC_CREAT))err = -ENOENT;else/* (4.2) 如果key对应的ipcp不存在,且设置了IPC_CREAT标志则根据key创建一个新的ipcp*/err = ops->getnew(ns, params);} else {/* ipc object has been locked by ipc_findkey() */if (flg & IPC_CREAT && flg & IPC_EXCL)err = -EEXIST;else {err = 0;/* (4.3) 如果key对应的ipcp存在,则针对参数进行第一步的检查 */if (ops->more_checks)err = ops->more_checks(ipcp, params);if (!err)/** ipc_check_perms returns the IPC id on* success*//* (4.4) ipcp存在,针对参数做第二步的权限检查 */err = ipc_check_perms(ns, ipcp, ops, params);}ipc_unlock(ipcp);}up_write(&ids->rwsem);return err;
}↓ops->getnew() → newary()↓static int newary(struct ipc_namespace *ns, struct ipc_params *params)
{int retval;struct sem_array *sma;key_t key = params->key;int nsems = params->u.nsems;int semflg = params->flg;int i;if (!nsems)return -EINVAL;if (ns->used_sems + nsems > ns->sc_semmns)return -ENOSPC;/* (4.2.1) 分配nsems个信号量的数据结构sem_array[] */sma = sem_alloc(nsems);if (!sma)return -ENOMEM;/* (4.2.2) 初始化其中的ipcp成员,保存UGO模式,保存对应的key */sma->sem_perm.mode = (semflg & S_IRWXUGO);sma->sem_perm.key = key;sma->sem_perm.security = NULL;retval = security_sem_alloc(sma);if (retval) {kvfree(sma);return retval;}for (i = 0; i < nsems; i++) {INIT_LIST_HEAD(&sma->sems[i].pending_alter);INIT_LIST_HEAD(&sma->sems[i].pending_const);spin_lock_init(&sma->sems[i].lock);}sma->complex_count = 0;sma->use_global_lock = USE_GLOBAL_LOCK_HYSTERESIS;INIT_LIST_HEAD(&sma->pending_alter);INIT_LIST_HEAD(&sma->pending_const);INIT_LIST_HEAD(&sma->list_id);sma->sem_nsems = nsems;sma->sem_ctime = ktime_get_real_seconds();/* ipc_addid() locks sma upon success. *//* (4.2.3) 赋值 ipcp 中的 uid、gid 并将新分配的ipcp加入信号量 idr 池 `ns->ids[IPC_SEM_IDS]`中*/retval = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);if (retval < 0) {call_rcu(&sma->sem_perm.rcu, sem_rcu_free);return retval;}ns->used_sems += nsems;sem_unlock(sma, -1);rcu_read_unlock();return sma->sem_perm.id;
}↓int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int limit)
{kuid_t euid;kgid_t egid;int id, err;if (limit > IPCMNI)limit = IPCMNI;if (!ids->tables_initialized || ids->in_use >= limit)return -ENOSPC;idr_preload(GFP_KERNEL);refcount_set(&new->refcount, 1);spin_lock_init(&new->lock);new->deleted = false;rcu_read_lock();spin_lock(&new->lock);/* (4.2.3.1) 获取当前进程的uid/gid,赋值给 ipcp 的相关成员,类似文件的 `chown uid:gid ` 操作*/current_euid_egid(&euid, &egid);new->cuid = new->uid = euid;new->gid = new->cgid = egid;id = ipc_idr_alloc(ids, new);idr_preload_end();/* (4.2.3.2) 加入信号量 idr 池 `ns->ids[IPC_SEM_IDS]`中 */if (id >= 0 && new->key != IPC_PRIVATE) {err = rhashtable_insert_fast(&ids->key_ht, &new->khtnode,ipc_kht_params);if (err < 0) {idr_remove(&ids->ipcs_idr, id);id = err;}}if (id < 0) {spin_unlock(&new->lock);rcu_read_unlock();return id;}ids->in_use++;if (id > ids->max_id)ids->max_id = id;new->id = ipc_buildid(id, ids, new);return id;
}
2.3 ipc_check_perms()
从上一节可以看到 key 被包含在 ipcp 即 struct kern_ipc_perm
结构中:
struct kern_ipc_perm {spinlock_t lock;bool deleted;int id;key_t key;kuid_t uid;kgid_t gid;kuid_t cuid;kgid_t cgid;umode_t mode;unsigned long seq;void *security;struct rhash_head khtnode;struct rcu_head rcu;refcount_t refcount;
} ____cacheline_aligned_in_smp __randomize_layout;
在 sem,shm,mq 对象中都有这个成员的存在:
struct sem_array {struct kern_ipc_perm sem_perm; /* permissions .. see ipc.h */...
}struct shmid_kernel /* private to the kernel */
{ struct kern_ipc_perm shm_perm;...
} struct msg_queue {struct kern_ipc_perm q_perm;...
}
struct kern_ipc_perm
的 ->key
成员保存了key值;->mode
成员保存了 UGO 操作权限,类似文件的 chmod 777
属性;->uid/gid/cuid/cgid
成员保存了属主 uid/gid,类似文件的 chown uid:gid
操作。
在 ipc_check_perms() 函数中,会对被操作的 sem,shm,mq 对象,进行 UGO 权限检查:
ipc_check_perms() → ipcperms()↓int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
{kuid_t euid = current_euid();int requested_mode, granted_mode;audit_ipc_obj(ipcp);/* (1) 或 请求的 UGO 操作 */requested_mode = (flag >> 6) | (flag >> 3) | flag;/* (2) 获取 ipcp 的 UGO 规则 */granted_mode = ipcp->mode;/* (2.1) 如果当前进程 和 ipcp 对象 uid 相等,则取用 U 规则 */if (uid_eq(euid, ipcp->cuid) ||uid_eq(euid, ipcp->uid))granted_mode >>= 6;/* (2.2) 如果当前进程 和 ipcp 对象 gid 相等,则取用 G 规则 */else if (in_group_p(ipcp->cgid) || in_group_p(ipcp->gid))granted_mode >>= 3;/* (2.3) 如果当前进程 和 ipcp 对象 uid gid 都不相等,则取用 O 规则 *//* is there some bit set in requested_mode but not in granted_mode? *//* (3) 判断请求的操作是否适配对应的规则 */if ((requested_mode & ~granted_mode & 0007) &&!ns_capable(ns->user_ns, CAP_IPC_OWNER))return -1;return security_ipc_permission(ipcp, flag);
}
2.4 相关系统调用
sem,shm,mq 对象通用部分的解析如上所示,除此以外 XSI IPC 还有其他的操作系统调用,这里就不一一解析:
Module | Syscall | Descript |
---|---|---|
sem | semget() | 创建信号量 |
- | semctl() | 初始化信号量 |
- | semop() | 信号量的PV操作 |
msg | msgget() | 创建消息队列 |
- | msgctl() | 获取和设置消息队列的属性 |
- | msgsnd() | 将消息写入到消息队列 |
- | msgrcv() | 从消息队列读取消息 |
shm | shmget() | 创建共享内存对象 |
- | shmctl() | 共享内存管理 |
- | shmat() | 把共享内存区对象映射到调用进程的地址空间 |
- | shmdt() | 断开共享内存连接 |
参考文档:
1.ipc_namespace
2.Linux内核命名空间之(2) ipc namespace
3.linux进程间通信(IPC)机制总结
4.POSIX:XSI Interprocess Communication
Linux ns 5. IPC Namespace 详解相关推荐
- Linux ns 3. Mnt Namespace 详解
1. 文件系统层次化 对 Linux 系统来说一切皆文件,Linux 使用树形的层次化结构来管理所有的文件对象. 完整的Linux文件系统,是由多种设备.多种文件系统组成的一个混合的树形结构.我们首先 ...
- linux服务器怎么查看cpu配置信息,linux服务器cpu信息查看详解
在linux系统中,提供了/proc目录下文件,显示系统的软硬件信息.如果想了解系统中CPU的提供商和相关配置信息,则可以查/proc/cpuinfo.但是此文件输出项较多,不易理解.例如我们想获取, ...
- 在Linux中ipcs命令,linux中ipcs命令使用详解
linux中ipcs命令使用详解 用途 报告进程间通信设施状态. 语法 代码如下: ipcs [-mqs] [-abcopt] [-C core] [-N namelist] -m 输出有关共享内存( ...
- 【linux】Valgrind工具集详解(八):Memcheck命令行参数详解
[linux]Valgrind工具集详解(五):命令行详解中不够全,在此专门针对Memcheck工具中的命令行参数做一次详细的解释. Memcheck命令行选项 –leak-check=<no| ...
- linux ps(process status) 命令详解
linux ps(process status) 命令详解 功能说明:报告程序状况. 语 法:ps [-aAcdefHjlmNVwy][acefghLnrsSTuvxX][-C <指令名称> ...
- Linux操作系统上lsof命令详解
Linux操作系统上lsof命令详解 2011-10-08 18:31:31 http://xjsunjie.blog.51cto.com/999372/682865 标签:Linux lsof命令 ...
- linux slocate(secure locate) 命令详解
linux slocate(secure locate) 命令详解 功能说明:查找文件或目录. 语 法:slocate [-u][--help][--version][-d <目录>][查 ...
- (传送门)linux命令总结dd命令详解
linux命令总结dd命令详解 https://www.cnblogs.com/ginvip/p/6370836.html 懒癌末期,不想花时间拷贝内容+排版,而且,原文排版就已经很棒了,我在这里只是 ...
- Linux上的free命令详解
Linux上的free命令详解 转自: http://www.cnblogs.com/coldplayerest/archive/2010/02/20/1669949.html 解释一下Linux上f ...
最新文章
- Python爬虫入门教程 54-100 博客园等博客网站自动评论器
- 即刻—你的私人消息定制
- 【干货】产品经理必读:app开发版本迭代的节奏该如何把握?
- 炒菜机器人的弊端_机器人炒菜真不是你想的那样!
- 说明exit()函数作用的程序
- 履带式机器人与轮式机器人的异同分析
- 微信小程序开发资料汇总
- 奇怪的加拿大:一方面大力禁烟,另一方面放松大麻
- Android入门项目(校园软件)
- fluidsim win7版本_FluidSIM 5|FluidSIM(液压气动仿真软件)下载v5.0中文免费版 附安装教程 - 欧普软件下载...
- rtl8211 smi读取_RTL8211E应用(二)之信号输入、输出接口
- python里的平方_python中的平方
- 在家如何访问公司电脑文件和服务器的共享文件夹
- orc识别 语音识别 云真机 内网穿透快速调研
- matlab dwt函数应用,MATLAB中关于DCT,DFT和DWT的相关函数
- iOS开发-汤姆猫Tom(序列帧动画)附详细注释
- 为什么要用Handler
- Excel 2010 SQL应用117 分组统计之GROUP BY 与First
- veek-soc-iii_所以您想使用招聘人员第III部分-警告
- 银河麒麟连不上网怎么办