]>
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 "formats-util.h"
32 #include "string-util.h"
35 #include "clean-ipc.h"
37 static int clean_sysvipc_shm(uid_t delete_uid
) {
38 _cleanup_fclose_
FILE *f
= NULL
;
43 f
= fopen("/proc/sysvipc/shm", "re");
48 log_warning_errno(errno
, "Failed to open /proc/sysvipc/shm: %m");
52 FOREACH_LINE(line
, f
, goto fail
) {
66 if (sscanf(line
, "%*i %i %*o %*u " PID_FMT
" " PID_FMT
" %u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
67 &shmid
, &cpid
, &lpid
, &n_attached
, &uid
, &gid
, &cuid
, &cgid
) != 8)
73 if (uid
!= delete_uid
)
76 if (shmctl(shmid
, IPC_RMID
, NULL
) < 0) {
78 /* Ignore entries that are already deleted */
79 if (errno
== EIDRM
|| errno
== EINVAL
)
82 ret
= log_warning_errno(errno
,
83 "Failed to remove SysV shared memory segment %i: %m",
91 log_warning_errno(errno
, "Failed to read /proc/sysvipc/shm: %m");
95 static int clean_sysvipc_sem(uid_t delete_uid
) {
96 _cleanup_fclose_
FILE *f
= NULL
;
101 f
= fopen("/proc/sysvipc/sem", "re");
106 log_warning_errno(errno
, "Failed to open /proc/sysvipc/sem: %m");
110 FOREACH_LINE(line
, f
, goto fail
) {
122 if (sscanf(line
, "%*i %i %*o %*u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
123 &semid
, &uid
, &gid
, &cuid
, &cgid
) != 5)
126 if (uid
!= delete_uid
)
129 if (semctl(semid
, 0, IPC_RMID
) < 0) {
131 /* Ignore entries that are already deleted */
132 if (errno
== EIDRM
|| errno
== EINVAL
)
135 ret
= log_warning_errno(errno
,
136 "Failed to remove SysV semaphores object %i: %m",
144 log_warning_errno(errno
, "Failed to read /proc/sysvipc/sem: %m");
148 static int clean_sysvipc_msg(uid_t delete_uid
) {
149 _cleanup_fclose_
FILE *f
= NULL
;
154 f
= fopen("/proc/sysvipc/msg", "re");
159 log_warning_errno(errno
, "Failed to open /proc/sysvipc/msg: %m");
163 FOREACH_LINE(line
, f
, goto fail
) {
176 if (sscanf(line
, "%*i %i %*o %*u %*u " PID_FMT
" " PID_FMT
" " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
177 &msgid
, &cpid
, &lpid
, &uid
, &gid
, &cuid
, &cgid
) != 7)
180 if (uid
!= delete_uid
)
183 if (msgctl(msgid
, IPC_RMID
, NULL
) < 0) {
185 /* Ignore entries that are already deleted */
186 if (errno
== EIDRM
|| errno
== EINVAL
)
189 ret
= log_warning_errno(errno
,
190 "Failed to remove SysV message queue %i: %m",
198 log_warning_errno(errno
, "Failed to read /proc/sysvipc/msg: %m");
202 static int clean_posix_shm_internal(DIR *dir
, uid_t uid
) {
208 FOREACH_DIRENT(de
, dir
, goto fail
) {
211 if (STR_IN_SET(de
->d_name
, "..", "."))
214 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
218 log_warning_errno(errno
, "Failed to stat() POSIX shared memory segment %s: %m", de
->d_name
);
223 if (st
.st_uid
!= uid
)
226 if (S_ISDIR(st
.st_mode
)) {
227 _cleanup_closedir_
DIR *kid
;
229 kid
= xopendirat(dirfd(dir
), de
->d_name
, O_NOFOLLOW
|O_NOATIME
);
231 if (errno
!= ENOENT
) {
232 log_warning_errno(errno
, "Failed to enter shared memory directory %s: %m", de
->d_name
);
236 r
= clean_posix_shm_internal(kid
, uid
);
241 if (unlinkat(dirfd(dir
), de
->d_name
, AT_REMOVEDIR
) < 0) {
246 log_warning_errno(errno
, "Failed to remove POSIX shared memory directory %s: %m", de
->d_name
);
251 if (unlinkat(dirfd(dir
), de
->d_name
, 0) < 0) {
256 log_warning_errno(errno
, "Failed to remove POSIX shared memory segment %s: %m", de
->d_name
);
265 log_warning_errno(errno
, "Failed to read /dev/shm: %m");
269 static int clean_posix_shm(uid_t uid
) {
270 _cleanup_closedir_
DIR *dir
= NULL
;
272 dir
= opendir("/dev/shm");
277 log_warning_errno(errno
, "Failed to open /dev/shm: %m");
281 return clean_posix_shm_internal(dir
, uid
);
284 static int clean_posix_mq(uid_t uid
) {
285 _cleanup_closedir_
DIR *dir
= NULL
;
289 dir
= opendir("/dev/mqueue");
294 log_warning_errno(errno
, "Failed to open /dev/mqueue: %m");
298 FOREACH_DIRENT(de
, dir
, goto fail
) {
300 char fn
[1+strlen(de
->d_name
)+1];
302 if (STR_IN_SET(de
->d_name
, "..", "."))
305 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
309 ret
= log_warning_errno(errno
,
310 "Failed to stat() MQ segment %s: %m",
315 if (st
.st_uid
!= uid
)
319 strcpy(fn
+1, de
->d_name
);
321 if (mq_unlink(fn
) < 0) {
325 ret
= log_warning_errno(errno
,
326 "Failed to unlink POSIX message queue %s: %m",
334 log_warning_errno(errno
, "Failed to read /dev/mqueue: %m");
338 int clean_ipc(uid_t uid
) {
341 /* Refuse to clean IPC of the root and system users */
342 if (uid
<= SYSTEM_UID_MAX
)
345 r
= clean_sysvipc_shm(uid
);
349 r
= clean_sysvipc_sem(uid
);
353 r
= clean_sysvipc_msg(uid
);
357 r
= clean_posix_shm(uid
);
361 r
= clean_posix_mq(uid
);