]>
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/>.
37 #include "clean-ipc.h"
38 #include "dirent-util.h"
41 #include "formats-util.h"
44 #include "string-util.h"
47 static int clean_sysvipc_shm(uid_t delete_uid
) {
48 _cleanup_fclose_
FILE *f
= NULL
;
53 f
= fopen("/proc/sysvipc/shm", "re");
58 return log_warning_errno(errno
, "Failed to open /proc/sysvipc/shm: %m");
61 FOREACH_LINE(line
, f
, goto fail
) {
75 if (sscanf(line
, "%*i %i %*o %*u " PID_FMT
" " PID_FMT
" %u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
76 &shmid
, &cpid
, &lpid
, &n_attached
, &uid
, &gid
, &cuid
, &cgid
) != 8)
82 if (uid
!= delete_uid
)
85 if (shmctl(shmid
, IPC_RMID
, NULL
) < 0) {
87 /* Ignore entries that are already deleted */
88 if (errno
== EIDRM
|| errno
== EINVAL
)
91 ret
= log_warning_errno(errno
,
92 "Failed to remove SysV shared memory segment %i: %m",
100 return log_warning_errno(errno
, "Failed to read /proc/sysvipc/shm: %m");
103 static int clean_sysvipc_sem(uid_t delete_uid
) {
104 _cleanup_fclose_
FILE *f
= NULL
;
109 f
= fopen("/proc/sysvipc/sem", "re");
114 return log_warning_errno(errno
, "Failed to open /proc/sysvipc/sem: %m");
117 FOREACH_LINE(line
, f
, goto fail
) {
129 if (sscanf(line
, "%*i %i %*o %*u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
130 &semid
, &uid
, &gid
, &cuid
, &cgid
) != 5)
133 if (uid
!= delete_uid
)
136 if (semctl(semid
, 0, IPC_RMID
) < 0) {
138 /* Ignore entries that are already deleted */
139 if (errno
== EIDRM
|| errno
== EINVAL
)
142 ret
= log_warning_errno(errno
,
143 "Failed to remove SysV semaphores object %i: %m",
151 return log_warning_errno(errno
, "Failed to read /proc/sysvipc/sem: %m");
154 static int clean_sysvipc_msg(uid_t delete_uid
) {
155 _cleanup_fclose_
FILE *f
= NULL
;
160 f
= fopen("/proc/sysvipc/msg", "re");
165 return log_warning_errno(errno
, "Failed to open /proc/sysvipc/msg: %m");
168 FOREACH_LINE(line
, f
, goto fail
) {
181 if (sscanf(line
, "%*i %i %*o %*u %*u " PID_FMT
" " PID_FMT
" " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
182 &msgid
, &cpid
, &lpid
, &uid
, &gid
, &cuid
, &cgid
) != 7)
185 if (uid
!= delete_uid
)
188 if (msgctl(msgid
, IPC_RMID
, NULL
) < 0) {
190 /* Ignore entries that are already deleted */
191 if (errno
== EIDRM
|| errno
== EINVAL
)
194 ret
= log_warning_errno(errno
,
195 "Failed to remove SysV message queue %i: %m",
203 return log_warning_errno(errno
, "Failed to read /proc/sysvipc/msg: %m");
206 static int clean_posix_shm_internal(DIR *dir
, uid_t uid
) {
212 FOREACH_DIRENT(de
, dir
, goto fail
) {
215 if (STR_IN_SET(de
->d_name
, "..", "."))
218 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
222 log_warning_errno(errno
, "Failed to stat() POSIX shared memory segment %s: %m", de
->d_name
);
227 if (st
.st_uid
!= uid
)
230 if (S_ISDIR(st
.st_mode
)) {
231 _cleanup_closedir_
DIR *kid
;
233 kid
= xopendirat(dirfd(dir
), de
->d_name
, O_NOFOLLOW
|O_NOATIME
);
235 if (errno
!= ENOENT
) {
236 log_warning_errno(errno
, "Failed to enter shared memory directory %s: %m", de
->d_name
);
240 r
= clean_posix_shm_internal(kid
, uid
);
245 if (unlinkat(dirfd(dir
), de
->d_name
, AT_REMOVEDIR
) < 0) {
250 log_warning_errno(errno
, "Failed to remove POSIX shared memory directory %s: %m", de
->d_name
);
255 if (unlinkat(dirfd(dir
), de
->d_name
, 0) < 0) {
260 log_warning_errno(errno
, "Failed to remove POSIX shared memory segment %s: %m", de
->d_name
);
269 log_warning_errno(errno
, "Failed to read /dev/shm: %m");
273 static int clean_posix_shm(uid_t uid
) {
274 _cleanup_closedir_
DIR *dir
= NULL
;
276 dir
= opendir("/dev/shm");
281 return 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 return 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 return 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
);