]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journald-native.c
journald: properly process multiple entries in the same native packet
[thirdparty/systemd.git] / src / journal / journald-native.c
CommitLineData
0153028a
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
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.
10
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.
15
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/>.
18***/
19
4871690d 20#include <stddef.h>
0153028a 21#include <sys/epoll.h>
c79e98ea 22#include <sys/mman.h>
1e603a48 23#include <sys/statvfs.h>
07630cea 24#include <unistd.h>
0153028a 25
b5efdb8a 26#include "alloc-util.h"
3ffd4af2 27#include "fd-util.h"
f4f15635 28#include "fs-util.h"
afc5dbf3 29#include "io-util.h"
b18453ed 30#include "journal-importer.h"
0153028a 31#include "journald-console.h"
07630cea 32#include "journald-kmsg.h"
3ffd4af2 33#include "journald-native.h"
07630cea 34#include "journald-server.h"
0153028a 35#include "journald-syslog.h"
40b71e89 36#include "journald-wall.h"
a09abc4a 37#include "memfd-util.h"
6bedfcbb 38#include "parse-util.h"
07630cea
LP
39#include "path-util.h"
40#include "selinux-util.h"
41#include "socket-util.h"
42#include "string-util.h"
731e10f3 43#include "unaligned.h"
0153028a 44
d18d46ec 45bool valid_user_field(const char *p, size_t l, bool allow_protected) {
0153028a
LP
46 const char *a;
47
48 /* We kinda enforce POSIX syntax recommendations for
49 environment variables here, but make a couple of additional
50 requirements.
51
52 http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
53
54 /* No empty field names */
55 if (l <= 0)
56 return false;
57
58 /* Don't allow names longer than 64 chars */
59 if (l > 64)
60 return false;
61
62 /* Variables starting with an underscore are protected */
d18d46ec 63 if (!allow_protected && p[0] == '_')
0153028a
LP
64 return false;
65
66 /* Don't allow digits as first character */
67 if (p[0] >= '0' && p[0] <= '9')
68 return false;
69
70 /* Only allow A-Z0-9 and '_' */
71 for (a = p; a < p + l; a++)
d18d46ec
ZJS
72 if ((*a < 'A' || *a > 'Z') &&
73 (*a < '0' || *a > '9') &&
74 *a != '_')
0153028a
LP
75 return false;
76
77 return true;
78}
79
3b3154df 80static bool allow_object_pid(const struct ucred *ucred) {
968f3196
ZJS
81 return ucred && ucred->uid == 0;
82}
83
68944f19 84static int server_process_entry(
0153028a 85 Server *s,
68944f19 86 const void *buffer, size_t *remaining,
3b3154df
LP
87 const struct ucred *ucred,
88 const struct timeval *tv,
0153028a
LP
89 const char *label, size_t label_len) {
90
68944f19
ZJS
91 /* Process a single entry from a native message.
92 * Returns 0 if nothing special happened and the message processing should continue,
93 * and a negative or positive value otherwise.
94 *
95 * Note that *remaining is altered on both success and failure. */
96
0153028a 97 struct iovec *iovec = NULL;
968f3196 98 unsigned n = 0, j, tn = (unsigned) -1;
0153028a 99 const char *p;
68944f19 100 size_t m = 0, entry_size = 0;
0153028a
LP
101 int priority = LOG_INFO;
102 char *identifier = NULL, *message = NULL;
968f3196 103 pid_t object_pid = 0;
68944f19 104 int r = 0;
0153028a
LP
105
106 p = buffer;
0153028a 107
68944f19 108 while (*remaining > 0) {
0153028a
LP
109 const char *e, *q;
110
68944f19 111 e = memchr(p, '\n', *remaining);
0153028a
LP
112
113 if (!e) {
114 /* Trailing noise, let's ignore it, and flush what we collected */
115 log_debug("Received message with trailing noise, ignoring.");
68944f19 116 r = 1; /* finish processing of the message */
0153028a
LP
117 break;
118 }
119
120 if (e == p) {
121 /* Entry separator */
68944f19
ZJS
122 *remaining -= 1;
123 break;
0153028a
LP
124 }
125
126 if (*p == '.' || *p == '#') {
127 /* Ignore control commands for now, and
128 * comments too. */
68944f19 129 *remaining -= (e - p) + 1;
0153028a
LP
130 p = e + 1;
131 continue;
132 }
133
134 /* A property follows */
135
12a717f8 136 /* n existing properties, 1 new, +1 for _TRANSPORT */
92ee6447 137 if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS)) {
68944f19 138 r = log_oom();
968f3196 139 break;
0153028a
LP
140 }
141
142 q = memchr(p, '=', e - p);
143 if (q) {
d18d46ec 144 if (valid_user_field(p, q - p, false)) {
0153028a
LP
145 size_t l;
146
147 l = e - p;
148
149 /* If the field name starts with an
150 * underscore, skip the variable,
151 * since that indidates a trusted
152 * field */
153 iovec[n].iov_base = (char*) p;
154 iovec[n].iov_len = l;
68944f19 155 entry_size += l;
a174f94d 156 n++;
0153028a
LP
157
158 /* We need to determine the priority
159 * of this entry for the rate limiting
160 * logic */
161 if (l == 10 &&
2a0e0692 162 startswith(p, "PRIORITY=") &&
0153028a
LP
163 p[9] >= '0' && p[9] <= '9')
164 priority = (priority & LOG_FACMASK) | (p[9] - '0');
165
166 else if (l == 17 &&
2a0e0692 167 startswith(p, "SYSLOG_FACILITY=") &&
0153028a
LP
168 p[16] >= '0' && p[16] <= '9')
169 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
170
171 else if (l == 18 &&
2a0e0692 172 startswith(p, "SYSLOG_FACILITY=") &&
0153028a
LP
173 p[16] >= '0' && p[16] <= '9' &&
174 p[17] >= '0' && p[17] <= '9')
175 priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
176
177 else if (l >= 19 &&
2a0e0692 178 startswith(p, "SYSLOG_IDENTIFIER=")) {
0153028a
LP
179 char *t;
180
181 t = strndup(p + 18, l - 18);
182 if (t) {
183 free(identifier);
184 identifier = t;
185 }
1f6b4113 186
0153028a 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 }
1f6b4113 196
968f3196
ZJS
197 } else if (l > strlen("OBJECT_PID=") &&
198 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
2a0e0692 199 startswith(p, "OBJECT_PID=") &&
968f3196
ZJS
200 allow_object_pid(ucred)) {
201 char buf[DECIMAL_STR_MAX(pid_t)];
202 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
daf535a3 203 buf[l-strlen("OBJECT_PID=")] = '\0';
968f3196 204
68944f19 205 (void) parse_pid(buf, &object_pid);
0153028a
LP
206 }
207 }
208
68944f19 209 *remaining -= (e - p) + 1;
0153028a
LP
210 p = e + 1;
211 continue;
212 } else {
0153028a
LP
213 uint64_t l;
214 char *k;
215
68944f19 216 if (*remaining < e - p + 1 + sizeof(uint64_t) + 1) {
0153028a
LP
217 log_debug("Failed to parse message, ignoring.");
218 break;
219 }
220
731e10f3 221 l = unaligned_read_le64(e + 1);
0153028a 222
505b6a61 223 if (l > DATA_SIZE_MAX) {
fa1c4b51 224 log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
505b6a61
LP
225 break;
226 }
227
68944f19 228 if ((uint64_t) *remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
0153028a
LP
229 e[1+sizeof(uint64_t)+l] != '\n') {
230 log_debug("Failed to parse message, ignoring.");
231 break;
232 }
233
234 k = malloc((e - p) + 1 + l);
235 if (!k) {
236 log_oom();
237 break;
238 }
239
240 memcpy(k, p, e - p);
241 k[e - p] = '=';
242 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
243
d18d46ec 244 if (valid_user_field(p, e - p, false)) {
0153028a
LP
245 iovec[n].iov_base = k;
246 iovec[n].iov_len = (e - p) + 1 + l;
874bc134 247 entry_size += iovec[n].iov_len;
a174f94d 248 n++;
0153028a
LP
249 } else
250 free(k);
251
68944f19 252 *remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
0153028a
LP
253 p = e + 1 + sizeof(uint64_t) + l + 1;
254 }
255 }
256
68944f19
ZJS
257 if (n <= 0) {
258 r = 1;
0153028a 259 goto finish;
68944f19 260 }
0153028a
LP
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)
b6a20306 274 server_forward_syslog(s, syslog_fixup_facility(priority), identifier, message, ucred, tv);
0153028a
LP
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 ||
68944f19 294 (const char*) iovec[j].iov_base >= p + *remaining)
0153028a
LP
295 free(iovec[j].iov_base);
296 }
297
298 free(iovec);
299 free(identifier);
300 free(message);
68944f19
ZJS
301
302 return r;
303}
304
305void server_process_native_message(
306 Server *s,
307 const void *buffer, size_t buffer_size,
308 const struct ucred *ucred,
309 const struct timeval *tv,
310 const char *label, size_t label_len) {
311
312 int r;
313 size_t remaining = buffer_size;
314
315 assert(s);
316 assert(buffer || buffer_size == 0);
317
318 do {
319 r = server_process_entry(s,
320 (const uint8_t*) buffer + (buffer_size - remaining), &remaining,
321 ucred, tv, label, label_len);
322 } while (r == 0);
0153028a
LP
323}
324
325void server_process_native_file(
326 Server *s,
327 int fd,
3b3154df
LP
328 const struct ucred *ucred,
329 const struct timeval *tv,
0153028a
LP
330 const char *label, size_t label_len) {
331
332 struct stat st;
c79e98ea 333 bool sealed;
1dfa7e79 334 int r;
0153028a 335
c79e98ea
LP
336 /* Data is in the passed fd, since it didn't fit in a
337 * datagram. */
338
0153028a
LP
339 assert(s);
340 assert(fd >= 0);
341
c79e98ea
LP
342 /* If it's a memfd, check if it is sealed. If so, we can just
343 * use map it and use it, and do not need to copy the data
344 * out. */
73843b52 345 sealed = memfd_get_sealed(fd) > 0;
c79e98ea
LP
346
347 if (!sealed && (!ucred || ucred->uid != 0)) {
1dfa7e79
LP
348 _cleanup_free_ char *sl = NULL, *k = NULL;
349 const char *e;
350
c79e98ea
LP
351 /* If this is not a sealed memfd, and the peer is unknown or
352 * unprivileged, then verify the path. */
353
1dfa7e79
LP
354 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
355 log_oom();
356 return;
357 }
358
359 r = readlink_malloc(sl, &k);
360 if (r < 0) {
709f6e46 361 log_error_errno(r, "readlink(%s) failed: %m", sl);
1dfa7e79
LP
362 return;
363 }
364
365 e = path_startswith(k, "/dev/shm/");
366 if (!e)
367 e = path_startswith(k, "/tmp/");
368 if (!e)
369 e = path_startswith(k, "/var/tmp/");
370 if (!e) {
371 log_error("Received file outside of allowed directories. Refusing.");
372 return;
373 }
374
ae6c3cc0 375 if (!filename_is_valid(e)) {
1dfa7e79
LP
376 log_error("Received file in subdirectory of allowed directories. Refusing.");
377 return;
378 }
379 }
380
0153028a 381 if (fstat(fd, &st) < 0) {
56f64d95 382 log_error_errno(errno, "Failed to stat passed file, ignoring: %m");
0153028a
LP
383 return;
384 }
385
386 if (!S_ISREG(st.st_mode)) {
387 log_error("File passed is not regular. Ignoring.");
388 return;
389 }
390
391 if (st.st_size <= 0)
392 return;
393
394 if (st.st_size > ENTRY_SIZE_MAX) {
395 log_error("File passed too large. Ignoring.");
396 return;
397 }
398
c79e98ea
LP
399 if (sealed) {
400 void *p;
401 size_t ps;
402
403 /* The file is sealed, we can just map it and use it. */
0153028a 404
c79e98ea
LP
405 ps = PAGE_ALIGN(st.st_size);
406 p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
407 if (p == MAP_FAILED) {
56f64d95 408 log_error_errno(errno, "Failed to map memfd, ignoring: %m");
c79e98ea
LP
409 return;
410 }
411
412 server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
413 assert_se(munmap(p, ps) >= 0);
414 } else {
415 _cleanup_free_ void *p = NULL;
1e603a48 416 struct statvfs vfs;
c79e98ea
LP
417 ssize_t n;
418
1e603a48
LP
419 if (fstatvfs(fd, &vfs) < 0) {
420 log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m");
421 return;
422 }
423
424 /* Refuse operating on file systems that have
425 * mandatory locking enabled, see:
426 *
427 * https://github.com/systemd/systemd/issues/1822
428 */
429 if (vfs.f_flag & ST_MANDLOCK) {
430 log_error("Received file descriptor from file system with mandatory locking enable, refusing.");
431 return;
432 }
433
434 /* Make the fd non-blocking. On regular files this has
435 * the effect of bypassing mandatory locking. Of
436 * course, this should normally not be necessary given
437 * the check above, but let's better be safe than
438 * sorry, after all NFS is pretty confusing regarding
439 * file system flags, and we better don't trust it,
440 * and so is SMB. */
441 r = fd_nonblock(fd, true);
442 if (r < 0) {
443 log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m");
444 return;
445 }
446
c79e98ea
LP
447 /* The file is not sealed, we can't map the file here, since
448 * clients might then truncate it and trigger a SIGBUS for
449 * us. So let's stupidly read it */
450
451 p = malloc(st.st_size);
452 if (!p) {
453 log_oom();
454 return;
455 }
456
457 n = pread(fd, p, st.st_size, 0);
458 if (n < 0)
c3753458 459 log_error_errno(errno, "Failed to read file, ignoring: %m");
c79e98ea
LP
460 else if (n > 0)
461 server_process_native_message(s, p, n, ucred, tv, label, label_len);
462 }
0153028a
LP
463}
464
465int server_open_native_socket(Server*s) {
fc2fffe7
LP
466
467 static const union sockaddr_union sa = {
468 .un.sun_family = AF_UNIX,
469 .un.sun_path = "/run/systemd/journal/socket",
470 };
3b3154df
LP
471 static const int one = 1;
472 int r;
0153028a
LP
473
474 assert(s);
475
476 if (s->native_fd < 0) {
0153028a 477 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710
MS
478 if (s->native_fd < 0)
479 return log_error_errno(errno, "socket() failed: %m");
0153028a 480
fc2fffe7 481 (void) unlink(sa.un.sun_path);
0153028a 482
fc2fffe7 483 r = bind(s->native_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
4a62c710
MS
484 if (r < 0)
485 return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
0153028a 486
4a61c3e5 487 (void) chmod(sa.un.sun_path, 0666);
0153028a
LP
488 } else
489 fd_nonblock(s->native_fd, 1);
490
0153028a 491 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
4a62c710
MS
492 if (r < 0)
493 return log_error_errno(errno, "SO_PASSCRED failed: %m");
0153028a
LP
494
495#ifdef HAVE_SELINUX
6355e756 496 if (mac_selinux_have()) {
d682b3a7
LP
497 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
498 if (r < 0)
56f64d95 499 log_warning_errno(errno, "SO_PASSSEC failed: %m");
d682b3a7 500 }
0153028a
LP
501#endif
502
0153028a 503 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
4a62c710
MS
504 if (r < 0)
505 return log_error_errno(errno, "SO_TIMESTAMP failed: %m");
0153028a 506
8531ae70 507 r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, server_process_datagram, s);
23bbb0de
MS
508 if (r < 0)
509 return log_error_errno(r, "Failed to add native server fd to event loop: %m");
0153028a 510
48cef295
VC
511 r = sd_event_source_set_priority(s->native_event_source, SD_EVENT_PRIORITY_NORMAL+5);
512 if (r < 0)
513 return log_error_errno(r, "Failed to adjust native event source priority: %m");
514
0153028a
LP
515 return 0;
516}