]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journald-native.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2011 Lennart Poettering
11 #include <sys/statvfs.h>
14 #include "alloc-util.h"
18 #include "journal-importer.h"
19 #include "journal-util.h"
20 #include "journald-console.h"
21 #include "journald-kmsg.h"
22 #include "journald-native.h"
23 #include "journald-server.h"
24 #include "journald-syslog.h"
25 #include "journald-wall.h"
26 #include "memfd-util.h"
27 #include "parse-util.h"
28 #include "path-util.h"
29 #include "process-util.h"
30 #include "selinux-util.h"
31 #include "socket-util.h"
32 #include "string-util.h"
33 #include "unaligned.h"
35 static bool allow_object_pid(const struct ucred
*ucred
) {
36 return ucred
&& ucred
->uid
== 0;
39 static void server_process_entry_meta(
40 const char *p
, size_t l
,
41 const struct ucred
*ucred
,
47 /* We need to determine the priority of this entry for the rate limiting logic */
50 startswith(p
, "PRIORITY=") &&
51 p
[9] >= '0' && p
[9] <= '9')
52 *priority
= (*priority
& LOG_FACMASK
) | (p
[9] - '0');
55 startswith(p
, "SYSLOG_FACILITY=") &&
56 p
[16] >= '0' && p
[16] <= '9')
57 *priority
= (*priority
& LOG_PRIMASK
) | ((p
[16] - '0') << 3);
60 startswith(p
, "SYSLOG_FACILITY=") &&
61 p
[16] >= '0' && p
[16] <= '9' &&
62 p
[17] >= '0' && p
[17] <= '9')
63 *priority
= (*priority
& LOG_PRIMASK
) | (((p
[16] - '0')*10 + (p
[17] - '0')) << 3);
66 startswith(p
, "SYSLOG_IDENTIFIER=")) {
69 t
= strndup(p
+ 18, l
- 18);
76 startswith(p
, "MESSAGE=")) {
79 t
= strndup(p
+ 8, l
- 8);
85 } else if (l
> STRLEN("OBJECT_PID=") &&
86 l
< STRLEN("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t
) &&
87 startswith(p
, "OBJECT_PID=") &&
88 allow_object_pid(ucred
)) {
89 char buf
[DECIMAL_STR_MAX(pid_t
)];
90 memcpy(buf
, p
+ STRLEN("OBJECT_PID="),
91 l
- STRLEN("OBJECT_PID="));
92 buf
[l
-STRLEN("OBJECT_PID=")] = '\0';
94 (void) parse_pid(buf
, object_pid
);
98 static int server_process_entry(
100 const void *buffer
, size_t *remaining
,
101 ClientContext
*context
,
102 const struct ucred
*ucred
,
103 const struct timeval
*tv
,
104 const char *label
, size_t label_len
) {
106 /* Process a single entry from a native message. Returns 0 if nothing special happened and the message
107 * processing should continue, and a negative or positive value otherwise.
109 * Note that *remaining is altered on both success and failure. */
111 size_t n
= 0, j
, tn
= (size_t) -1, m
= 0, entry_size
= 0;
112 char *identifier
= NULL
, *message
= NULL
;
113 struct iovec
*iovec
= NULL
;
114 int priority
= LOG_INFO
;
115 pid_t object_pid
= 0;
121 while (*remaining
> 0) {
124 e
= memchr(p
, '\n', *remaining
);
127 /* Trailing noise, let's ignore it, and flush what we collected */
128 log_debug("Received message with trailing noise, ignoring.");
129 r
= 1; /* finish processing of the message */
134 /* Entry separator */
139 if (IN_SET(*p
, '.', '#')) {
140 /* Ignore control commands for now, and
142 *remaining
-= (e
- p
) + 1;
147 /* A property follows */
149 /* n existing properties, 1 new, +1 for _TRANSPORT */
150 if (!GREEDY_REALLOC(iovec
, m
,
152 N_IOVEC_META_FIELDS
+ N_IOVEC_OBJECT_FIELDS
+
153 client_context_extra_fields_n_iovec(context
))) {
158 q
= memchr(p
, '=', e
- p
);
160 if (journal_field_valid(p
, q
- p
, false)) {
165 /* If the field name starts with an underscore, skip the variable, since that indicates
167 iovec
[n
++] = IOVEC_MAKE((char*) p
, l
);
170 server_process_entry_meta(p
, l
, ucred
,
177 *remaining
-= (e
- p
) + 1;
184 if (*remaining
< e
- p
+ 1 + sizeof(uint64_t) + 1) {
185 log_debug("Failed to parse message, ignoring.");
189 l
= unaligned_read_le64(e
+ 1);
191 if (l
> DATA_SIZE_MAX
) {
192 log_debug("Received binary data block of %"PRIu64
" bytes is too large, ignoring.", l
);
196 if ((uint64_t) *remaining
< e
- p
+ 1 + sizeof(uint64_t) + l
+ 1 ||
197 e
[1+sizeof(uint64_t)+l
] != '\n') {
198 log_debug("Failed to parse message, ignoring.");
202 k
= malloc((e
- p
) + 1 + l
);
210 memcpy(k
+ (e
- p
) + 1, e
+ 1 + sizeof(uint64_t), l
);
212 if (journal_field_valid(p
, e
- p
, false)) {
213 iovec
[n
].iov_base
= k
;
214 iovec
[n
].iov_len
= (e
- p
) + 1 + l
;
215 entry_size
+= iovec
[n
].iov_len
;
218 server_process_entry_meta(k
, (e
- p
) + 1 + l
, ucred
,
226 *remaining
-= (e
- p
) + 1 + sizeof(uint64_t) + l
+ 1;
227 p
= e
+ 1 + sizeof(uint64_t) + l
+ 1;
236 if (!client_context_test_priority(context
, priority
)) {
242 iovec
[tn
] = IOVEC_MAKE_STRING("_TRANSPORT=journal");
243 entry_size
+= STRLEN("_TRANSPORT=journal");
245 if (entry_size
+ n
+ 1 > ENTRY_SIZE_MAX
) { /* data + separators + trailer */
246 log_debug("Entry is too big with %zu properties and %zu bytes, ignoring.", n
, entry_size
);
251 if (s
->forward_to_syslog
)
252 server_forward_syslog(s
, syslog_fixup_facility(priority
), identifier
, message
, ucred
, tv
);
254 if (s
->forward_to_kmsg
)
255 server_forward_kmsg(s
, priority
, identifier
, message
, ucred
);
257 if (s
->forward_to_console
)
258 server_forward_console(s
, priority
, identifier
, message
, ucred
);
260 if (s
->forward_to_wall
)
261 server_forward_wall(s
, priority
, identifier
, message
, ucred
);
264 server_dispatch_message(s
, iovec
, n
, m
, context
, tv
, priority
, object_pid
);
267 for (j
= 0; j
< n
; j
++) {
271 if (iovec
[j
].iov_base
< buffer
||
272 (const char*) iovec
[j
].iov_base
>= p
+ *remaining
)
273 free(iovec
[j
].iov_base
);
283 void server_process_native_message(
285 const void *buffer
, size_t buffer_size
,
286 const struct ucred
*ucred
,
287 const struct timeval
*tv
,
288 const char *label
, size_t label_len
) {
290 size_t remaining
= buffer_size
;
291 ClientContext
*context
= NULL
;
295 assert(buffer
|| buffer_size
== 0);
297 if (ucred
&& pid_is_valid(ucred
->pid
)) {
298 r
= client_context_get(s
, ucred
->pid
, ucred
, label
, label_len
, NULL
, &context
);
300 log_warning_errno(r
, "Failed to retrieve credentials for PID " PID_FMT
", ignoring: %m", ucred
->pid
);
304 r
= server_process_entry(s
,
305 (const uint8_t*) buffer
+ (buffer_size
- remaining
), &remaining
,
306 context
, ucred
, tv
, label
, label_len
);
310 void server_process_native_file(
313 const struct ucred
*ucred
,
314 const struct timeval
*tv
,
315 const char *label
, size_t label_len
) {
321 /* Data is in the passed fd, since it didn't fit in a
327 /* If it's a memfd, check if it is sealed. If so, we can just
328 * use map it and use it, and do not need to copy the data
330 sealed
= memfd_get_sealed(fd
) > 0;
332 if (!sealed
&& (!ucred
|| ucred
->uid
!= 0)) {
333 _cleanup_free_
char *k
= NULL
;
336 /* If this is not a sealed memfd, and the peer is unknown or
337 * unprivileged, then verify the path. */
339 r
= fd_get_path(fd
, &k
);
341 log_error_errno(r
, "readlink(/proc/self/fd/%i) failed: %m", fd
);
345 e
= path_startswith(k
, "/dev/shm/");
347 e
= path_startswith(k
, "/tmp/");
349 e
= path_startswith(k
, "/var/tmp/");
351 log_error("Received file outside of allowed directories. Refusing.");
355 if (!filename_is_valid(e
)) {
356 log_error("Received file in subdirectory of allowed directories. Refusing.");
361 if (fstat(fd
, &st
) < 0) {
362 log_error_errno(errno
, "Failed to stat passed file, ignoring: %m");
366 if (!S_ISREG(st
.st_mode
)) {
367 log_error("File passed is not regular. Ignoring.");
374 if (st
.st_size
> ENTRY_SIZE_MAX
) {
375 log_error("File passed too large. Ignoring.");
383 /* The file is sealed, we can just map it and use it. */
385 ps
= PAGE_ALIGN(st
.st_size
);
386 p
= mmap(NULL
, ps
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
387 if (p
== MAP_FAILED
) {
388 log_error_errno(errno
, "Failed to map memfd, ignoring: %m");
392 server_process_native_message(s
, p
, st
.st_size
, ucred
, tv
, label
, label_len
);
393 assert_se(munmap(p
, ps
) >= 0);
395 _cleanup_free_
void *p
= NULL
;
399 if (fstatvfs(fd
, &vfs
) < 0) {
400 log_error_errno(errno
, "Failed to stat file system of passed file, ignoring: %m");
404 /* Refuse operating on file systems that have
405 * mandatory locking enabled, see:
407 * https://github.com/systemd/systemd/issues/1822
409 if (vfs
.f_flag
& ST_MANDLOCK
) {
410 log_error("Received file descriptor from file system with mandatory locking enabled, refusing.");
414 /* Make the fd non-blocking. On regular files this has
415 * the effect of bypassing mandatory locking. Of
416 * course, this should normally not be necessary given
417 * the check above, but let's better be safe than
418 * sorry, after all NFS is pretty confusing regarding
419 * file system flags, and we better don't trust it,
421 r
= fd_nonblock(fd
, true);
423 log_error_errno(r
, "Failed to make fd non-blocking, ignoring: %m");
427 /* The file is not sealed, we can't map the file here, since
428 * clients might then truncate it and trigger a SIGBUS for
429 * us. So let's stupidly read it */
431 p
= malloc(st
.st_size
);
437 n
= pread(fd
, p
, st
.st_size
, 0);
439 log_error_errno(errno
, "Failed to read file, ignoring: %m");
441 server_process_native_message(s
, p
, n
, ucred
, tv
, label
, label_len
);
445 int server_open_native_socket(Server
*s
) {
447 static const union sockaddr_union sa
= {
448 .un
.sun_family
= AF_UNIX
,
449 .un
.sun_path
= "/run/systemd/journal/socket",
451 static const int one
= 1;
456 if (s
->native_fd
< 0) {
457 s
->native_fd
= socket(AF_UNIX
, SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
458 if (s
->native_fd
< 0)
459 return log_error_errno(errno
, "socket() failed: %m");
461 (void) unlink(sa
.un
.sun_path
);
463 r
= bind(s
->native_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
));
465 return log_error_errno(errno
, "bind(%s) failed: %m", sa
.un
.sun_path
);
467 (void) chmod(sa
.un
.sun_path
, 0666);
469 fd_nonblock(s
->native_fd
, 1);
471 r
= setsockopt(s
->native_fd
, SOL_SOCKET
, SO_PASSCRED
, &one
, sizeof(one
));
473 return log_error_errno(errno
, "SO_PASSCRED failed: %m");
476 if (mac_selinux_use()) {
477 r
= setsockopt(s
->native_fd
, SOL_SOCKET
, SO_PASSSEC
, &one
, sizeof(one
));
479 log_warning_errno(errno
, "SO_PASSSEC failed: %m");
483 r
= setsockopt(s
->native_fd
, SOL_SOCKET
, SO_TIMESTAMP
, &one
, sizeof(one
));
485 return log_error_errno(errno
, "SO_TIMESTAMP failed: %m");
487 r
= sd_event_add_io(s
->event
, &s
->native_event_source
, s
->native_fd
, EPOLLIN
, server_process_datagram
, s
);
489 return log_error_errno(r
, "Failed to add native server fd to event loop: %m");
491 r
= sd_event_source_set_priority(s
->native_event_source
, SD_EVENT_PRIORITY_NORMAL
+5);
493 return log_error_errno(r
, "Failed to adjust native event source priority: %m");