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