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