Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Command execution/empty action #81

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions crates/rrg/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ default = [
"action-list_winreg_values",
"action-list_winreg_keys",
"action-query_wmi",
"action-execute_signed_command",
]

action-get_system_metadata = []
Expand All @@ -39,6 +40,7 @@ action-get_winreg_value = []
action-list_winreg_values = []
action-list_winreg_keys = []
action-query_wmi = []
action-execute_signed_command = []

test-setfattr = []
test-chattr = []
Expand Down Expand Up @@ -130,3 +132,12 @@ features = [
"Win32_Foundation",
"Win32_Storage_FileSystem",
]

[dependencies.ed25519-dalek]
version = "2.1.1"
features = [
"rand_core",
]

[dependencies.hex]
version = "0.4.3"
7 changes: 7 additions & 0 deletions crates/rrg/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ pub mod list_winreg_keys;
#[cfg(feature = "action-query_wmi")]
pub mod query_wmi;

#[cfg(feature = "action-execute_signed_command")]
pub mod execute_signed_command;

use log::info;

/// Dispatches the given `request` to an appropriate action handler.
Expand Down Expand Up @@ -125,6 +128,10 @@ where
QueryWmi => {
handle(session, request, self::query_wmi::handle)
}
#[cfg(feature = "action-execute_signed_command")]
ExecuteSignedCommand => {
handle(session, request, self::execute_signed_command::handle)
}
// We allow `unreachable_patterns` because otherwise we get a warning if
// we compile with all the actions enabled.
#[allow(unreachable_patterns)]
Expand Down
117 changes: 117 additions & 0 deletions crates/rrg/src/action/execute_signed_command.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright 2024 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

use std::process::ExitStatus;

use protobuf::Message;

/// Arguments of the `execute_signed_command` action.
pub struct Args {
raw_command: Vec<u8>,

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read

Check warning on line 12 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

fields `raw_command`, `command`, `stdin`, `ed25519_signature`, and `timeout` are never read
command: rrg_proto::execute_signed_command::SignedCommand,
stdin: Stdin,
ed25519_signature: ed25519_dalek::Signature,
timeout: std::time::Duration,
}

/// Result of the `execute_signed_command` action.
pub struct Item {
/// Exit status of the command subprocess.
exit_status: ExitStatus,
/// Standard output of the command executiom.
stdout: Vec<u8>,
/// Wheather standard output is truncated.
truncated_stdout: bool,
/// Standard error of the command executiom.
stderr: Vec<u8>,
/// Wheather stderr is truncated.
truncated_stderr: bool,
}

enum Stdin {
NONE,
UNSIGNED(Vec<u8>),

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

field `0` is never read

Check warning on line 35 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

field `0` is never read
SIGNED(Vec<u8>),

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

field `0` is never read

Check warning on line 36 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

field `0` is never read
}


/// Handles invocations of the `execute_signed_command` action.
pub fn handle<S>(session: &mut S, mut args: Args) -> crate::session::Result<()>

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, stable)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (macos-latest, nightly)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, stable)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (ubuntu-latest, nightly)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, nightly)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

variable does not need to be mutable

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

unused variable: `session`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

unused variable: `args`

Check warning on line 41 in crates/rrg/src/action/execute_signed_command.rs

View workflow job for this annotation

GitHub Actions / CI (windows-latest, stable)

variable does not need to be mutable
where
S: crate::session::Session,
{
// TODO(s-westphal): Add implementation.
Ok(())
}

impl crate::request::Args for Args {

type Proto = rrg_proto::execute_signed_command::Args;

fn from_proto(mut proto: Self::Proto) -> Result<Args, crate::request::ParseArgsError> {
use crate::request::ParseArgsError;

let raw_signature= proto.take_command_ed25519_signature();

let ed25519_signature = ed25519_dalek::Signature::try_from(&raw_signature[..])
.map_err(|error| ParseArgsError::invalid_field("command_ed25519_signature", error))?;

let raw_command = proto.take_command();
let mut command = rrg_proto::execute_signed_command::SignedCommand::parse_from_bytes(&raw_command)
.map_err(|error| ParseArgsError::invalid_field("command", error))?;


let stdin: Stdin;
if command.has_signed_stdin() {
stdin = Stdin::SIGNED(command.take_signed_stdin());
} else if command.unsigned_stdin() && !proto.unsigned_stdin.is_empty() {
stdin = Stdin::UNSIGNED(proto.take_unsigned_stdin());
} else {
stdin = Stdin::NONE
}

let timeout = std::time::Duration::try_from(proto.take_timeout())
.map_err(|error| ParseArgsError::invalid_field("command", error))?;

Ok(Args {
raw_command,
command,
ed25519_signature,
stdin,
timeout,
})
}
}

