blob: 33890a6d5c858ca30fce312fb418c2c60c73e653 [file] [log] [blame]
// 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];
}