]>
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"
34 #include "formats-util.h"
35 #include "string-util.h"
39 static int clean_sysvipc_shm(uid_t delete_uid
) {
40 _cleanup_fclose_
FILE *f
= NULL
;
45 f
= fopen("/proc/sysvipc/shm", "re");
50 log_warning_errno(errno
, "Failed to open /proc/sysvipc/shm: %m");
54 FOREACH_LINE(line
, f
, goto fail
) {
68 if (sscanf(line
, "%*i %i %*o %*u " PID_FMT
" " PID_FMT
" %u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
69 &shmid
, &cpid
, &lpid
, &n_attached
, &uid
, &gid
, &cuid
, &cgid
) != 8)
75 if (uid
!= delete_uid
)
78 if (shmctl(shmid
, IPC_RMID
, NULL
) < 0) {
80 /* Ignore entries that are already deleted */
81 if (errno
== EIDRM
|| errno
== EINVAL
)
84 ret
= log_warning_errno(errno
,
85 "Failed to remove SysV shared memory segment %i: %m",
93 log_warning_errno(errno
, "Failed to read /proc/sysvipc/shm: %m");
97 static int clean_sysvipc_sem(uid_t delete_uid
) {
98 _cleanup_fclose_
FILE *f
= NULL
;
103 f
= fopen("/proc/sysvipc/sem", "re");
108 log_warning_errno(errno
, "Failed to open /proc/sysvipc/sem: %m");
112 FOREACH_LINE(line
, f
, goto fail
) {
124 if (sscanf(line
, "%*i %i %*o %*u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
125 &semid
, &uid
, &gid
, &cuid
, &cgid
) != 5)
128 if (uid
!= delete_uid
)
131 if (semctl(semid
, 0, IPC_RMID
) < 0) {
133 /* Ignore entries that are already deleted */
134 if (errno
== EIDRM
|| errno
== EINVAL
)
137 ret
= log_warning_errno(errno
,
138 "Failed to remove SysV semaphores object %i: %m",
146 log_warning_errno(errno
, "Failed to read /proc/sysvipc/sem: %m");
150 static int clean_sysvipc_msg(uid_t delete_uid
) {
151 _cleanup_fclose_
FILE *f
= NULL
;
156 f
= fopen("/proc/sysvipc/msg", "re");
161 log_warning_errno(errno
, "Failed to open /proc/sysvipc/msg: %m");
165 FOREACH_LINE(line
, f
, goto fail
) {
178 if (sscanf(line
, "%*i %i %*o %*u %*u " PID_FMT
" " PID_FMT
" " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
179 &msgid
, &cpid
, &lpid
, &uid
, &gid
, &cuid
, &cgid
) != 7)
182 if (uid
!= delete_uid
)
185 if (msgctl(msgid
, IPC_RMID
, NULL
) < 0) {
187 /* Ignore entries that are already deleted */
188 if (errno
== EIDRM
|| errno
== EINVAL
)
191 ret
= log_warning_errno(errno
,
192 "Failed to remove SysV message queue %i: %m",
200 log_warning_errno(errno
, "Failed to read /proc/sysvipc/msg: %m");
204 static int clean_posix_shm_internal(DIR *dir
, uid_t uid
) {
210 FOREACH_DIRENT(de
, dir
, goto fail
) {
213 if (STR_IN_SET(de
->d_name
, "..", "."))
216 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
220 log_warning_errno(errno
, "Failed to stat() POSIX shared memory segment %s: %m", de
->d_name
);
225 if (st
.st_uid
!= uid
)
228 if (S_ISDIR(st
.st_mode
)) {
229 _cleanup_closedir_
DIR *kid
;
231 kid
= xopendirat(dirfd(dir
), de
->d_name
, O_NOFOLLOW
|O_NOATIME
);
233 if (errno
!= ENOENT
) {
234 log_warning_errno(errno
, "Failed to enter shared memory directory %s: %m", de
->d_name
);
238 r
= clean_posix_shm_internal(kid
, uid
);
243 if (unlinkat(dirfd(dir
), de
->d_name
, AT_REMOVEDIR
) < 0) {
248 log_warning_errno(errno
, "Failed to remove POSIX shared memory directory %s: %m", de
->d_name
);
253 if (unlinkat(dirfd(dir
), de
->d_name
, 0) < 0) {
258 log_warning_errno(errno
, "Failed to remove POSIX shared memory segment %s: %m", de
->d_name
);
267 log_warning_errno(errno
, "Failed to read /dev/shm: %m");
271 static int clean_posix_shm(uid_t uid
) {
272 _cleanup_closedir_
DIR *dir
= NULL
;
274 dir
= opendir("/dev/shm");
279 log_warning_errno(errno
, "Failed to open /dev/shm: %m");
283 return clean_posix_shm_internal(dir
, uid
);
286 static int clean_posix_mq(uid_t uid
) {
287 _cleanup_closedir_
DIR *dir
= NULL
;
291 dir
= opendir("/dev/mqueue");
296 log_warning_errno(errno
, "Failed to open /dev/mqueue: %m");
300 FOREACH_DIRENT(de
, dir
, goto fail
) {
302 char fn
[1+strlen(de
->d_name
)+1];
304 if (STR_IN_SET(de
->d_name
, "..", "."))
307 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
311 ret
= log_warning_errno(errno
,
312 "Failed to stat() MQ segment %s: %m",
317 if (st
.st_uid
!= uid
)
321 strcpy(fn
+1, de
->d_name
);
323 if (mq_unlink(fn
) < 0) {
327 ret
= log_warning_errno(errno
,
328 "Failed to unlink POSIX message queue %s: %m",
336 log_warning_errno(errno
, "Failed to read /dev/mqueue: %m");
340 int clean_ipc(uid_t uid
) {
343 /* Refuse to clean IPC of the root and system users */
344 if (uid
<= SYSTEM_UID_MAX
)
347 r
= clean_sysvipc_shm(uid
);
351 r
= clean_sysvipc_sem(uid
);
355 r
= clean_sysvipc_msg(uid
);
359 r
= clean_posix_shm(uid
);
363 r
= clean_posix_mq(uid
);