]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/clean-ipc.c
remove unused includes
[thirdparty/systemd.git] / src / shared / clean-ipc.c
CommitLineData
66cdd0f2
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#include <sys/ipc.h>
23#include <sys/shm.h>
24#include <sys/sem.h>
25#include <sys/msg.h>
26#include <sys/stat.h>
66cdd0f2
LP
27#include <fcntl.h>
28#include <dirent.h>
29#include <mqueue.h>
30
31#include "util.h"
32#include "strv.h"
33#include "clean-ipc.h"
34
35static int clean_sysvipc_shm(uid_t delete_uid) {
36 _cleanup_fclose_ FILE *f = NULL;
37 char line[LINE_MAX];
38 bool first = true;
39 int ret = 0;
40
41 f = fopen("/proc/sysvipc/shm", "re");
42 if (!f) {
43 if (errno == ENOENT)
44 return 0;
45
56f64d95 46 log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m");
66cdd0f2
LP
47 return -errno;
48 }
49
50 FOREACH_LINE(line, f, goto fail) {
51 unsigned n_attached;
52 pid_t cpid, lpid;
53 uid_t uid, cuid;
54 gid_t gid, cgid;
55 int shmid;
56
57 if (first) {
58 first = false;
59 continue;
60 }
61
62 truncate_nl(line);
63
64 if (sscanf(line, "%*i %i %*o %*u " PID_FMT " " PID_FMT " %u " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT,
65 &shmid, &cpid, &lpid, &n_attached, &uid, &gid, &cuid, &cgid) != 8)
66 continue;
67
68 if (n_attached > 0)
69 continue;
70
71 if (uid != delete_uid)
72 continue;
73
74 if (shmctl(shmid, IPC_RMID, NULL) < 0) {
75
76 /* Ignore entries that are already deleted */
77 if (errno == EIDRM || errno == EINVAL)
78 continue;
79
56f64d95 80 log_warning_errno(errno, "Failed to remove SysV shared memory segment %i: %m", shmid);
66cdd0f2
LP
81 ret = -errno;
82 }
83 }
84
85 return ret;
86
87fail:
56f64d95 88 log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m");
66cdd0f2
LP
89 return -errno;
90}
91
92static int clean_sysvipc_sem(uid_t delete_uid) {
93 _cleanup_fclose_ FILE *f = NULL;
94 char line[LINE_MAX];
95 bool first = true;
96 int ret = 0;
97
98 f = fopen("/proc/sysvipc/sem", "re");
99 if (!f) {
100 if (errno == ENOENT)
101 return 0;
102
56f64d95 103 log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m");
66cdd0f2
LP
104 return -errno;
105 }
106
107 FOREACH_LINE(line, f, goto fail) {
108 uid_t uid, cuid;
109 gid_t gid, cgid;
110 int semid;
111
112 if (first) {
113 first = false;
114 continue;
115 }
116
117 truncate_nl(line);
118
119 if (sscanf(line, "%*i %i %*o %*u " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT,
120 &semid, &uid, &gid, &cuid, &cgid) != 5)
121 continue;
122
123 if (uid != delete_uid)
124 continue;
125
126 if (semctl(semid, 0, IPC_RMID) < 0) {
127
128 /* Ignore entries that are already deleted */
129 if (errno == EIDRM || errno == EINVAL)
130 continue;
131
56f64d95 132 log_warning_errno(errno, "Failed to remove SysV semaphores object %i: %m", semid);
66cdd0f2
LP
133 ret = -errno;
134 }
135 }
136
137 return ret;
138
139fail:
56f64d95 140 log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m");
66cdd0f2
LP
141 return -errno;
142}
143
144static int clean_sysvipc_msg(uid_t delete_uid) {
145 _cleanup_fclose_ FILE *f = NULL;
146 char line[LINE_MAX];
147 bool first = true;
148 int ret = 0;
149
150 f = fopen("/proc/sysvipc/msg", "re");
151 if (!f) {
152 if (errno == ENOENT)
153 return 0;
154
56f64d95 155 log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m");
66cdd0f2
LP
156 return -errno;
157 }
158
159 FOREACH_LINE(line, f, goto fail) {
160 uid_t uid, cuid;
161 gid_t gid, cgid;
162 pid_t cpid, lpid;
163 int msgid;
164
165 if (first) {
166 first = false;
167 continue;
168 }
169
170 truncate_nl(line);
171
172 if (sscanf(line, "%*i %i %*o %*u %*u " PID_FMT " " PID_FMT " " UID_FMT " " GID_FMT " " UID_FMT " " GID_FMT,
173 &msgid, &cpid, &lpid, &uid, &gid, &cuid, &cgid) != 7)
174 continue;
175
176 if (uid != delete_uid)
177 continue;
178
179 if (msgctl(msgid, IPC_RMID, NULL) < 0) {
180
181 /* Ignore entries that are already deleted */
182 if (errno == EIDRM || errno == EINVAL)
183 continue;
184
56f64d95 185 log_warning_errno(errno, "Failed to remove SysV message queue %i: %m", msgid);
66cdd0f2
LP
186 ret = -errno;
187 }
188 }
189
190 return ret;
191
192fail:
56f64d95 193 log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m");
66cdd0f2
LP
194 return -errno;
195}
196
197static int clean_posix_shm_internal(DIR *dir, uid_t uid) {
198 struct dirent *de;
199 int ret = 0, r;
200
201 assert(dir);
202
203 FOREACH_DIRENT(de, dir, goto fail) {
204 struct stat st;
205
206 if (STR_IN_SET(de->d_name, "..", "."))
207 continue;
208
209 if (fstatat(dirfd(dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
210 if (errno == ENOENT)
211 continue;
212
56f64d95 213 log_warning_errno(errno, "Failed to stat() POSIX shared memory segment %s: %m", de->d_name);
66cdd0f2
LP
214 ret = -errno;
215 continue;
216 }
217
218 if (st.st_uid != uid)
219 continue;
220
221 if (S_ISDIR(st.st_mode)) {
222 _cleanup_closedir_ DIR *kid;
223
224 kid = xopendirat(dirfd(dir), de->d_name, O_NOFOLLOW|O_NOATIME);
225 if (!kid) {
226 if (errno != ENOENT) {
56f64d95 227 log_warning_errno(errno, "Failed to enter shared memory directory %s: %m", de->d_name);
66cdd0f2
LP
228 ret = -errno;
229 }
230 } else {
231 r = clean_posix_shm_internal(kid, uid);
232 if (r < 0)
233 ret = r;
234 }
235
236 if (unlinkat(dirfd(dir), de->d_name, AT_REMOVEDIR) < 0) {
237
238 if (errno == ENOENT)
239 continue;
240
56f64d95 241 log_warning_errno(errno, "Failed to remove POSIX shared memory directory %s: %m", de->d_name);
66cdd0f2
LP
242 ret = -errno;
243 }
244 } else {
245
246 if (unlinkat(dirfd(dir), de->d_name, 0) < 0) {
247
248 if (errno == ENOENT)
249 continue;
250
56f64d95 251 log_warning_errno(errno, "Failed to remove POSIX shared memory segment %s: %m", de->d_name);
66cdd0f2
LP
252 ret = -errno;
253 }
254 }
255 }
256
257 return ret;
258
259fail:
56f64d95 260 log_warning_errno(errno, "Failed to read /dev/shm: %m");
66cdd0f2
LP
261 return -errno;
262}
263
264static int clean_posix_shm(uid_t uid) {
265 _cleanup_closedir_ DIR *dir = NULL;
266
267 dir = opendir("/dev/shm");
268 if (!dir) {
269 if (errno == ENOENT)
270 return 0;
271
56f64d95 272 log_warning_errno(errno, "Failed to open /dev/shm: %m");
66cdd0f2
LP
273 return -errno;
274 }
275
276 return clean_posix_shm_internal(dir, uid);
277}
278
279static int clean_posix_mq(uid_t uid) {
280 _cleanup_closedir_ DIR *dir = NULL;
281 struct dirent *de;
282 int ret = 0;
283
284 dir = opendir("/dev/mqueue");
285 if (!dir) {
286 if (errno == ENOENT)
287 return 0;
288
56f64d95 289 log_warning_errno(errno, "Failed to open /dev/mqueue: %m");
66cdd0f2
LP
290 return -errno;
291 }
292
293 FOREACH_DIRENT(de, dir, goto fail) {
294 struct stat st;
295 char fn[1+strlen(de->d_name)+1];
296
297 if (STR_IN_SET(de->d_name, "..", "."))
298 continue;
299
300 if (fstatat(dirfd(dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
301 if (errno == ENOENT)
302 continue;
303
56f64d95 304 log_warning_errno(errno, "Failed to stat() MQ segment %s: %m", de->d_name);
66cdd0f2
LP
305 ret = -errno;
306 continue;
307 }
308
309 if (st.st_uid != uid)
310 continue;
311
312 fn[0] = '/';
313 strcpy(fn+1, de->d_name);
314
315 if (mq_unlink(fn) < 0) {
316 if (errno == ENOENT)
317 continue;
318
56f64d95 319 log_warning_errno(errno, "Failed to unlink POSIX message queue %s: %m", fn);
66cdd0f2
LP
320 ret = -errno;
321 }
322 }
323
324 return ret;
325
326fail:
56f64d95 327 log_warning_errno(errno, "Failed to read /dev/mqueue: %m");
66cdd0f2
LP
328 return -errno;
329}
330
331int clean_ipc(uid_t uid) {
332 int ret = 0, r;
333
f7dc3ab9
LP
334 /* Refuse to clean IPC of the root and system users */
335 if (uid <= SYSTEM_UID_MAX)
66cdd0f2
LP
336 return 0;
337
338 r = clean_sysvipc_shm(uid);
339 if (r < 0)
340 ret = r;
341
342 r = clean_sysvipc_sem(uid);
343 if (r < 0)
344 ret = r;
345
346 r = clean_sysvipc_msg(uid);
347 if (r < 0)
348 ret = r;
349
350 r = clean_posix_shm(uid);
351 if (r < 0)
352 ret = r;
353
354 r = clean_posix_mq(uid);
355 if (r < 0)
356 ret = r;
357
358 return ret;
359}