impl crate::response::Item for Item {

type Proto = rrg_proto::execute_signed_command::Result;

fn into_proto(self) -> Self::Proto {

let mut proto = rrg_proto::execute_signed_command::Result::new();

if let Some(exit_code) = self.exit_status.code() {
proto.set_exit_code(exit_code);
}

#[cfg(target_family = "unix")]
{
use std::os::unix::process::ExitStatusExt;

if let Some(exit_signal) = self.exit_status.signal() {
proto.set_exit_signal(exit_signal);
}
}

proto.set_stdout(self.stdout);
proto.set_stdout_truncated(self.truncated_stdout);

proto.set_stderr(self.stderr);
proto.set_stderr_truncated(self.truncated_stderr);

proto
}
}
15 changes: 15 additions & 0 deletions crates/rrg/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ pub struct Args {
arg_name="PATH",
description="whether to log to a file")]
pub log_to_file: Option<std::path::PathBuf>,

/// The public key for verfying signed commands.
#[argh(option,
long="command-verification-key",
arg_name="KEY",
description="verification key for signed commands",
from_str_fn(parse_verfication_key))]
pub command_verification_key: Option<ed25519_dalek::VerifyingKey>,
}

/// Parses command-line arguments.
Expand All @@ -66,3 +74,10 @@ pub fn from_env_args() -> Args {
fn parse_duration(value: &str) -> Result<Duration, String> {
humantime::parse_duration(value).map_err(|error| error.to_string())
}

/// Parses a ed25519 verification key from hex data given as string to a `VerifyingKey` object.
fn parse_verfication_key(key: &str) -> Result<ed25519_dalek::VerifyingKey, String> {
let bytes = hex::decode(key).map_err(|error| error.to_string())?;
ed25519_dalek::VerifyingKey::try_from(&bytes[..])
.map_err(|error| error.to_string())
}
4 changes: 4 additions & 0 deletions crates/rrg/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ pub enum Action {
ListWinregKeys,
/// Query WMI using WQL (Windows-only).
QueryWmi,
/// Execute a signed command.
ExecuteSignedCommand,
}

impl std::fmt::Display for Action {
Expand All @@ -70,6 +72,7 @@ impl std::fmt::Display for Action {
Action::ListWinregValues => write!(fmt, "list_winreg_values"),
Action::ListWinregKeys => write!(fmt, "list_winreg_keys"),
Action::QueryWmi => write!(fmt, "query_wmi"),
Action::ExecuteSignedCommand => write!(fmt, "execute_signed_command"),
}
}
}
Expand Down Expand Up @@ -119,6 +122,7 @@ impl TryFrom<rrg_proto::rrg::Action> for Action {
LIST_WINREG_VALUES => Ok(Action::ListWinregValues),
LIST_WINREG_KEYS => Ok(Action::ListWinregKeys),
QUERY_WMI => Ok(Action::QueryWmi),
EXECUTE_SIGNED_COMMAND => Ok(Action::ExecuteSignedCommand),
_ => {
let value = protobuf::Enum::value(&proto);
Err(UnknownAction { value })
Expand Down
1 change: 1 addition & 0 deletions crates/rrg/src/session/fake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ impl FakeSession {
pub fn new() -> FakeSession {
FakeSession::with_args(crate::args::Args {
heartbeat_rate: std::time::Duration::from_secs(0),
command_verification_key: Some(ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng).verifying_key()),
verbosity: log::LevelFilter::Debug,
log_to_stdout: false,
log_to_file: None,
Expand Down
2 changes: 2 additions & 0 deletions proto/rrg.proto
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ enum Action {
QUERY_WMI = 16;
/// Grep the specified file for a pattern.
GREP_FILE_CONTENTS = 17;
/// Execute a signed command.
EXECUTE_SIGNED_COMMAND = 18;

// TODO: Define more actions that should be supported.

Expand Down
Loading