]>
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"
38 #include "dirent-util.h"
40 static int clean_sysvipc_shm(uid_t delete_uid
) {
41 _cleanup_fclose_
FILE *f
= NULL
;
46 f
= fopen("/proc/sysvipc/shm", "re");
51 log_warning_errno(errno
, "Failed to open /proc/sysvipc/shm: %m");
55 FOREACH_LINE(line
, f
, goto fail
) {
69 if (sscanf(line
, "%*i %i %*o %*u " PID_FMT
" " PID_FMT
" %u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
70 &shmid
, &cpid
, &lpid
, &n_attached
, &uid
, &gid
, &cuid
, &cgid
) != 8)
76 if (uid
!= delete_uid
)
79 if (shmctl(shmid
, IPC_RMID
, NULL
) < 0) {
81 /* Ignore entries that are already deleted */
82 if (errno
== EIDRM
|| errno
== EINVAL
)
85 ret
= log_warning_errno(errno
,
86 "Failed to remove SysV shared memory segment %i: %m",
94 log_warning_errno(errno
, "Failed to read /proc/sysvipc/shm: %m");
98 static int clean_sysvipc_sem(uid_t delete_uid
) {
99 _cleanup_fclose_
FILE *f
= NULL
;
104 f
= fopen("/proc/sysvipc/sem", "re");
109 log_warning_errno(errno
, "Failed to open /proc/sysvipc/sem: %m");
113 FOREACH_LINE(line
, f
, goto fail
) {
125 if (sscanf(line
, "%*i %i %*o %*u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
126 &semid
, &uid
, &gid
, &cuid
, &cgid
) != 5)
129 if (uid
!= delete_uid
)
132 if (semctl(semid
, 0, IPC_RMID
) < 0) {
134 /* Ignore entries that are already deleted */
135 if (errno
== EIDRM
|| errno
== EINVAL
)
138 ret
= log_warning_errno(errno
,
139 "Failed to remove SysV semaphores object %i: %m",
147 log_warning_errno(errno
, "Failed to read /proc/sysvipc/sem: %m");
151 static int clean_sysvipc_msg(uid_t delete_uid
) {
152 _cleanup_fclose_
FILE *f
= NULL
;
157 f
= fopen("/proc/sysvipc/msg", "re");
162 log_warning_errno(errno
, "Failed to open /proc/sysvipc/msg: %m");
166 FOREACH_LINE(line
, f
, goto fail
) {
179 if (sscanf(line
, "%*i %i %*o %*u %*u " PID_FMT
" " PID_FMT
" " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
180 &msgid
, &cpid
, &lpid
, &uid
, &gid
, &cuid
, &cgid
) != 7)
183 if (uid
!= delete_uid
)
186 if (msgctl(msgid
, IPC_RMID
, NULL
) < 0) {
188 /* Ignore entries that are already deleted */
189 if (errno
== EIDRM
|| errno
== EINVAL
)
192 ret
= log_warning_errno(errno
,
193 "Failed to remove SysV message queue %i: %m",
201 log_warning_errno(errno
, "Failed to read /proc/sysvipc/msg: %m");
205 static int clean_posix_shm_internal(DIR *dir
, uid_t uid
) {
211 FOREACH_DIRENT(de
, dir
, goto fail
) {
214 if (STR_IN_SET(de
->d_name
, "..", "."))
217 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
221 log_warning_errno(errno
, "Failed to stat() POSIX shared memory segment %s: %m", de
->d_name
);
226 if (st
.st_uid
!= uid
)
229 if (S_ISDIR(st
.st_mode
)) {
230 _cleanup_closedir_
DIR *kid
;
232 kid
= xopendirat(dirfd(dir
), de
->d_name
, O_NOFOLLOW
|O_NOATIME
);
234 if (errno
!= ENOENT
) {
235 log_warning_errno(errno
, "Failed to enter shared memory directory %s: %m", de
->d_name
);
239 r
= clean_posix_shm_internal(kid
, uid
);
244 if (unlinkat(dirfd(dir
), de
->d_name
, AT_REMOVEDIR
) < 0) {
249 log_warning_errno(errno
, "Failed to remove POSIX shared memory directory %s: %m", de
->d_name
);
254 if (unlinkat(dirfd(dir
), de
->d_name
, 0) < 0) {
259 log_warning_errno(errno
, "Failed to remove POSIX shared memory segment %s: %m", de
->d_name
);
268 log_warning_errno(errno
, "Failed to read /dev/shm: %m");
272 static int clean_posix_shm(uid_t uid
) {
273 _cleanup_closedir_
DIR *dir
= NULL
;
275 dir
= opendir("/dev/shm");
280 log_warning_errno(errno
, "Failed to open /dev/shm: %m");
284 return clean_posix_shm_internal(dir
, uid
);
287 static int clean_posix_mq(uid_t uid
) {
288 _cleanup_closedir_
DIR *dir
= NULL
;
292 dir
= opendir("/dev/mqueue");
297 log_warning_errno(errno
, "Failed to open /dev/mqueue: %m");
301 FOREACH_DIRENT(de
, dir
, goto fail
) {
303 char fn
[1+strlen(de
->d_name
)+1];
305 if (STR_IN_SET(de
->d_name
, "..", "."))
308 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
312 ret
= log_warning_errno(errno
,
313 "Failed to stat() MQ segment %s: %m",
318 if (st
.st_uid
!= uid
)
322 strcpy(fn
+1, de
->d_name
);
324 if (mq_unlink(fn
) < 0) {
328 ret
= log_warning_errno(errno
,
329 "Failed to unlink POSIX message queue %s: %m",
337 log_warning_errno(errno
, "Failed to read /dev/mqueue: %m");
341 int clean_ipc(uid_t uid
) {
344 /* Refuse to clean IPC of the root and system users */
345 if (uid
<= SYSTEM_UID_MAX
)
348 r
= clean_sysvipc_shm(uid
);
352 r
= clean_sysvipc_sem(uid
);
356 r
= clean_sysvipc_msg(uid
);
360 r
= clean_posix_shm(uid
);
364 r
= clean_posix_mq(uid
);