]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/clean-ipc.c
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/>.
31 #include "clean-ipc.h"
33 #include "formats-util.h"
34 #include "string-util.h"
38 static int clean_sysvipc_shm(uid_t delete_uid
) {
39 _cleanup_fclose_
FILE *f
= NULL
;
44 f
= fopen("/proc/sysvipc/shm", "re");
49 log_warning_errno(errno
, "Failed to open /proc/sysvipc/shm: %m");
53 FOREACH_LINE(line
, f
, goto fail
) {
67 if (sscanf(line
, "%*i %i %*o %*u " PID_FMT
" " PID_FMT
" %u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
68 &shmid
, &cpid
, &lpid
, &n_attached
, &uid
, &gid
, &cuid
, &cgid
) != 8)
74 if (uid
!= delete_uid
)
77 if (shmctl(shmid
, IPC_RMID
, NULL
) < 0) {
79 /* Ignore entries that are already deleted */
80 if (errno
== EIDRM
|| errno
== EINVAL
)
83 ret
= log_warning_errno(errno
,
84 "Failed to remove SysV shared memory segment %i: %m",
92 log_warning_errno(errno
, "Failed to read /proc/sysvipc/shm: %m");
96 static int clean_sysvipc_sem(uid_t delete_uid
) {
97 _cleanup_fclose_
FILE *f
= NULL
;
102 f
= fopen("/proc/sysvipc/sem", "re");
107 log_warning_errno(errno
, "Failed to open /proc/sysvipc/sem: %m");
111 FOREACH_LINE(line
, f
, goto fail
) {
123 if (sscanf(line
, "%*i %i %*o %*u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
124 &semid
, &uid
, &gid
, &cuid
, &cgid
) != 5)
127 if (uid
!= delete_uid
)
130 if (semctl(semid
, 0, IPC_RMID
) < 0) {
132 /* Ignore entries that are already deleted */
133 if (errno
== EIDRM
|| errno
== EINVAL
)
136 ret
= log_warning_errno(errno
,
137 "Failed to remove SysV semaphores object %i: %m",
145 log_warning_errno(errno
, "Failed to read /proc/sysvipc/sem: %m");
149 static int clean_sysvipc_msg(uid_t delete_uid
) {
150 _cleanup_fclose_
FILE *f
= NULL
;
155 f
= fopen("/proc/sysvipc/msg", "re");
160 log_warning_errno(errno
, "Failed to open /proc/sysvipc/msg: %m");
164 FOREACH_LINE(line
, f
, goto fail
) {
177 if (sscanf(line
, "%*i %i %*o %*u %*u " PID_FMT
" " PID_FMT
" " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
178 &msgid
, &cpid
, &lpid
, &uid
, &gid
, &cuid
, &cgid
) != 7)
181 if (uid
!= delete_uid
)
184 if (msgctl(msgid
, IPC_RMID
, NULL
) < 0) {
186 /* Ignore entries that are already deleted */
187 if (errno
== EIDRM
|| errno
== EINVAL
)
190 ret
= log_warning_errno(errno
,
191 "Failed to remove SysV message queue %i: %m",
199 log_warning_errno(errno
, "Failed to read /proc/sysvipc/msg: %m");
203 static int clean_posix_shm_internal(DIR *dir
, uid_t uid
) {
209 FOREACH_DIRENT(de
, dir
, goto fail
) {
212 if (STR_IN_SET(de
->d_name
, "..", "."))
215 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
219 log_warning_errno(errno
, "Failed to stat() POSIX shared memory segment %s: %m", de
->d_name
);
224 if (st
.st_uid
!= uid
)
227 if (S_ISDIR(st
.st_mode
)) {
228 _cleanup_closedir_
DIR *kid
;
230 kid
= xopendirat(dirfd(dir
), de
->d_name
, O_NOFOLLOW
|O_NOATIME
);
232 if (errno
!= ENOENT
) {
233 log_warning_errno(errno
, "Failed to enter shared memory directory %s: %m", de
->d_name
);
237 r
= clean_posix_shm_internal(kid
, uid
);
242 if (unlinkat(dirfd(dir
), de
->d_name
, AT_REMOVEDIR
) < 0) {
247 log_warning_errno(errno
, "Failed to remove POSIX shared memory directory %s: %m", de
->d_name
);
252 if (unlinkat(dirfd(dir
), de
->d_name
, 0) < 0) {
257 log_warning_errno(errno
, "Failed to remove POSIX shared memory segment %s: %m", de
->d_name
);
266 log_warning_errno(errno
, "Failed to read /dev/shm: %m");
270 static int clean_posix_shm(uid_t uid
) {
271 _cleanup_closedir_
DIR *dir
= NULL
;
273 dir
= opendir("/dev/shm");
278 log_warning_errno(errno
, "Failed to open /dev/shm: %m");
282 return clean_posix_shm_internal(dir
, uid
);
285 static int clean_posix_mq(uid_t uid
) {
286 _cleanup_closedir_
DIR *dir
= NULL
;
290 dir
= opendir("/dev/mqueue");
295 log_warning_errno(errno
, "Failed to open /dev/mqueue: %m");
299 FOREACH_DIRENT(de
, dir
, goto fail
) {
301 char fn
[1+strlen(de
->d_name
)+1];
303 if (STR_IN_SET(de
->d_name
, "..", "."))
306 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
310 ret
= log_warning_errno(errno
,
311 "Failed to stat() MQ segment %s: %m",
316 if (st
.st_uid
!= uid
)
320 strcpy(fn
+1, de
->d_name
);
322 if (mq_unlink(fn
) < 0) {
326 ret
= log_warning_errno(errno
,
327 "Failed to unlink POSIX message queue %s: %m",
335 log_warning_errno(errno
, "Failed to read /dev/mqueue: %m");
339 int clean_ipc(uid_t uid
) {
342 /* Refuse to clean IPC of the root and system users */
343 if (uid
<= SYSTEM_UID_MAX
)
346 r
= clean_sysvipc_shm(uid
);
350 r
= clean_sysvipc_sem(uid
);
354 r
= clean_sysvipc_msg(uid
);
358 r
= clean_posix_shm(uid
);
362 r
= clean_posix_mq(uid
);