]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journald-native.c
treewide: use log_*_errno whenever %m is in the format string
[thirdparty/systemd.git] / src / journal / journald-native.c
CommitLineData
0153028a
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 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 <unistd.h>
4871690d 23#include <stddef.h>
0153028a 24#include <sys/epoll.h>
c79e98ea 25#include <sys/mman.h>
0153028a
LP
26
27#include "socket-util.h"
1dfa7e79 28#include "path-util.h"
d682b3a7 29#include "selinux-util.h"
d025f1e4 30#include "journald-server.h"
0153028a
LP
31#include "journald-native.h"
32#include "journald-kmsg.h"
33#include "journald-console.h"
34#include "journald-syslog.h"
40b71e89 35#include "journald-wall.h"
a09abc4a 36#include "memfd-util.h"
0153028a 37
d18d46ec 38bool valid_user_field(const char *p, size_t l, bool allow_protected) {
0153028a
LP
39 const char *a;
40
41 /* We kinda enforce POSIX syntax recommendations for
42 environment variables here, but make a couple of additional
43 requirements.
44
45 http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
46
47 /* No empty field names */
48 if (l <= 0)
49 return false;
50
51 /* Don't allow names longer than 64 chars */
52 if (l > 64)
53 return false;
54
55 /* Variables starting with an underscore are protected */
d18d46ec 56 if (!allow_protected && p[0] == '_')
0153028a
LP
57 return false;
58
59 /* Don't allow digits as first character */
60 if (p[0] >= '0' && p[0] <= '9')
61 return false;
62
63 /* Only allow A-Z0-9 and '_' */
64 for (a = p; a < p + l; a++)
d18d46ec
ZJS
65 if ((*a < 'A' || *a > 'Z') &&
66 (*a < '0' || *a > '9') &&
67 *a != '_')
0153028a
LP
68 return false;
69
70 return true;
71}
72
3b3154df 73static bool allow_object_pid(const struct ucred *ucred) {
968f3196
ZJS
74 return ucred && ucred->uid == 0;
75}
76
0153028a
LP
77void server_process_native_message(
78 Server *s,
79 const void *buffer, size_t buffer_size,
3b3154df
LP
80 const struct ucred *ucred,
81 const struct timeval *tv,
0153028a
LP
82 const char *label, size_t label_len) {
83
84 struct iovec *iovec = NULL;
968f3196 85 unsigned n = 0, j, tn = (unsigned) -1;
0153028a 86 const char *p;
874bc134 87 size_t remaining, m = 0, entry_size = 0;
0153028a
LP
88 int priority = LOG_INFO;
89 char *identifier = NULL, *message = NULL;
968f3196 90 pid_t object_pid = 0;
0153028a
LP
91
92 assert(s);
93 assert(buffer || buffer_size == 0);
94
95 p = buffer;
96 remaining = buffer_size;
97
98 while (remaining > 0) {
99 const char *e, *q;
100
101 e = memchr(p, '\n', remaining);
102
103 if (!e) {
104 /* Trailing noise, let's ignore it, and flush what we collected */
105 log_debug("Received message with trailing noise, ignoring.");
106 break;
107 }
108
109 if (e == p) {
110 /* Entry separator */
874bc134
ZJS
111
112 if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
8c0b803b 113 log_debug("Entry is too big with %u properties and %zu bytes, ignoring.", n, entry_size);
874bc134
ZJS
114 continue;
115 }
116
968f3196 117 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
0153028a
LP
118 n = 0;
119 priority = LOG_INFO;
874bc134 120 entry_size = 0;
0153028a
LP
121
122 p++;
123 remaining--;
124 continue;
125 }
126
127 if (*p == '.' || *p == '#') {
128 /* Ignore control commands for now, and
129 * comments too. */
130 remaining -= (e - p) + 1;
131 p = e + 1;
132 continue;
133 }
134
135 /* A property follows */
136
f6422def 137 /* n received properties, +1 for _TRANSPORT */
8c0b803b 138 if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS + !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
968f3196
ZJS
139 log_oom();
140 break;
0153028a
LP
141 }
142
143 q = memchr(p, '=', e - p);
144 if (q) {
d18d46ec 145 if (valid_user_field(p, q - p, false)) {
0153028a
LP
146 size_t l;
147
148 l = e - p;
149
150 /* If the field name starts with an
151 * underscore, skip the variable,
152 * since that indidates a trusted
153 * field */
154 iovec[n].iov_base = (char*) p;
155 iovec[n].iov_len = l;
874bc134 156 entry_size += iovec[n].iov_len;
a174f94d 157 n++;
0153028a
LP
158
159 /* We need to determine the priority
160 * of this entry for the rate limiting
161 * logic */
162 if (l == 10 &&
2a0e0692 163 startswith(p, "PRIORITY=") &&
0153028a
LP
164 p[9] >= '0' && p[9] <= '9')
165 priority = (priority & LOG_FACMASK) | (p[9] - '0');
166
167 else if (l == 17 &&
2a0e0692 168 startswith(p, "SYSLOG_FACILITY=") &&
0153028a
LP
169 p[16] >= '0' && p[16] <= '9')
170 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
171
172 else if (l == 18 &&
2a0e0692 173 startswith(p, "SYSLOG_FACILITY=") &&
0153028a
LP
174 p[16] >= '0' && p[16] <= '9' &&
175 p[17] >= '0' && p[17] <= '9')
176 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
177
178 else if (l >= 19 &&
2a0e0692 179 startswith(p, "SYSLOG_IDENTIFIER=")) {
0153028a
LP
180 char *t;
181
182 t = strndup(p + 18, l - 18);
183 if (t) {
184 free(identifier);
185 identifier = t;
186 }
187 } else if (l >= 8 &&
2a0e0692 188 startswith(p, "MESSAGE=")) {
0153028a
LP
189 char *t;
190
191 t = strndup(p + 8, l - 8);
192 if (t) {
193 free(message);
194 message = t;
195 }
968f3196
ZJS
196 } else if (l > strlen("OBJECT_PID=") &&
197 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
2a0e0692 198 startswith(p, "OBJECT_PID=") &&
968f3196
ZJS
199 allow_object_pid(ucred)) {
200 char buf[DECIMAL_STR_MAX(pid_t)];
201 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
202 char_array_0(buf);
203
204 /* ignore error */
205 parse_pid(buf, &object_pid);
0153028a
LP
206 }
207 }
208
209 remaining -= (e - p) + 1;
210 p = e + 1;
211 continue;
212 } else {
213 le64_t l_le;
214 uint64_t l;
215 char *k;
216
217 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
218 log_debug("Failed to parse message, ignoring.");
219 break;
220 }
221
222 memcpy(&l_le, e + 1, sizeof(uint64_t));
223 l = le64toh(l_le);
224
505b6a61 225 if (l > DATA_SIZE_MAX) {
fa1c4b51 226 log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
505b6a61
LP
227 break;
228 }
229
230 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
0153028a
LP
231 e[1+sizeof(uint64_t)+l] != '\n') {
232 log_debug("Failed to parse message, ignoring.");
233 break;
234 }
235
236 k = malloc((e - p) + 1 + l);
237 if (!k) {
238 log_oom();
239 break;
240 }
241
242 memcpy(k, p, e - p);
243 k[e - p] = '=';
244 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
245
d18d46ec 246 if (valid_user_field(p, e - p, false)) {
0153028a
LP
247 iovec[n].iov_base = k;
248 iovec[n].iov_len = (e - p) + 1 + l;
874bc134 249 entry_size += iovec[n].iov_len;
a174f94d 250 n++;
0153028a
LP
251 } else
252 free(k);
253
254 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
255 p = e + 1 + sizeof(uint64_t) + l + 1;
256 }
257 }
258
259 if (n <= 0)
260 goto finish;
261
262 tn = n++;
263 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
874bc134
ZJS
264 entry_size += strlen("_TRANSPORT=journal");
265
266 if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
267 log_debug("Entry is too big with %u properties and %zu bytes, ignoring.",
268 n, entry_size);
269 goto finish;
270 }
0153028a
LP
271
272 if (message) {
273 if (s->forward_to_syslog)
274 server_forward_syslog(s, priority, identifier, message, ucred, tv);
275
276 if (s->forward_to_kmsg)
277 server_forward_kmsg(s, priority, identifier, message, ucred);
278
279 if (s->forward_to_console)
280 server_forward_console(s, priority, identifier, message, ucred);
40b71e89
ST
281
282 if (s->forward_to_wall)
283 server_forward_wall(s, priority, identifier, message, ucred);
0153028a
LP
284 }
285
968f3196 286 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
0153028a
LP
287
288finish:
289 for (j = 0; j < n; j++) {
290 if (j == tn)
291 continue;
292
293 if (iovec[j].iov_base < buffer ||
294 (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
295 free(iovec[j].iov_base);
296 }
297
298 free(iovec);
299 free(identifier);
300 free(message);
301}
302
303void server_process_native_file(
304 Server *s,
305 int fd,
3b3154df
LP
306 const struct ucred *ucred,
307 const struct timeval *tv,
0153028a
LP
308 const char *label, size_t label_len) {
309
310 struct stat st;
c79e98ea 311 bool sealed;
1dfa7e79 312 int r;
0153028a 313
c79e98ea
LP
314 /* Data is in the passed fd, since it didn't fit in a
315 * datagram. */
316
0153028a
LP
317 assert(s);
318 assert(fd >= 0);
319
c79e98ea
LP
320 /* If it's a memfd, check if it is sealed. If so, we can just
321 * use map it and use it, and do not need to copy the data
322 * out. */
73843b52 323 sealed = memfd_get_sealed(fd) > 0;
c79e98ea
LP
324
325 if (!sealed && (!ucred || ucred->uid != 0)) {
1dfa7e79
LP
326 _cleanup_free_ char *sl = NULL, *k = NULL;
327 const char *e;
328
c79e98ea
LP
329 /* If this is not a sealed memfd, and the peer is unknown or
330 * unprivileged, then verify the path. */
331
1dfa7e79
LP
332 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
333 log_oom();
334 return;
335 }
336
337 r = readlink_malloc(sl, &k);
338 if (r < 0) {
56f64d95 339 log_error_errno(errno, "readlink(%s) failed: %m", sl);
1dfa7e79
LP
340 return;
341 }
342
343 e = path_startswith(k, "/dev/shm/");
344 if (!e)
345 e = path_startswith(k, "/tmp/");
346 if (!e)
347 e = path_startswith(k, "/var/tmp/");
348 if (!e) {
349 log_error("Received file outside of allowed directories. Refusing.");
350 return;
351 }
352
0b507b17 353 if (!filename_is_safe(e)) {
1dfa7e79
LP
354 log_error("Received file in subdirectory of allowed directories. Refusing.");
355 return;
356 }
357 }
358
0153028a 359 if (fstat(fd, &st) < 0) {
56f64d95 360 log_error_errno(errno, "Failed to stat passed file, ignoring: %m");
0153028a
LP
361 return;
362 }
363
364 if (!S_ISREG(st.st_mode)) {
365 log_error("File passed is not regular. Ignoring.");
366 return;
367 }
368
369 if (st.st_size <= 0)
370 return;
371
372 if (st.st_size > ENTRY_SIZE_MAX) {
373 log_error("File passed too large. Ignoring.");
374 return;
375 }
376
c79e98ea
LP
377 if (sealed) {
378 void *p;
379 size_t ps;
380
381 /* The file is sealed, we can just map it and use it. */
0153028a 382
c79e98ea
LP
383 ps = PAGE_ALIGN(st.st_size);
384 p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
385 if (p == MAP_FAILED) {
56f64d95 386 log_error_errno(errno, "Failed to map memfd, ignoring: %m");
c79e98ea
LP
387 return;
388 }
389
390 server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
391 assert_se(munmap(p, ps) >= 0);
392 } else {
393 _cleanup_free_ void *p = NULL;
394 ssize_t n;
395
396 /* The file is not sealed, we can't map the file here, since
397 * clients might then truncate it and trigger a SIGBUS for
398 * us. So let's stupidly read it */
399
400 p = malloc(st.st_size);
401 if (!p) {
402 log_oom();
403 return;
404 }
405
406 n = pread(fd, p, st.st_size, 0);
407 if (n < 0)
da927ba9 408 log_error_errno(n, "Failed to read file, ignoring: %m");
c79e98ea
LP
409 else if (n > 0)
410 server_process_native_message(s, p, n, ucred, tv, label, label_len);
411 }
0153028a
LP
412}
413
414int server_open_native_socket(Server*s) {
3b3154df
LP
415 static const int one = 1;
416 int r;
0153028a
LP
417
418 assert(s);
419
420 if (s->native_fd < 0) {
f7a5bb28
ZJS
421 union sockaddr_union sa = {
422 .un.sun_family = AF_UNIX,
423 .un.sun_path = "/run/systemd/journal/socket",
424 };
0153028a
LP
425
426 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
427 if (s->native_fd < 0) {
56f64d95 428 log_error_errno(errno, "socket() failed: %m");
0153028a
LP
429 return -errno;
430 }
431
0153028a
LP
432 unlink(sa.un.sun_path);
433
434 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
435 if (r < 0) {
56f64d95 436 log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
0153028a
LP
437 return -errno;
438 }
439
440 chmod(sa.un.sun_path, 0666);
441 } else
442 fd_nonblock(s->native_fd, 1);
443
0153028a
LP
444 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
445 if (r < 0) {
56f64d95 446 log_error_errno(errno, "SO_PASSCRED failed: %m");
0153028a
LP
447 return -errno;
448 }
449
450#ifdef HAVE_SELINUX
6baa7db0 451 if (mac_selinux_use()) {
d682b3a7
LP
452 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
453 if (r < 0)
56f64d95 454 log_warning_errno(errno, "SO_PASSSEC failed: %m");
d682b3a7 455 }
0153028a
LP
456#endif
457
0153028a
LP
458 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
459 if (r < 0) {
56f64d95 460 log_error_errno(errno, "SO_TIMESTAMP failed: %m");
0153028a
LP
461 return -errno;
462 }
463
151b9b96 464 r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s);
23bbb0de
MS
465 if (r < 0)
466 return log_error_errno(r, "Failed to add native server fd to event loop: %m");
0153028a
LP
467
468 return 0;
469}