| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This program is run directly by the kernel for all programs the kernel runs. |
| // See the CONFIG_STATIC_USERMODEHELPER setting. |
| |
| #include "init/usermode-helper.h" |
| |
| #include <unistd.h> |
| |
| #include <string> |
| |
| #include <base/command_line.h> |
| #include <base/logging.h> |
| #include <base/strings/string_util.h> |
| #include <brillo/syslog_logging.h> |
| |
| int main(int argc, const char* argv[]) { |
| brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty); |
| |
| if (argc <= 1) |
| LOG(FATAL) << "missing program to run"; |
| |
| // When running locally for testing, argv[0] will be usermode-helper itself. |
| // When the kernel invokes us, argv[0] will be set to the program it wants |
| // us to run. So only shift argv when it makes sense. |
| if (strcmp(basename(argv[0]), "usermode-helper") == 0) { |
| --argc; |
| ++argv; |
| } |
| |
| // Validate the program and its arguments, and reject all others. |
| if (!usermode_helper::ValidateProgramArgs(argc, argv)) { |
| // TODO(crbug.com/915974): Remove this fork until we've tracked down all |
| // current usermode calls from the kernel. This lets us get a crash dump |
| // in a child process without blocking the kernel call. |
| if (fork() == 0) { |
| base::CommandLine cmdline(argc, argv); |
| LOG(FATAL) << "program invocation not permitted: " |
| << cmdline.GetCommandLineString(); |
| } |
| } |
| |
| // We could use execveat(), but it's not a clear win. |
| // Pros: |
| // - We guarantee the program is in the rootfs (/) and people can't bind |
| // mount over paths to confuse us. |
| // - The kernel doesn't allow scripts (i.e. files with #! shebangs) to be |
| // executed through execveat. Might be a bug? |
| // - We could require all programs not be symlinked. |
| // Cons: |
| // - Some programs we permit are actually symlinks (e.g. modprobe is a |
| // symlink to kmod). We have an image test that verifies all symlinks in |
| // the rootfs are sane, so not exactly a win. |
| // - Some standard programs use #! to redirect themselves (e.g. coreutils |
| // uses it for all of its programs). Not clear that banning scripts when |
| // we've already validated the argv is a win. |
| // |
| // So we stick with execv for now. |
| execv(argv[0], const_cast<char**>(argv)); |
| PLOG(FATAL) << "execing program failed: " << argv[0]; |
| } |