Ubuntu 20.04 LTS下POSIX共享内存重启后留存且归root所有问题
重要通知
问题完全未解决,也并非由拼写错误导致。仅因部分用户无法复现(基于其本地测试环境),并不代表该问题在我的环境中不存在。我可稳定复现问题,仍在寻求解决方案或解释。
如需更多信息,请告知具体需要哪些内容。
演示视频
有演示该问题的短视频可供查看。
原问题
我使用POSIX共享内存在应用的多个实例间共享状态,通过shm_open()创建共享内存,ftruncate()扩展至所需大小,再通过mmap()映射到内存。同时使用sem_open()创建信号量,用于同步共享内存访问并确保首个实例完成初始化。
目前该流程运行正常,共享内存对象显示在/dev/shm/目录下,所有者和权限均符合预期。但在Linux(Ubuntu 20.04 LTS)中出现异常:重启后共享内存对象(及信号量)仍存在!据我所知,共享内存是易失性的,/dev/shm/是基于RAM的tmpfs文件系统,本不应在重启后留存。更糟的是,重启后共享内存的所有者从原用户变为root,导致重启后启动应用时shm_open()因权限拒绝失败!这说明系统关机时存在某种机制将共享内存持久化到磁盘,重启时恢复,但为何所有者会变更导致共享内存无法访问?
注:我在MacOS X和FreeBSD上测试未发现此问题。
我多次测试确认:重启前ls -al /dev/shm显示共享内存(及信号量)的原所有者,重启后则显示root为所有者,期间未运行应用。目前唯一解决办法是重启后执行sudo rm -f /dev/shm/*,但这绝非标准解决方案,Linux下该如何规范处理此问题?
我的代码如下:
static unsigned char *initialize(const int create_shmem) { void *buffer = NULL; int fd = shm_open(OBJECT_NAME, create_shmem ? O_CREAT | O_EXCL | O_RDWR : O_RDONLY, 0644); if (fd < 0) { if ((!create_shmem) && (errno == ENOENT)) { return initialize(1); } else { return NULL; } } if (create_shmem) { if (ftruncate(fd, BUFFER_SIZE) != 0) { goto failure; } } buffer = mmap(NULL, BUFFER_SIZE, create_shmem ? PROT_READ | PROT_WRITE : PROT_READ, MAP_SHARED, fd, 0U); if (buffer == MAP_FAILED) { goto failure; } /* ... */ }
我知道可通过shm_unlink()在重启前显式删除共享内存,这或许能避免问题,但该方式不可靠!若应用因崩溃等原因未正常清理,重启后将留下无法访问的共享内存对象。
我发现systemd登录管理器有RemoveIPC配置项,可控制用户完全注销时删除其System V和POSIX IPC对象,但该设置对root用户的共享内存无效,且无法解释为何重启时所有者会从原用户变为root而非直接删除共享内存(删除的话普通用户可重新创建),目前也无删除root所有IPC对象的类似选项。
Linux是否提供每次开机或重启时递增的“启动计数器”?若有,我可将计数器附加到对象名称,规避root用户占用旧对象名称的问题。
我已创建systemd服务单元,在系统关机时执行脚本删除/dev/shm目录下所有内容。日志显示脚本已执行且确实删除了共享内存,但重启后/dev/shm中共享内存仍存在且归root所有!
我推测原因是:系统重启时将/dev/shm内容持久化到磁盘的操作,早于我的删除脚本执行。
内容的提问来源于stack exchange,提问作者Schraubstock1990

