]>
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/>.
32 #include "formats-util.h"
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_errno(errno
, "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 ret
= log_warning_errno(errno
,
82 "Failed to remove SysV shared memory segment %i: %m",
90 log_warning_errno(errno
, "Failed to read /proc/sysvipc/shm: %m");
94 static int clean_sysvipc_sem(uid_t delete_uid
) {
95 _cleanup_fclose_
FILE *f
= NULL
;
100 f
= fopen("/proc/sysvipc/sem", "re");
105 log_warning_errno(errno
, "Failed to open /proc/sysvipc/sem: %m");
109 FOREACH_LINE(line
, f
, goto fail
) {
121 if (sscanf(line
, "%*i %i %*o %*u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
122 &semid
, &uid
, &gid
, &cuid
, &cgid
) != 5)
125 if (uid
!= delete_uid
)
128 if (semctl(semid
, 0, IPC_RMID
) < 0) {
130 /* Ignore entries that are already deleted */
131 if (errno
== EIDRM
|| errno
== EINVAL
)
134 ret
= log_warning_errno(errno
,
135 "Failed to remove SysV semaphores object %i: %m",
143 log_warning_errno(errno
, "Failed to read /proc/sysvipc/sem: %m");
147 static int clean_sysvipc_msg(uid_t delete_uid
) {
148 _cleanup_fclose_
FILE *f
= NULL
;
153 f
= fopen("/proc/sysvipc/msg", "re");
158 log_warning_errno(errno
, "Failed to open /proc/sysvipc/msg: %m");
162 FOREACH_LINE(line
, f
, goto fail
) {
175 if (sscanf(line
, "%*i %i %*o %*u %*u " PID_FMT
" " PID_FMT
" " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
176 &msgid
, &cpid
, &lpid
, &uid
, &gid
, &cuid
, &cgid
) != 7)
179 if (uid
!= delete_uid
)
182 if (msgctl(msgid
, IPC_RMID
, NULL
) < 0) {
184 /* Ignore entries that are already deleted */
185 if (errno
== EIDRM
|| errno
== EINVAL
)
188 ret
= log_warning_errno(errno
,
189 "Failed to remove SysV message queue %i: %m",
197 log_warning_errno(errno
, "Failed to read /proc/sysvipc/msg: %m");
201 static int clean_posix_shm_internal(DIR *dir
, uid_t uid
) {
207 FOREACH_DIRENT(de
, dir
, goto fail
) {
210 if (STR_IN_SET(de
->d_name
, "..", "."))
213 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
217 log_warning_errno(errno
, "Failed to stat() POSIX shared memory segment %s: %m", de
->d_name
);
222 if (st
.st_uid
!= uid
)
225 if (S_ISDIR(st
.st_mode
)) {
226 _cleanup_closedir_
DIR *kid
;
228 kid
= xopendirat(dirfd(dir
), de
->d_name
, O_NOFOLLOW
|O_NOATIME
);
230 if (errno
!= ENOENT
) {
231 log_warning_errno(errno
, "Failed to enter shared memory directory %s: %m", de
->d_name
);
235 r
= clean_posix_shm_internal(kid
, uid
);
240 if (unlinkat(dirfd(dir
), de
->d_name
, AT_REMOVEDIR
) < 0) {
245 log_warning_errno(errno
, "Failed to remove POSIX shared memory directory %s: %m", de
->d_name
);
250 if (unlinkat(dirfd(dir
), de
->d_name
, 0) < 0) {
255 log_warning_errno(errno
, "Failed to remove POSIX shared memory segment %s: %m", de
->d_name
);
264 log_warning_errno(errno
, "Failed to read /dev/shm: %m");
268 static int clean_posix_shm(uid_t uid
) {
269 _cleanup_closedir_
DIR *dir
= NULL
;
271 dir
= opendir("/dev/shm");
276 log_warning_errno(errno
, "Failed to open /dev/shm: %m");
280 return clean_posix_shm_internal(dir
, uid
);
283 static int clean_posix_mq(uid_t uid
) {
284 _cleanup_closedir_
DIR *dir
= NULL
;
288 dir
= opendir("/dev/mqueue");
293 log_warning_errno(errno
, "Failed to open /dev/mqueue: %m");
297 FOREACH_DIRENT(de
, dir
, goto fail
) {
299 char fn
[1+strlen(de
->d_name
)+1];
301 if (STR_IN_SET(de
->d_name
, "..", "."))
304 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
308 ret
= log_warning_errno(errno
,
309 "Failed to stat() MQ segment %s: %m",
314 if (st
.st_uid
!= uid
)
318 strcpy(fn
+1, de
->d_name
);
320 if (mq_unlink(fn
) < 0) {
324 ret
= log_warning_errno(errno
,
325 "Failed to unlink POSIX message queue %s: %m",
333 log_warning_errno(errno
, "Failed to read /dev/mqueue: %m");
337 int clean_ipc(uid_t uid
) {
340 /* Refuse to clean IPC of the root and system users */
341 if (uid
<= SYSTEM_UID_MAX
)
344 r
= clean_sysvipc_shm(uid
);
348 r
= clean_sysvipc_sem(uid
);
352 r
= clean_sysvipc_msg(uid
);
356 r
= clean_posix_shm(uid
);
360 r
= clean_posix_mq(uid
);