]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/clean-ipc.c
2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
35 #include "clean-ipc.h"
36 #include "dirent-util.h"
39 #include "format-util.h"
42 #include "string-util.h"
44 #include "user-util.h"
46 static bool match_uid_gid(uid_t subject_uid
, gid_t subject_gid
, uid_t delete_uid
, gid_t delete_gid
) {
48 if (uid_is_valid(delete_uid
) && subject_uid
== delete_uid
)
51 if (gid_is_valid(delete_gid
) && subject_gid
== delete_gid
)
57 static int clean_sysvipc_shm(uid_t delete_uid
, gid_t delete_gid
) {
58 _cleanup_fclose_
FILE *f
= NULL
;
63 f
= fopen("/proc/sysvipc/shm", "re");
68 return log_warning_errno(errno
, "Failed to open /proc/sysvipc/shm: %m");
71 FOREACH_LINE(line
, f
, goto fail
) {
85 if (sscanf(line
, "%*i %i %*o %*u " PID_FMT
" " PID_FMT
" %u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
86 &shmid
, &cpid
, &lpid
, &n_attached
, &uid
, &gid
, &cuid
, &cgid
) != 8)
92 if (!match_uid_gid(uid
, gid
, delete_uid
, delete_gid
))
95 if (shmctl(shmid
, IPC_RMID
, NULL
) < 0) {
97 /* Ignore entries that are already deleted */
98 if (errno
== EIDRM
|| errno
== EINVAL
)
101 ret
= log_warning_errno(errno
,
102 "Failed to remove SysV shared memory segment %i: %m",
105 log_debug("Removed SysV shared memory segment %i.", shmid
);
111 return log_warning_errno(errno
, "Failed to read /proc/sysvipc/shm: %m");
114 static int clean_sysvipc_sem(uid_t delete_uid
, gid_t delete_gid
) {
115 _cleanup_fclose_
FILE *f
= NULL
;
120 f
= fopen("/proc/sysvipc/sem", "re");
125 return log_warning_errno(errno
, "Failed to open /proc/sysvipc/sem: %m");
128 FOREACH_LINE(line
, f
, goto fail
) {
140 if (sscanf(line
, "%*i %i %*o %*u " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
141 &semid
, &uid
, &gid
, &cuid
, &cgid
) != 5)
144 if (!match_uid_gid(uid
, gid
, delete_uid
, delete_gid
))
147 if (semctl(semid
, 0, IPC_RMID
) < 0) {
149 /* Ignore entries that are already deleted */
150 if (errno
== EIDRM
|| errno
== EINVAL
)
153 ret
= log_warning_errno(errno
,
154 "Failed to remove SysV semaphores object %i: %m",
157 log_debug("Removed SysV semaphore %i.", semid
);
163 return log_warning_errno(errno
, "Failed to read /proc/sysvipc/sem: %m");
166 static int clean_sysvipc_msg(uid_t delete_uid
, gid_t delete_gid
) {
167 _cleanup_fclose_
FILE *f
= NULL
;
172 f
= fopen("/proc/sysvipc/msg", "re");
177 return log_warning_errno(errno
, "Failed to open /proc/sysvipc/msg: %m");
180 FOREACH_LINE(line
, f
, goto fail
) {
193 if (sscanf(line
, "%*i %i %*o %*u %*u " PID_FMT
" " PID_FMT
" " UID_FMT
" " GID_FMT
" " UID_FMT
" " GID_FMT
,
194 &msgid
, &cpid
, &lpid
, &uid
, &gid
, &cuid
, &cgid
) != 7)
197 if (!match_uid_gid(uid
, gid
, delete_uid
, delete_gid
))
200 if (msgctl(msgid
, IPC_RMID
, NULL
) < 0) {
202 /* Ignore entries that are already deleted */
203 if (errno
== EIDRM
|| errno
== EINVAL
)
206 ret
= log_warning_errno(errno
,
207 "Failed to remove SysV message queue %i: %m",
210 log_debug("Removed SysV message queue %i.", msgid
);
216 return log_warning_errno(errno
, "Failed to read /proc/sysvipc/msg: %m");
219 static int clean_posix_shm_internal(DIR *dir
, uid_t uid
, gid_t gid
) {
225 FOREACH_DIRENT_ALL(de
, dir
, goto fail
) {
228 if (dot_or_dot_dot(de
->d_name
))
231 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
235 ret
= log_warning_errno(errno
, "Failed to stat() POSIX shared memory segment %s: %m", de
->d_name
);
239 if (!match_uid_gid(st
.st_uid
, st
.st_gid
, uid
, gid
))
242 if (S_ISDIR(st
.st_mode
)) {
243 _cleanup_closedir_
DIR *kid
;
245 kid
= xopendirat(dirfd(dir
), de
->d_name
, O_NOFOLLOW
|O_NOATIME
);
248 ret
= log_warning_errno(errno
, "Failed to enter shared memory directory %s: %m", de
->d_name
);
250 r
= clean_posix_shm_internal(kid
, uid
, gid
);
255 if (unlinkat(dirfd(dir
), de
->d_name
, AT_REMOVEDIR
) < 0) {
260 ret
= log_warning_errno(errno
, "Failed to remove POSIX shared memory directory %s: %m", de
->d_name
);
262 log_debug("Removed POSIX shared memory directory %s", de
->d_name
);
265 if (unlinkat(dirfd(dir
), de
->d_name
, 0) < 0) {
270 ret
= log_warning_errno(errno
, "Failed to remove POSIX shared memory segment %s: %m", de
->d_name
);
272 log_debug("Removed POSIX shared memory segment %s", de
->d_name
);
279 return log_warning_errno(errno
, "Failed to read /dev/shm: %m");
282 static int clean_posix_shm(uid_t uid
, gid_t gid
) {
283 _cleanup_closedir_
DIR *dir
= NULL
;
285 dir
= opendir("/dev/shm");
290 return log_warning_errno(errno
, "Failed to open /dev/shm: %m");
293 return clean_posix_shm_internal(dir
, uid
, gid
);
296 static int clean_posix_mq(uid_t uid
, gid_t gid
) {
297 _cleanup_closedir_
DIR *dir
= NULL
;
301 dir
= opendir("/dev/mqueue");
306 return log_warning_errno(errno
, "Failed to open /dev/mqueue: %m");
309 FOREACH_DIRENT_ALL(de
, dir
, goto fail
) {
311 char fn
[1+strlen(de
->d_name
)+1];
313 if (dot_or_dot_dot(de
->d_name
))
316 if (fstatat(dirfd(dir
), de
->d_name
, &st
, AT_SYMLINK_NOFOLLOW
) < 0) {
320 ret
= log_warning_errno(errno
,
321 "Failed to stat() MQ segment %s: %m",
326 if (!match_uid_gid(st
.st_uid
, st
.st_gid
, uid
, gid
))
330 strcpy(fn
+1, de
->d_name
);
332 if (mq_unlink(fn
) < 0) {
336 ret
= log_warning_errno(errno
,
337 "Failed to unlink POSIX message queue %s: %m",
340 log_debug("Removed POSIX message queue %s", fn
);
346 return log_warning_errno(errno
, "Failed to read /dev/mqueue: %m");
349 int clean_ipc(uid_t uid
, gid_t gid
) {
352 /* Anything to do? */
353 if (!uid_is_valid(uid
) && !gid_is_valid(gid
))
356 /* Refuse to clean IPC of the root user */
357 if (uid
== 0 && gid
== 0)
360 r
= clean_sysvipc_shm(uid
, gid
);
364 r
= clean_sysvipc_sem(uid
, gid
);
368 r
= clean_sysvipc_msg(uid
, gid
);
372 r
= clean_posix_shm(uid
, gid
);
376 r
= clean_posix_mq(uid
, gid
);
383 int clean_ipc_by_uid(uid_t uid
) {
384 return clean_ipc(uid
, GID_INVALID
);
387 int clean_ipc_by_gid(gid_t gid
) {
388 return clean_ipc(UID_INVALID
, gid
);