1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
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.
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.
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/>.
24 #include <sys/epoll.h>
27 #include "socket-util.h"
28 #include "path-util.h"
29 #include "selinux-util.h"
30 #include "journald-server.h"
31 #include "journald-native.h"
32 #include "journald-kmsg.h"
33 #include "journald-console.h"
34 #include "journald-syslog.h"
35 #include "journald-wall.h"
37 bool valid_user_field(const char *p, size_t l, bool allow_protected) {
40 /* We kinda enforce POSIX syntax recommendations for
41 environment variables here, but make a couple of additional
44 http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
46 /* No empty field names */
50 /* Don't allow names longer than 64 chars */
54 /* Variables starting with an underscore are protected */
55 if (!allow_protected && p[0] == '_')
58 /* Don't allow digits as first character */
59 if (p[0] >= '0' && p[0] <= '9')
62 /* Only allow A-Z0-9 and '_' */
63 for (a = p; a < p + l; a++)
64 if ((*a < 'A' || *a > 'Z') &&
65 (*a < '0' || *a > '9') &&
72 static bool allow_object_pid(struct ucred *ucred) {
73 return ucred && ucred->uid == 0;
76 void server_process_native_message(
78 const void *buffer, size_t buffer_size,
81 const char *label, size_t label_len) {
83 struct iovec *iovec = NULL;
84 unsigned n = 0, j, tn = (unsigned) -1;
86 size_t remaining, m = 0, entry_size = 0;
87 int priority = LOG_INFO;
88 char *identifier = NULL, *message = NULL;
92 assert(buffer || buffer_size == 0);
95 remaining = buffer_size;
97 while (remaining > 0) {
100 e = memchr(p, '\n', remaining);
103 /* Trailing noise, let's ignore it, and flush what we collected */
104 log_debug("Received message with trailing noise, ignoring.");
109 /* Entry separator */
111 if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
112 log_debug("Entry is too big with %u properties and %zu bytes, ignoring.", n, entry_size);
116 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
126 if (*p == '.' || *p == '#') {
127 /* Ignore control commands for now, and
129 remaining -= (e - p) + 1;
134 /* A property follows */
136 /* n received properties, +1 for _TRANSPORT */
137 if (!GREEDY_REALLOC(iovec, m, n + 1 + N_IOVEC_META_FIELDS + !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
142 q = memchr(p, '=', e - p);
144 if (valid_user_field(p, q - p, false)) {
149 /* If the field name starts with an
150 * underscore, skip the variable,
151 * since that indidates a trusted
153 iovec[n].iov_base = (char*) p;
154 iovec[n].iov_len = l;
155 entry_size += iovec[n].iov_len;
158 /* We need to determine the priority
159 * of this entry for the rate limiting
162 startswith(p, "PRIORITY=") &&
163 p[9] >= '0' && p[9] <= '9')
164 priority = (priority & LOG_FACMASK) | (p[9] - '0');
167 startswith(p, "SYSLOG_FACILITY=") &&
168 p[16] >= '0' && p[16] <= '9')
169 priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
172 startswith(p, "SYSLOG_FACILITY=") &&
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);
178 startswith(p, "SYSLOG_IDENTIFIER=")) {
181 t = strndup(p + 18, l - 18);
187 startswith(p, "MESSAGE=")) {
190 t = strndup(p + 8, l - 8);
195 } else if (l > strlen("OBJECT_PID=") &&
196 l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
197 startswith(p, "OBJECT_PID=") &&
198 allow_object_pid(ucred)) {
199 char buf[DECIMAL_STR_MAX(pid_t)];
200 memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
204 parse_pid(buf, &object_pid);
208 remaining -= (e - p) + 1;
216 if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
217 log_debug("Failed to parse message, ignoring.");
221 memcpy(&l_le, e + 1, sizeof(uint64_t));
224 if (l > DATA_SIZE_MAX) {
225 log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
229 if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
230 e[1+sizeof(uint64_t)+l] != '\n') {
231 log_debug("Failed to parse message, ignoring.");
235 k = malloc((e - p) + 1 + l);
243 memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
245 if (valid_user_field(p, e - p, false)) {
246 iovec[n].iov_base = k;
247 iovec[n].iov_len = (e - p) + 1 + l;
248 entry_size += iovec[n].iov_len;
253 remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
254 p = e + 1 + sizeof(uint64_t) + l + 1;
262 IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
263 entry_size += strlen("_TRANSPORT=journal");
265 if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
266 log_debug("Entry is too big with %u properties and %zu bytes, ignoring.",
272 if (s->forward_to_syslog)
273 server_forward_syslog(s, priority, identifier, message, ucred, tv);
275 if (s->forward_to_kmsg)
276 server_forward_kmsg(s, priority, identifier, message, ucred);
278 if (s->forward_to_console)
279 server_forward_console(s, priority, identifier, message, ucred);
281 if (s->forward_to_wall)
282 server_forward_wall(s, priority, identifier, message, ucred);
285 server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
288 for (j = 0; j < n; j++) {
292 if (iovec[j].iov_base < buffer ||
293 (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
294 free(iovec[j].iov_base);
302 void server_process_native_file(
307 const char *label, size_t label_len) {
313 /* Data is in the passed fd, since it didn't fit in a
319 /* If it's a memfd, check if it is sealed. If so, we can just
320 * use map it and use it, and do not need to copy the data
322 r = fcntl(fd, F_GET_SEALS);
324 (r & (F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL)) == (F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_SEAL);
326 if (!sealed && (!ucred || ucred->uid != 0)) {
327 _cleanup_free_ char *sl = NULL, *k = NULL;
330 /* If this is not a sealed memfd, and the peer is unknown or
331 * unprivileged, then verify the path. */
333 if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
338 r = readlink_malloc(sl, &k);
340 log_error("readlink(%s) failed: %m", sl);
344 e = path_startswith(k, "/dev/shm/");
346 e = path_startswith(k, "/tmp/");
348 e = path_startswith(k, "/var/tmp/");
350 log_error("Received file outside of allowed directories. Refusing.");
354 if (!filename_is_safe(e)) {
355 log_error("Received file in subdirectory of allowed directories. Refusing.");
360 if (fstat(fd, &st) < 0) {
361 log_error("Failed to stat passed file, ignoring: %m");
365 if (!S_ISREG(st.st_mode)) {
366 log_error("File passed is not regular. Ignoring.");
373 if (st.st_size > ENTRY_SIZE_MAX) {
374 log_error("File passed too large. Ignoring.");
382 /* The file is sealed, we can just map it and use it. */
384 ps = PAGE_ALIGN(st.st_size);
385 p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
386 if (p == MAP_FAILED) {
387 log_error("Failed to map memfd, ignoring: %m");
391 server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
392 assert_se(munmap(p, ps) >= 0);
394 _cleanup_free_ void *p = NULL;
397 /* The file is not sealed, we can't map the file here, since
398 * clients might then truncate it and trigger a SIGBUS for
399 * us. So let's stupidly read it */
401 p = malloc(st.st_size);
407 n = pread(fd, p, st.st_size, 0);
409 log_error("Failed to read file, ignoring: %s", strerror(-n));
411 server_process_native_message(s, p, n, ucred, tv, label, label_len);
415 int server_open_native_socket(Server*s) {
420 if (s->native_fd < 0) {
421 union sockaddr_union sa = {
422 .un.sun_family = AF_UNIX,
423 .un.sun_path = "/run/systemd/journal/socket",
426 s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
427 if (s->native_fd < 0) {
428 log_error("socket() failed: %m");
432 unlink(sa.un.sun_path);
434 r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
436 log_error("bind(%s) failed: %m", sa.un.sun_path);
440 chmod(sa.un.sun_path, 0666);
442 fd_nonblock(s->native_fd, 1);
445 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
447 log_error("SO_PASSCRED failed: %m");
452 if (mac_selinux_use()) {
454 r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
456 log_warning("SO_PASSSEC failed: %m");
461 r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
463 log_error("SO_TIMESTAMP failed: %m");
467 r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s);
469 log_error("Failed to add native server fd to event loop: %s", strerror(-r));