1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
34 #include "clean-ipc.h"
36 static int clean_sysvipc_shm(uid_t delete_uid) {
37 _cleanup_fclose_ FILE *f = NULL;
42 f = fopen("/proc/sysvipc/shm", "re");
47 log_warning("Failed to open /proc/sysvipc/shm: %m");
51 FOREACH_LINE(line, f, goto fail) {
65 if (sscanf(line, "%*i %i %*o %*u " PID_FMT " " PID_FMT " %u " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT,
66 &shmid, &cpid, &lpid, &n_attached, &uid, &gid, &cuid, &cgid) != 8)
72 if (uid != delete_uid)
75 if (shmctl(shmid, IPC_RMID, NULL) < 0) {
77 /* Ignore entries that are already deleted */
78 if (errno == EIDRM || errno == EINVAL)
81 log_warning("Failed to remove SysV shared memory segment %i: %m", shmid);
89 log_warning("Failed to read /proc/sysvipc/shm: %m");
93 static int clean_sysvipc_sem(uid_t delete_uid) {
94 _cleanup_fclose_ FILE *f = NULL;
99 f = fopen("/proc/sysvipc/sem", "re");
104 log_warning("Failed to open /proc/sysvipc/sem: %m");
108 FOREACH_LINE(line, f, goto fail) {
120 if (sscanf(line, "%*i %i %*o %*u " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT,
121 &semid, &uid, &gid, &cuid, &cgid) != 5)
124 if (uid != delete_uid)
127 if (semctl(semid, 0, IPC_RMID) < 0) {
129 /* Ignore entries that are already deleted */
130 if (errno == EIDRM || errno == EINVAL)
133 log_warning("Failed to remove SysV semaphores object %i: %m", semid);
141 log_warning("Failed to read /proc/sysvipc/sem: %m");
145 static int clean_sysvipc_msg(uid_t delete_uid) {
146 _cleanup_fclose_ FILE *f = NULL;
151 f = fopen("/proc/sysvipc/msg", "re");
156 log_warning("Failed to open /proc/sysvipc/msg: %m");
160 FOREACH_LINE(line, f, goto fail) {
173 if (sscanf(line, "%*i %i %*o %*u %*u " PID_FMT " " PID_FMT " " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT,
174 &msgid, &cpid, &lpid, &uid, &gid, &cuid, &cgid) != 7)
177 if (uid != delete_uid)
180 if (msgctl(msgid, IPC_RMID, NULL) < 0) {
182 /* Ignore entries that are already deleted */
183 if (errno == EIDRM || errno == EINVAL)
186 log_warning("Failed to remove SysV message queue %i: %m", msgid);
194 log_warning("Failed to read /proc/sysvipc/msg: %m");
198 static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
204 FOREACH_DIRENT(de, dir, goto fail) {
207 if (STR_IN_SET(de->d_name, "..", "."))
210 if (fstatat(dirfd(dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
214 log_warning("Failed to stat() POSIX shared memory segment %s: %m", de->d_name);
219 if (st.st_uid != uid)
222 if (S_ISDIR(st.st_mode)) {
223 _cleanup_closedir_ DIR *kid;
225 kid = xopendirat(dirfd(dir), de->d_name, O_NOFOLLOW|O_NOATIME);
227 if (errno != ENOENT) {
228 log_warning("Failed to enter shared memory directory %s: %m", de->d_name);
232 r = clean_posix_shm_internal(kid, uid);
237 if (unlinkat(dirfd(dir), de->d_name, AT_REMOVEDIR) < 0) {
242 log_warning("Failed to remove POSIX shared memory directory %s: %m", de->d_name);
247 if (unlinkat(dirfd(dir), de->d_name, 0) < 0) {
252 log_warning("Failed to remove POSIX shared memory segment %s: %m", de->d_name);
261 log_warning("Failed to read /dev/shm: %m");
265 static int clean_posix_shm(uid_t uid) {
266 _cleanup_closedir_ DIR *dir = NULL;
268 dir = opendir("/dev/shm");
273 log_warning("Failed to open /dev/shm: %m");
277 return clean_posix_shm_internal(dir, uid);
280 static int clean_posix_mq(uid_t uid) {
281 _cleanup_closedir_ DIR *dir = NULL;
285 dir = opendir("/dev/mqueue");
290 log_warning("Failed to open /dev/mqueue: %m");
294 FOREACH_DIRENT(de, dir, goto fail) {
296 char fn[1+strlen(de->d_name)+1];
298 if (STR_IN_SET(de->d_name, "..", "."))
301 if (fstatat(dirfd(dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
305 log_warning("Failed to stat() MQ segment %s: %m", de->d_name);
310 if (st.st_uid != uid)
314 strcpy(fn+1, de->d_name);
316 if (mq_unlink(fn) < 0) {
320 log_warning("Failed to unlink POSIX message queue %s: %m", fn);
328 log_warning("Failed to read /dev/mqueue: %m");
332 int clean_ipc(uid_t uid) {
335 /* Refuse to clean IPC of the root and system users */
336 if (uid <= SYSTEM_UID_MAX)
339 r = clean_sysvipc_shm(uid);
343 r = clean_sysvipc_sem(uid);
347 r = clean_sysvipc_msg(uid);
351 r = clean_posix_shm(uid);
355 r = clean_posix_mq(uid);