0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering This file is part of systemd.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering Copyright 2011 Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (at your option) any later version.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering systemd is distributed in the hope that it will be useful, but
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering Lesser General Public License for more details.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmekbool valid_user_field(const char *p, size_t l, bool allow_protected) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering const char *a;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* We kinda enforce POSIX syntax recommendations for
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering environment variables here, but make a couple of additional
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* No empty field names */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Don't allow names longer than 64 chars */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Variables starting with an underscore are protected */
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek if (!allow_protected && p[0] == '_')
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Don't allow digits as first character */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Only allow A-Z0-9 and '_' */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering for (a = p; a < p + l; a++)
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poetteringstatic bool allow_object_pid(const struct ucred *ucred) {
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek return ucred && ucred->uid == 0;
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek unsigned n = 0, j, tn = (unsigned) -1;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering const char *p;
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek size_t remaining, m = 0, entry_size = 0;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering char *identifier = NULL, *message = NULL;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering const char *e, *q;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Trailing noise, let's ignore it, and flush what we collected */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering log_debug("Received message with trailing noise, ignoring.");
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Entry separator */
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
8c0b803b97bb0ee6603d9be85fb6b69cd6081eafLennart Poettering log_debug("Entry is too big with %u properties and %zu bytes, ignoring.", n, entry_size);
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Ignore control commands for now, and
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * comments too. */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* A property follows */
12a717f8347f3daf0ae46a2b71c7d011d9c12feaZbigniew Jędrzejewski-Szmek /* n existing properties, 1 new, +1 for _TRANSPORT */
92ee6447b1deef7c79962a8121fdf8e58acb3a83Zbigniew Jędrzejewski-Szmek if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS)) {
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek if (valid_user_field(p, q - p, false)) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* If the field name starts with an
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * underscore, skip the variable,
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * since that indidates a trusted
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* We need to determine the priority
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * of this entry for the rate limiting
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (l == 10 &&
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering priority = (priority & LOG_FACMASK) | (p[9] - '0');
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering else if (l == 17 &&
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering else if (l == 18 &&
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering else if (l >= 19 &&
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering } else if (l >= 8 &&
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek } else if (l > strlen("OBJECT_PID=") &&
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek char buf[DECIMAL_STR_MAX(pid_t)];
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek /* ignore error */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering log_debug("Failed to parse message, ignoring.");
fa1c4b518ec7d8ec2d647213ee651cde4d6c9d7eZbigniew Jędrzejewski-Szmek log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
505b6a61c22d5565e9308045c7b9bf79f7d0517eLennart Poettering if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering log_debug("Failed to parse message, ignoring.");
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering k[e - p] = '=';
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek if (valid_user_field(p, e - p, false)) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek entry_size += strlen("_TRANSPORT=journal");
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek log_debug("Entry is too big with %u properties and %zu bytes, ignoring.",
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering server_forward_syslog(s, priority, identifier, message, ucred, tv);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering server_forward_kmsg(s, priority, identifier, message, ucred);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering server_forward_console(s, priority, identifier, message, ucred);
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen server_forward_wall(s, priority, identifier, message, ucred);
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering for (j = 0; j < n; j++) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering /* Data is in the passed fd, since it didn't fit in a
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering * datagram. */
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering /* If it's a memfd, check if it is sealed. If so, we can just
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering * use map it and use it, and do not need to copy the data
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (!sealed && (!ucred || ucred->uid != 0)) {
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering _cleanup_free_ char *sl = NULL, *k = NULL;
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering const char *e;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering /* If this is not a sealed memfd, and the peer is unknown or
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering * unprivileged, then verify the path. */
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
709f6e46a35ec492b70eb92943d82a8d838ce918Michal Schmidt log_error_errno(r, "readlink(%s) failed: %m", sl);
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering log_error("Received file outside of allowed directories. Refusing.");
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering log_error("Received file in subdirectory of allowed directories. Refusing.");
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt log_error_errno(errno, "Failed to stat passed file, ignoring: %m");
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering log_error("File passed is not regular. Ignoring.");
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering log_error("File passed too large. Ignoring.");
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering /* The file is sealed, we can just map it and use it. */
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt log_error_errno(errno, "Failed to map memfd, ignoring: %m");
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m");
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering /* Refuse operating on file systems that have
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering * mandatory locking enabled, see:
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering * https://github.com/systemd/systemd/issues/1822
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering log_error("Received file descriptor from file system with mandatory locking enable, refusing.");
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering /* Make the fd non-blocking. On regular files this has
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering * the effect of bypassing mandatory locking. Of
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering * course, this should normally not be necessary given
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering * the check above, but let's better be safe than
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering * sorry, after all NFS is pretty confusing regarding
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering * file system flags, and we better don't trust it,
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering * and so is SMB. */
1e603a482f57edb1fb863dbf23b868cf5854e004Lennart Poettering log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m");
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering /* The file is not sealed, we can't map the file here, since
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering * clients might then truncate it and trigger a SIGBUS for
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering * us. So let's stupidly read it */
c3753458fc30f35b7c2d2c5d5873198cd18131d8Michal Schmidt log_error_errno(errno, "Failed to read file, ignoring: %m");
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering else if (n > 0)
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering server_process_native_message(s, p, n, ucred, tv, label, label_len);
f7a5bb2842037fa27dbc99d92c3fee7fe1bbbc2aZbigniew Jędrzejewski-Szmek .un.sun_path = "/run/systemd/journal/socket",
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return log_error_errno(errno, "socket() failed: %m");
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
4a61c3e51e96a747c30598d78ee3a24e7c569e9fZbigniew Jędrzejewski-Szmek (void) chmod(sa.un.sun_path, 0666);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return log_error_errno(errno, "SO_PASSCRED failed: %m");
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt log_warning_errno(errno, "SO_PASSSEC failed: %m");
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
4a62c710b62a5a3c7a8a278b810b9d5b5a0c8f4fMichal Schmidt return log_error_errno(errno, "SO_TIMESTAMP failed: %m");
8531ae707d4d0203e83304d4af948b8169a5fce1Lennart Poettering r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, server_process_datagram, s);
23bbb0de4e3f85d9704a5c12a5afa2dfa0159e41Michal Schmidt return log_error_errno(r, "Failed to add native server fd to event loop: %m");
48cef29504b1ffc0df9929f2d8b2af2ad74d2b4aVito Caputo r = sd_event_source_set_priority(s->native_event_source, SD_EVENT_PRIORITY_NORMAL+5);
48cef29504b1ffc0df9929f2d8b2af2ad74d2b4aVito Caputo return log_error_errno(r, "Failed to adjust native event source priority: %m");