blob: 59c54cc75f53985bfb0d6d886363a36f78e7b692 [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.
#include "init/usermode-helper.h"
#include <base/logging.h>
#include <base/strings/string_util.h>
namespace usermode_helper {
namespace {
// Processes core dumps from the kernel when a crash is detected.
// Controlled via /proc/sys/kernel/core_pattern.
bool ValidateCrashReporter(int argc, const char* argv[]) {
if (argc != 2) {
LOG(ERROR) << "crash_reporter: argc must be 2";
return false;
}
if (!base::StartsWith(argv[1], "--user=", base::CompareCase::SENSITIVE)) {
LOG(ERROR) << "crash_reporter: first argument must be --user=";
return false;
}
return true;
}
// Automatic module loading when kernel code calls request_module().
// Controlled via /proc/sys/kernel/modprobe.
bool ValidateModprobe(int argc, const char* argv[]) {
// The kernel has loaded modules with the form `modprobe -q -- modname` since
// at least linux-2.6.12. We'll enforce that until the kernel changes, but it
// rarely does, so maybe it's fine to be lazy.
if (argc != 4) {
LOG(ERROR) << "modprobe: argc must be 4";
return false;
}
if (strcmp(argv[1], "-q") != 0) {
LOG(ERROR) << "modprobe: argv[1] must be -q";
return false;
}
if (strcmp(argv[2], "--") != 0) {
LOG(ERROR) << "modprobe: argv[2] must be --";
return false;
}
// We allow the last arg to be anything since the -- marker told modprobe to
// parse it exactly as a module name and not an option.
return true;
}
// When kernel code poweroffs the system by calling orderly_poweroff().
// This is not related to userspace calling `poweroff` or uses the reboot
// syscall.
// Controlled via /proc/sys/kernel/poweroff_cmd.
bool ValidatePoweroff(int argc, const char* argv[]) {
if (argc != 1) {
LOG(ERROR) << "poweroff: argc must be 1";
return false;
}
return true;
}
// When kernel code reboots the system by calling orderly_reboot().
// This is not related to userspace calling `reboot` or uses the reboot
// syscall.
bool ValidateReboot(int argc, const char* argv[]) {
if (argc != 1) {
LOG(ERROR) << "reboot: argc must be 1";
return false;
}
return true;
}
// When the kernel needs access to a key as part of the kernel keyring.
bool ValidateRequestKey(int argc, const char* argv[]) {
// The kernel always executes this as:
// /sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>
if (argc != 8) {
LOG(ERROR) << "request-key: argc must be 8";
return false;
}
// Don't allow any command line options.
for (size_t i = 1; i < argc; ++i) {
const std::string_view arg(argv[i]);
if (arg[0] == '-') {
LOG(ERROR) << "request-key: options not allowed: " << arg;
return false;
}
}
return true;
}
} // namespace
// Whether the arguments to the program are permitted.
bool ValidateProgramArgs(int argc, const char* argv[]) {
const std::string_view prog(argv[0]);
if (prog == "/sbin/crash_reporter")
return ValidateCrashReporter(argc, argv);
else if (prog == "/sbin/modprobe")
return ValidateModprobe(argc, argv);
else if (prog == "/sbin/poweroff")
return ValidatePoweroff(argc, argv);
else if (prog == "/sbin/reboot")
return ValidateReboot(argc, argv);
else if (prog == "/sbin/request-key")
return ValidateRequestKey(argc, argv);
LOG(ERROR) << "program not permitted: " << argv[0];
return false;
}
} // namespace usermode_helper