Allow redirecting logging to an FD
This change allows redirection of logging facilities, from syslog to a
file.
Bug: None
Test: make tests // see logging in stderr
Change-Id: Ia45ccb87908f1d4a2f7964a01d11a74da6e9fdb7
diff --git a/Android.mk b/Android.mk
index daec814..d531f4b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,9 +26,13 @@
system.c \
util.c
+targetUnittestSrcFiles := \
+ testrunner.cc
+
hostUnittestSrcFiles := \
linux-x86/libconstants.gen.c \
- linux-x86/libsyscalls.gen.c
+ linux-x86/libsyscalls.gen.c \
+ testrunner.cc
minijailCommonCFlags := -DHAVE_SECUREBITS_H -Wall -Werror
minijailCommonLibraries := libcap
@@ -121,6 +125,7 @@
LOCAL_SRC_FILES := \
$(libminijailSrcFiles) \
libminijail_unittest.cc \
+ $(targetUnittestSrcFiles)
LOCAL_STATIC_LIBRARIES := libminijail_generated
LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
@@ -162,6 +167,7 @@
syscall_filter.c \
util.c \
syscall_filter_unittest.cc \
+ $(targetUnittestSrcFiles)
LOCAL_STATIC_LIBRARIES := libminijail_generated
LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
@@ -201,7 +207,9 @@
LOCAL_CLANG := true
LOCAL_SRC_FILES := \
system.c \
+ util.c \
system_unittest.cc \
+ $(targetUnittestSrcFiles)
LOCAL_STATIC_LIBRARIES := libminijail_generated
LOCAL_SHARED_LIBRARIES := $(minijailCommonLibraries)
@@ -220,6 +228,7 @@
LOCAL_CLANG := true
LOCAL_SRC_FILES := \
system.c \
+ util.c \
system_unittest.cc \
$(hostUnittestSrcFiles)
diff --git a/Makefile b/Makefile
index a102dbf..5d799b7 100644
--- a/Makefile
+++ b/Makefile
@@ -58,11 +58,12 @@
CXX_BINARY(libminijail_unittest): CXXFLAGS += -Wno-write-strings \
$(GTEST_CXXFLAGS)
-CXX_BINARY(libminijail_unittest): LDLIBS += -lcap $(GTEST_MAIN)
+CXX_BINARY(libminijail_unittest): LDLIBS += -lcap $(GTEST_LIBS)
ifeq ($(USE_SYSTEM_GTEST),no)
-CXX_BINARY(libminijail_unittest): $(GTEST_MAIN)
+CXX_BINARY(libminijail_unittest): $(GTEST_LIBS)
endif
-CXX_BINARY(libminijail_unittest): libminijail_unittest.o $(CORE_OBJECT_FILES)
+CXX_BINARY(libminijail_unittest): libminijail_unittest.o $(CORE_OBJECT_FILES) \
+ testrunner.o
clean: CLEAN(libminijail_unittest)
@@ -73,22 +74,22 @@
CXX_BINARY(syscall_filter_unittest): CXXFLAGS += -Wno-write-strings \
$(GTEST_CXXFLAGS)
-CXX_BINARY(syscall_filter_unittest): LDLIBS += -lcap $(GTEST_MAIN)
+CXX_BINARY(syscall_filter_unittest): LDLIBS += -lcap $(GTEST_LIBS)
ifeq ($(USE_SYSTEM_GTEST),no)
-CXX_BINARY(syscall_filter_unittest): $(GTEST_MAIN)
+CXX_BINARY(syscall_filter_unittest): $(GTEST_LIBS)
endif
CXX_BINARY(syscall_filter_unittest): syscall_filter_unittest.o \
- syscall_filter.o bpf.o util.o libconstants.gen.o \
- libsyscalls.gen.o
+ $(CORE_OBJECT_FILES) testrunner.o
clean: CLEAN(syscall_filter_unittest)
CXX_BINARY(system_unittest): CXXFLAGS += $(GTEST_CXXFLAGS)
-CXX_BINARY(system_unittest): LDLIBS += $(GTEST_MAIN)
+CXX_BINARY(system_unittest): LDLIBS += -lcap $(GTEST_LIBS)
ifeq ($(USE_SYSTEM_GTEST),no)
-CXX_BINARY(system_unittest): $(GTEST_MAIN)
+CXX_BINARY(system_unittest): $(GTEST_LIBS)
endif
-CXX_BINARY(system_unittest): system_unittest.o system.o
+CXX_BINARY(system_unittest): system_unittest.o \
+ $(CORE_OBJECT_FILES) testrunner.o
clean: CLEAN(system_unittest)
diff --git a/libminijail.c b/libminijail.c
index d06aeeb..0eca595 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -2691,3 +2691,8 @@
free(j->cgroups[i]);
free(j);
}
+
+void API minijail_log_to_fd(int fd, int min_priority)
+{
+ init_logging(LOG_TO_FD, fd, min_priority);
+}
diff --git a/libminijail.h b/libminijail.h
index 15fa124..f1cb346 100644
--- a/libminijail.h
+++ b/libminijail.h
@@ -339,6 +339,16 @@
*/
void minijail_destroy(struct minijail *j);
+/*
+ * minijail_log_to_fd: redirects the module-wide logging to an FD instead of
+ * syslog.
+ * @fd FD to log to. Caller must ensure this is available after
+ * jailing (e.g. with minijail_preserve_fd()).
+ * @min_priority the minimum logging priority. Same as the priority argument
+ * to syslog(2).
+ */
+void minijail_log_to_fd(int fd, int min_priority);
+
#ifdef __cplusplus
}; /* extern "C" */
#endif
diff --git a/minijail0.1 b/minijail0.1
index d80b182..7206104 100644
--- a/minijail0.1
+++ b/minijail0.1
@@ -167,6 +167,10 @@
\fB--uts[=hostname]\fR
Create a new UTS/hostname namespace, and optionally set the hostname in the new
namespace to \fIhostname\fR.
+.TP
+\fB--logging=<system>\fR
+Use \fIsystem\fR as the logging system. \fIsystem\fR must be one of
+\fBsyslog\fR (the default) or \fBstderr\fR.
.SH IMPLEMENTATION
This program is broken up into two parts: \fBminijail0\fR (the frontend) and a helper
library called \fBlibminijailpreload\fR. Some jailings can only be achieved from
diff --git a/minijail0.c b/minijail0.c
index db9fc40..d47aad5 100644
--- a/minijail0.c
+++ b/minijail0.c
@@ -212,7 +212,9 @@
" -Y: Synchronize seccomp filters across thread group.\n"
" -z: Don't forward signals to jailed process.\n"
" --ambient: Raise ambient capabilities. Requires -c.\n"
- " --uts[=name]: Enter a new UTS namespace (and set hostname).\n");
+ " --uts[=name]: Enter a new UTS namespace (and set hostname).\n"
+ " --logging=<s>:Use <s> as the logging system.\n"
+ " <s> must be 'syslog' (default) or 'stderr'.\n");
/* clang-format on */
}
@@ -243,6 +245,7 @@
char *map;
size_t size;
const char *filter_path = NULL;
+ int log_to_stderr = 0;
const char *optstring =
"+u:g:sS:c:C:P:b:B:V:f:m::M::k:a:e::R:T:vrGhHinNplLt::IUKwyYz";
@@ -251,6 +254,7 @@
const struct option long_options[] = {
{"ambient", no_argument, 0, 128},
{"uts", optional_argument, 0, 129},
+ {"logging", required_argument, 0, 130},
{0, 0, 0, 0},
};
/* clang-format on */
@@ -499,12 +503,35 @@
if (optarg)
minijail_namespace_set_hostname(j, optarg);
break;
+ case 130: /* Logging. */
+ if (!strcmp(optarg, "syslog"))
+ log_to_stderr = 0;
+ else if (!strcmp(optarg, "stderr")) {
+ log_to_stderr = 1;
+ } else {
+ fprintf(stderr, "--logger must be 'syslog' or "
+ "'stderr'.\n");
+ exit(1);
+ }
+ break;
default:
usage(argv[0]);
exit(1);
}
}
+ if (log_to_stderr) {
+ init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
+ /*
+ * When logging to stderr, ensure the FD survives the jailing.
+ */
+ if (0 !=
+ minijail_preserve_fd(j, STDERR_FILENO, STDERR_FILENO)) {
+ fprintf(stderr, "Could not preserve stderr.\n");
+ exit(1);
+ }
+ }
+
/* Can only set ambient caps when using regular caps. */
if (ambient_caps && !caps) {
fprintf(stderr, "Can't set ambient capabilities (--ambient) "
@@ -625,7 +652,7 @@
}
if (exit_immediately) {
- info("not running init loop, exiting immediately");
+ info("not running init loop, exiting immediately\n");
return 0;
}
int ret = minijail_wait(j);
diff --git a/parse_seccomp_policy.cc b/parse_seccomp_policy.cc
index 32b2853..88debbe 100644
--- a/parse_seccomp_policy.cc
+++ b/parse_seccomp_policy.cc
@@ -21,6 +21,8 @@
/* TODO(jorgelo): Use libseccomp disassembler here. */
int main(int argc, char **argv) {
+ init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
+
if (argc < 2) {
fprintf(stderr, "Usage: %s <policy file>\n", argv[0]);
return 1;
diff --git a/testrunner.cc b/testrunner.cc
new file mode 100644
index 0000000..b848c9c
--- /dev/null
+++ b/testrunner.cc
@@ -0,0 +1,42 @@
+// testrunner.cpp
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// Main entrypoint for gtest.
+// Redirects logging to stderr to avoid syslog logspam.
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+
+#include "util.h"
+
+namespace {
+
+class Environment : public ::testing::Environment {
+ public:
+ ~Environment() override = default;
+
+ void SetUp() {
+ init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
+ }
+};
+
+} // namespace
+
+int main(int argc, char **argv) {
+ testing::InitGoogleTest(&argc, argv);
+ ::testing::AddGlobalTestEnvironment(new Environment());
+ return RUN_ALL_TESTS();
+}
diff --git a/util.c b/util.c
index 2605a3f..f228ff7 100644
--- a/util.c
+++ b/util.c
@@ -8,6 +8,7 @@
#include <ctype.h>
#include <errno.h>
#include <limits.h>
+#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -64,6 +65,41 @@
const size_t log_syscalls_len = ARRAY_SIZE(log_syscalls);
+/* clang-format off */
+static struct logging_config_t {
+ /* The logging system to use. The default is syslog. */
+ enum logging_system_t logger;
+
+ /* File descriptor to log to. Only used when logger is LOG_TO_FD. */
+ int fd;
+
+ /* Minimum priority to log. Only used when logger is LOG_TO_FD. */
+ int min_priority;
+} logging_config = {
+ .logger = LOG_TO_SYSLOG,
+};
+/* clang-format on */
+
+void do_log(int priority, const char *format, ...)
+{
+ if (logging_config.logger == LOG_TO_SYSLOG) {
+ va_list args;
+ va_start(args, format);
+ vsyslog(priority, format, args);
+ va_end(args);
+ return;
+ }
+
+ if (logging_config.min_priority < priority)
+ return;
+
+ va_list args;
+ va_start(args, format);
+ vdprintf(logging_config.fd, format, args);
+ va_end(args);
+ dprintf(logging_config.fd, "\n");
+}
+
int lookup_syscall(const char *name)
{
const struct syscall_entry *entry = syscall_table;
@@ -298,3 +334,10 @@
return NULL;
return consumebytes(len + 1, buf, buflength);
}
+
+void init_logging(enum logging_system_t logger, int fd, int min_priority)
+{
+ logging_config.logger = logger;
+ logging_config.fd = fd;
+ logging_config.min_priority = min_priority;
+}
diff --git a/util.h b/util.h
index 14e79f5..56d1246 100644
--- a/util.h
+++ b/util.h
@@ -9,6 +9,7 @@
#ifndef _UTIL_H_
#define _UTIL_H_
+#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <syslog.h>
@@ -20,7 +21,7 @@
/* clang-format off */
#define die(_msg, ...) do { \
- syslog(LOG_ERR, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__); \
+ do_log(LOG_ERR, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__); \
abort(); \
} while (0)
@@ -28,13 +29,13 @@
die(_msg ": %m", ## __VA_ARGS__)
#define warn(_msg, ...) \
- syslog(LOG_WARNING, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__)
+ do_log(LOG_WARNING, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__)
#define pwarn(_msg, ...) \
warn(_msg ": %m", ## __VA_ARGS__)
#define info(_msg, ...) \
- syslog(LOG_INFO, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__)
+ do_log(LOG_INFO, "libminijail[%d]: " _msg, getpid(), ## __VA_ARGS__)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* clang-format on */
@@ -42,6 +43,17 @@
extern const char *log_syscalls[];
extern const size_t log_syscalls_len;
+enum logging_system_t {
+ /* Log to syslog. This is the default. */
+ LOG_TO_SYSLOG = 0,
+
+ /* Log to a file descriptor. */
+ LOG_TO_FD,
+};
+
+extern void do_log(int priority, const char *format, ...)
+ __attribute__((__format__(__printf__, 2, 3)));
+
static inline int is_android(void)
{
#if defined(__ANDROID__)
@@ -88,6 +100,16 @@
*/
char *consumestr(char **buf, size_t *buflength);
+/*
+ * init_logging: initializes the module-wide logging.
+ * @logger The logging system to use.
+ * @fd The file descriptor to log into. Ignored unless
+ * @logger = LOG_TO_FD.
+ * @min_priority The minimum priority to display. Corresponds to syslog's
+ priority parameter. Ignored unless @logger = LOG_TO_FD.
+ */
+void init_logging(enum logging_system_t logger, int fd, int min_priority);
+
#ifdef __cplusplus
}; /* extern "C" */
#endif