journald-native.c revision 12a717f8347f3daf0ae46a2b71c7d011d9c12fea
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering This file is part of systemd.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Copyright 2011 Lennart Poettering
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is free software; you can redistribute it and/or modify it
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering under the terms of the GNU Lesser General Public License as published by
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (at your option) any later version.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering systemd is distributed in the hope that it will be useful, but
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering Lesser General Public License for more details.
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering You should have received a copy of the GNU Lesser General Public License
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmekbool valid_user_field(const char *p, size_t l, bool allow_protected) {
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering const char *a;
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen /* We kinda enforce POSIX syntax recommendations for
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering environment variables here, but make a couple of additional
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
7ccbd1ae843d77275f2c542582a9a80e5e058a70Lennart Poettering /* No empty field names */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Don't allow names longer than 64 chars */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Variables starting with an underscore are protected */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Don't allow digits as first character */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Only allow A-Z0-9 and '_' */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering for (a = p; a < p + l; a++)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poetteringstatic bool allow_object_pid(const struct ucred *ucred) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering const char *p;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering char *identifier = NULL, *message = NULL;
13790add4bf648fed816361794d8277a75253410Lennart Poettering const char *e, *q;
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Trailing noise, let's ignore it, and flush what we collected */
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_debug("Received message with trailing noise, ignoring.");
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Entry separator */
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_debug("Entry is too big with %u properties and %zu bytes, ignoring.", n, entry_size);
13790add4bf648fed816361794d8277a75253410Lennart Poettering server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* Ignore control commands for now, and
13790add4bf648fed816361794d8277a75253410Lennart Poettering * comments too. */
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* A property follows */
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* n existing properties, 1 new, +1 for _TRANSPORT */
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + !!object_pid * N_IOVEC_OBJECT_FIELDS)) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (valid_user_field(p, q - p, false)) {
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* If the field name starts with an
13790add4bf648fed816361794d8277a75253410Lennart Poettering * underscore, skip the variable,
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering * since that indidates a trusted
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* We need to determine the priority
13790add4bf648fed816361794d8277a75253410Lennart Poettering * of this entry for the rate limiting
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (l == 10 &&
13790add4bf648fed816361794d8277a75253410Lennart Poettering priority = (priority & LOG_FACMASK) | (p[9] - '0');
13790add4bf648fed816361794d8277a75253410Lennart Poettering else if (l == 17 &&
13790add4bf648fed816361794d8277a75253410Lennart Poettering priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3);
13790add4bf648fed816361794d8277a75253410Lennart Poettering else if (l == 18 &&
13790add4bf648fed816361794d8277a75253410Lennart Poettering priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3);
13790add4bf648fed816361794d8277a75253410Lennart Poettering else if (l >= 19 &&
13790add4bf648fed816361794d8277a75253410Lennart Poettering } else if (l >= 8 &&
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) &&
13790add4bf648fed816361794d8277a75253410Lennart Poettering memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
13790add4bf648fed816361794d8277a75253410Lennart Poettering /* ignore error */
13790add4bf648fed816361794d8277a75253410Lennart Poettering if (remaining < e - p + 1 + sizeof(uint64_t) + 1) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_debug("Failed to parse message, ignoring.");
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek memcpy(&l_le, e + 1, sizeof(uint64_t));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 ||
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_debug("Failed to parse message, ignoring.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering k[e - p] = '=';
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (valid_user_field(p, e - p, false)) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1;
e3bfb7be07d9b1f4ebb12eb22c4c8bcd2a988d51Zbigniew Jędrzejewski-Szmek p = e + 1 + sizeof(uint64_t) + l + 1;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering entry_size += strlen("_TRANSPORT=journal");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_debug("Entry is too big with %u properties and %zu bytes, ignoring.",
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_forward_syslog(s, priority, identifier, message, ucred, tv);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_forward_kmsg(s, priority, identifier, message, ucred);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_forward_console(s, priority, identifier, message, ucred);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_forward_wall(s, priority, identifier, message, ucred);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering for (j = 0; j < n; j++) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* Data is in the passed fd, since it didn't fit in a
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * datagram. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* If it's a memfd, check if it is sealed. If so, we can just
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * use map it and use it, and do not need to copy the data
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (!sealed && (!ucred || ucred->uid != 0)) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering _cleanup_free_ char *sl = NULL, *k = NULL;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering const char *e;
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* If this is not a sealed memfd, and the peer is unknown or
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * unprivileged, then verify the path. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering if (asprintf(&sl, "/proc/self/fd/%i", fd) < 0) {
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error_errno(errno, "readlink(%s) failed: %m", sl);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Received file outside of allowed directories. Refusing.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("Received file in subdirectory of allowed directories. Refusing.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error_errno(errno, "Failed to stat passed file, ignoring: %m");
13790add4bf648fed816361794d8277a75253410Lennart Poettering log_error("File passed is not regular. Ignoring.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error("File passed too large. Ignoring.");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* The file is sealed, we can just map it and use it. */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering p = mmap(NULL, ps, PROT_READ, MAP_PRIVATE, fd, 0);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error_errno(errno, "Failed to map memfd, ignoring: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_process_native_message(s, p, st.st_size, ucred, tv, label, label_len);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering /* The file is not sealed, we can't map the file here, since
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * clients might then truncate it and trigger a SIGBUS for
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering * us. So let's stupidly read it */
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering log_error_errno(n, "Failed to read file, ignoring: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering else if (n > 0)
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering server_process_native_message(s, p, n, ucred, tv, label, label_len);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering .un.sun_path = "/run/systemd/journal/socket",
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(errno, "socket() failed: %m");
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
91bf3b3e124575f6f647bff29766e9d992f55b32Lennart Poettering return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(errno, "SO_PASSCRED failed: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
7b77ed8cf36e8eca6017791626044b61ae2d68e7Lennart Poettering log_warning_errno(errno, "SO_PASSSEC failed: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = setsockopt(s->native_fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one));
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(errno, "SO_TIMESTAMP failed: %m");
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering r = sd_event_add_io(s->event, &s->native_event_source, s->native_fd, EPOLLIN, process_datagram, s);
a45b9fca6b91a767dcd9060cfcb30617dad234c7Lennart Poettering return log_error_errno(r, "Failed to add native server fd to event loop: %m");