blob: c7ce9778d39f0af905aaa357ee5824caa085e207 [file] [log] [blame]
// Copyright 2022 The Chromium 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 "chrome/elevation_service/caller_validation.h"
#include <windows.h> // Must be in front of other Windows header files.
#include <psapi.h>
#include <string>
#include <vector>
#include "base/logging.h"
#include "base/process/process.h"
#include "base/strings/string_util.h"
#include "chrome/elevation_service/elevation_service_idl.h"
namespace elevation_service {
namespace {
constexpr char kPathValidationPrefix[] = "PATH";
constexpr char kNoneValidationPrefix[] = "NONE";
std::string GetProcessExecutablePath(const base::Process& process) {
std::string image_path(MAX_PATH, L'\0');
DWORD path_length = image_path.size();
BOOL success = ::QueryFullProcessImageNameA(
process.Handle(), PROCESS_NAME_NATIVE, image_path.data(), &path_length);
if (!success && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
// Process name is potentially greater than MAX_PATH, try larger max size.
// https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation
image_path.resize(UNICODE_STRING_MAX_CHARS);
path_length = image_path.size();
success = ::QueryFullProcessImageNameA(
process.Handle(), PROCESS_NAME_NATIVE, image_path.data(), &path_length);
}
if (!success) {
PLOG_IF(ERROR, ::GetLastError() != ERROR_GEN_FAILURE)
<< "Failed to get process image path";
return std::string();
}
image_path.resize(path_length);
return image_path;
}
// Generate path based validation data, or return empty string if this was not
// possible.
std::string GeneratePathValidationData(const base::Process& process) {
return GetProcessExecutablePath(process);
}
bool ValidatePath(const base::Process& process, const std::string& data) {
return data == GetProcessExecutablePath(process);
}
} // namespace
std::string GenerateValidationData(ProtectionLevel level,
const base::Process& process) {
std::string validation_data;
switch (level) {
case ProtectionLevel::NONE:
validation_data.insert(0, kNoneValidationPrefix);
break;
case ProtectionLevel::PATH_VALIDATION:
validation_data = GeneratePathValidationData(process);
if (validation_data.empty())
return std::string();
validation_data.insert(0, kPathValidationPrefix);
break;
}
return validation_data;
}
bool ValidateData(const base::Process& process,
const std::string& validation_data) {
// Determine which kind of validation was requested.
if (base::StartsWith(validation_data, kNoneValidationPrefix,
base::CompareCase::SENSITIVE)) {
// No validation always returns true.
return true;
} else if (base::StartsWith(validation_data, kPathValidationPrefix,
base::CompareCase::SENSITIVE)) {
// Strip off the path validation header.
const std::string path_validation_data =
validation_data.substr(sizeof(kPathValidationPrefix) - 1);
// Defer to the path validation.
return ValidatePath(process, path_validation_data);
}
return false;
}
} // namespace elevation_service