diff --git a/.gitignore b/.gitignore index 4f86940..24e8576 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /rust-keylime-0.1.0~20211110gitd5a3191.tar.gz /rust-keylime-0.1.0~20220602gitc98e381-vendor.tar.xz /rust-keylime-0.1.0~20220602gitc98e381.tar.gz +/rust-keylime-0.1.0~20220603gitaed51c7.tar.gz +/rust-keylime-0.1.0~20220603gitaed51c7-vendor.tar.xz diff --git a/keylime-agent-rust.spec b/keylime-agent-rust.spec index 1e2da88..a6ad6a7 100644 --- a/keylime-agent-rust.spec +++ b/keylime-agent-rust.spec @@ -1,18 +1,14 @@ # keylime-agent-rust.spec # Generated by rust2rpm 20 -# missing dev-dependencies: wiremock -%bcond_with check +%bcond_without check %global crate keylime_agent %global crate_version 0.1.0 -# As the latest git version uses an unreleased tss-esapi crate, we -# stick to an older version. FIXME: once the new tss-esapi crate is -# available on crates.io, update the revision to the latest -%global commit c98e381363752fd38e4ac45d0e654c76f11b02c5 +%global commit aed51c7c8c526953e945357594352c3df2ca4ace %global shortcommit %(c=%{commit}; echo ${c:0:7}) -%global commitdate 20220602 +%global commitdate 20220603 %if 0%{?rhel} # RHEL: Use bundled deps as it doesn't ship Rust libraries @@ -22,11 +18,6 @@ %global bundled_rust_deps 0 %endif -%ifarch armv7hl -# drop debuginfo generation for armv7hl OOM problems -%global rustflags_debuginfo 0 -%endif - Name: keylime-agent-rust Version: %{crate_version}~%{commitdate}git%{shortcommit} Release: %{?autorelease}%{!?autorelease:1%{?dist}} @@ -60,14 +51,34 @@ Source0: %{url}/archive/%{commit}/rust-keylime-%{version}.tar.gz # cargo vendor # tar jcf rust-keylime-%%{version}-vendor.tar.xz vendor Source1: rust-keylime-%{version}-vendor.tar.xz +# Drop rustc-serialize and flate2, update clap, and make wiremock optional +Patch0: rust-keylime-drop-dependencies.patch +# Add serialization functions to fix issue on big-endian arches +Patch1: rust-keylime-add-quote-serialization.patch +# Show path on missing mTLS certificate +Patch2: rust-keylime-show-path-missing-cert.patch +# Use more descriptive error messages for missing files errors +Patch3: rust-keylime-descriptive-error-messages.patch +# Set supplementary groups when dropping privileges +Patch4: rust-keylime-set-supplementary-groups.patch ExclusiveArch: %{rust_arches} -%if 0%{?bundled_rust_deps} -BuildRequires: rust-toolset +Requires: tpm2-tss + +# The keylime-base package provides the configuration file from the python +# implementation which can be used for the rust implementation. It is available +# from Fedora 36 +%if 0%{?fedora} >= 36 +Requires: keylime-base +%endif + +BuildRequires: systemd BuildRequires: openssl-devel BuildRequires: libarchive-devel BuildRequires: tpm2-tss-devel +%if 0%{?bundled_rust_deps} +BuildRequires: rust-toolset %else BuildRequires: rust-packaging >= 21-2 %endif @@ -79,12 +90,6 @@ Conflicts: keylime-agent %description Rust agent for Keylime -%files -%license LICENSE -%doc README.md -%{_bindir}/keylime_agent -%{_bindir}/keylime_ima_emulator - %prep %autosetup -n rust-keylime-%{commit} -p1 %if 0%{?bundled_rust_deps} @@ -92,9 +97,6 @@ Rust agent for Keylime %cargo_prep -V 1 %else %cargo_prep -%endif - -%if !0%{?bundled_rust_deps} %generate_buildrequires %cargo_generate_buildrequires %endif @@ -105,6 +107,37 @@ Rust agent for Keylime %install %cargo_install +mkdir -p %{buildroot}/%{_sharedstatedir}/keylime +mkdir -p --mode=0700 %{buildroot}/%{_rundir}/keylime +mkdir -p --mode=0700 %{buildroot}/%{_localstatedir}/log/keylime +mkdir -p --mode=0700 %{buildroot}/%{_libexecdir}/keylime + +install -Dpm 644 ./dist/systemd/system/keylime_agent.service \ + %{buildroot}%{_unitdir}/keylime_agent.service + +install -Dpm 644 ./dist/systemd/system/var-lib-keylime-secure.mount \ + %{buildroot}%{_unitdir}/var-lib-keylime-secure.mount + +%preun +%systemd_preun keylime_agent.service +%systemd_preun var-lib-keylime-secure.mount + +%postun +%systemd_postun_with_restart keylime_agent.service +%systemd_postun_with_restart var-lib-keylime-secure.mount + +%files +%license LICENSE +%doc README.md +%{_unitdir}/keylime_agent.service +%{_unitdir}/var-lib-keylime-secure.mount +%attr(700,keylime,keylime) %dir %{_rundir}/keylime +%attr(700,keylime,keylime) %dir %{_localstatedir}/log/keylime +%attr(700,keylime,keylime) %{_sharedstatedir}/keylime +%attr(700,keylime,keylime) %{_libexecdir}/keylime +%{_bindir}/keylime_agent +%{_bindir}/keylime_ima_emulator + %if %{with check} %check %cargo_test diff --git a/rust-keylime-add-quote-serialization.patch b/rust-keylime-add-quote-serialization.patch new file mode 100644 index 0000000..7401c2e --- /dev/null +++ b/rust-keylime-add-quote-serialization.patch @@ -0,0 +1,217 @@ +From 423f7337d991ec5085914a361e68260bdd513ac6 Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Mon, 20 Jun 2022 11:51:46 +0200 +Subject: [PATCH] tpm: Add serialization functions for structures in quotes + +Add serialization and deserialization functions for the data in quotes +to avoid endianness issues when the arch is big-endian. + +The added serialization and deserialization functions will convert the +data endianness as necessary. + +Note: the official marshalling and unmarshalling functions cannot be +used directly because the tpm2-tools uses a custom format. + +Fixes: #407 + +Signed-off-by: Anderson Toshiyuki Sasaki +--- + src/tpm.rs | 139 +++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 107 insertions(+), 32 deletions(-) + +diff --git a/src/tpm.rs b/src/tpm.rs +index 9002c29..5521892 100644 +--- a/src/tpm.rs ++++ b/src/tpm.rs +@@ -52,15 +52,20 @@ use tss_esapi::{ + tss2_esys::{ + Tss2_MU_TPM2B_PUBLIC_Marshal, Tss2_MU_TPMS_ATTEST_Marshal, + Tss2_MU_TPMS_ATTEST_Unmarshal, Tss2_MU_TPMT_SIGNATURE_Marshal, +- TPM2B_ATTEST, TPM2B_PUBLIC, TPML_DIGEST, TPML_PCR_SELECTION, +- TPMS_ATTEST, TPMS_SCHEME_HASH, TPMT_SIGNATURE, TPMT_SIG_SCHEME, +- TPMU_SIG_SCHEME, ++ TPM2B_ATTEST, TPM2B_DIGEST, TPM2B_PUBLIC, TPML_DIGEST, ++ TPML_PCR_SELECTION, TPMS_ATTEST, TPMS_PCR_SELECTION, ++ TPMS_SCHEME_HASH, TPMT_SIGNATURE, TPMT_SIG_SCHEME, TPMU_SIG_SCHEME, + }, + utils::TpmsContext, + Context, + }; + + pub const MAX_NONCE_SIZE: usize = 64; ++pub const TPML_DIGEST_SIZE: usize = std::mem::size_of::(); ++pub const TPML_PCR_SELECTION_SIZE: usize = ++ std::mem::size_of::(); ++pub const TPMS_PCR_SELECTION_SIZE: usize = ++ std::mem::size_of::(); + + /* + * Input: None +@@ -123,6 +128,95 @@ pub(crate) fn create_ek( + assert_eq_size!(TPML_PCR_SELECTION, [u8; 132]); + assert_eq_size!(TPML_DIGEST, [u8; 532]); + ++// Serialize a TPML_PCR_SELECTION into a Vec ++// The serialization will adjust the data endianness as necessary and add paddings to keep the ++// memory aligment. ++pub(crate) fn serialize_pcrsel( ++ pcr_selection: &TPML_PCR_SELECTION, ++) -> Vec { ++ let mut output = Vec::with_capacity(TPML_PCR_SELECTION_SIZE); ++ output.extend(u32::to_le_bytes(pcr_selection.count)); ++ for selection in pcr_selection.pcrSelections.iter() { ++ output.extend(selection.hash.to_le_bytes()); ++ output.extend(selection.sizeofSelect.to_le_bytes()); ++ output.extend(selection.pcrSelect); ++ output.extend([0u8; 1]); // padding to keep the memory alignment ++ } ++ output ++} ++ ++// Deserialize a TPML_PCR_SELECTION from a &[u8] slice. ++// The deserialization will adjust the data endianness as necessary. ++pub(crate) fn deserialize_pcrsel( ++ pcrsel_vec: &[u8], ++) -> Result { ++ if pcrsel_vec.len() != TPML_PCR_SELECTION_SIZE { ++ return Err(KeylimeError::InvalidRequest); ++ } ++ ++ let mut reader = std::io::Cursor::new(pcrsel_vec); ++ let mut count_vec = [0u8; 4]; ++ reader.read_exact(&mut count_vec)?; ++ let count = u32::from_le_bytes(count_vec); ++ ++ let mut pcr_selections: [TPMS_PCR_SELECTION; 16] = ++ [TPMS_PCR_SELECTION::default(); 16]; ++ ++ for selection in &mut pcr_selections { ++ let mut hash_vec = [0u8; 2]; ++ reader.read_exact(&mut hash_vec)?; ++ selection.hash = u16::from_le_bytes(hash_vec); ++ ++ let mut size_vec = [0u8; 1]; ++ reader.read_exact(&mut size_vec)?; ++ selection.sizeofSelect = u8::from_le_bytes(size_vec); ++ ++ reader.read_exact(&mut selection.pcrSelect)?; ++ } ++ ++ Ok(TPML_PCR_SELECTION { ++ count, ++ pcrSelections: pcr_selections, ++ }) ++} ++ ++// Serialize a TPML_DIGEST into a Vec ++// The serialization will adjust the data endianness as necessary. ++pub(crate) fn serialize_digest(digest_list: &TPML_DIGEST) -> Vec { ++ let mut output = Vec::with_capacity(TPML_DIGEST_SIZE); ++ output.extend(u32::to_le_bytes(digest_list.count)); ++ for digest in digest_list.digests.iter() { ++ output.extend(digest.size.to_le_bytes()); ++ output.extend(digest.buffer); ++ } ++ output ++} ++ ++// Deserialize a TPML_DIGEST from a &[u8] slice. ++// The deserialization will adjust the data endianness as necessary. ++pub(crate) fn deserialize_digest(digest_vec: &[u8]) -> Result { ++ if digest_vec.len() != TPML_DIGEST_SIZE { ++ return Err(KeylimeError::InvalidRequest); ++ } ++ ++ let mut reader = std::io::Cursor::new(digest_vec); ++ let mut count_vec = [0u8; 4]; ++ ++ reader.read_exact(&mut count_vec)?; ++ let count = u32::from_le_bytes(count_vec); ++ ++ let mut digests: [TPM2B_DIGEST; 8] = [TPM2B_DIGEST::default(); 8]; ++ ++ for digest in &mut digests { ++ let mut size_vec = [0u8; 2]; ++ reader.read_exact(&mut size_vec)?; ++ digest.size = u16::from_le_bytes(size_vec); ++ reader.read_exact(&mut digest.buffer)?; ++ } ++ ++ Ok(TPML_DIGEST { count, digests }) ++} ++ + // Recreate how tpm2-tools creates the PCR out file. Roughly, this is a + // TPML_PCR_SELECTION + number of TPML_DIGESTS + TPML_DIGESTs. + // Reference: +@@ -140,16 +234,14 @@ pub(crate) fn pcrdata_to_vec( + const DIGEST_SIZE: usize = std::mem::size_of::(); + + let mut pcrsel: TPML_PCR_SELECTION = selection_list.into(); +- pcrsel.count = pcrsel.count.to_le(); +- let pcrsel_vec: [u8; PCRSEL_SIZE] = +- unsafe { std::mem::transmute(pcrsel) }; ++ let pcrsel_vec = serialize_pcrsel(&pcrsel); + + let digest: Vec = pcrdata.into(); + let num_tpml_digests = digest.len() as u32; + let mut digest_vec = Vec::with_capacity(digest.len() * DIGEST_SIZE); + + for d in digest { +- let vec: [u8; DIGEST_SIZE] = unsafe { std::mem::transmute(d) }; ++ let vec = serialize_digest(&d); + digest_vec.extend(vec); + } + +@@ -665,41 +757,24 @@ pub mod testing { + ); + + fn vec_to_pcrdata(val: &[u8]) -> Result<(PcrSelectionList, PcrData)> { +- const PCRSEL_SIZE: usize = std::mem::size_of::(); +- const DIGEST_SIZE: usize = std::mem::size_of::(); +- + let mut reader = std::io::Cursor::new(val); +- let mut pcrsel_vec = [0u8; PCRSEL_SIZE]; +- let len = reader.read(&mut pcrsel_vec)?; +- if len != pcrsel_vec.len() { +- return Err(KeylimeError::InvalidRequest); +- } +- let mut pcrsel = unsafe { +- std::mem::transmute::<[u8; PCRSEL_SIZE], TPML_PCR_SELECTION>( +- pcrsel_vec, +- ) +- }; ++ let mut pcrsel_vec = [0u8; TPML_PCR_SELECTION_SIZE]; ++ reader.read_exact(&mut pcrsel_vec)?; ++ ++ let pcrsel = deserialize_pcrsel(&pcrsel_vec)?; + let pcrlist: PcrSelectionList = pcrsel.try_into()?; + + let mut count_vec = [0u8; 4]; +- let len = reader.read(&mut count_vec)?; +- if len < count_vec.len() { +- return Err(KeylimeError::InvalidRequest); +- } ++ reader.read_exact(&mut count_vec)?; + let count = u32::from_le_bytes(count_vec); + // Always 1 PCR digest should follow + if count != 1 { + return Err(KeylimeError::InvalidRequest); + } + +- let mut digest_vec = [0u8; DIGEST_SIZE]; +- let len = reader.read(&mut digest_vec)?; +- if len != digest_vec.len() { +- return Err(KeylimeError::InvalidRequest); +- } +- let mut digest = unsafe { +- std::mem::transmute::<[u8; DIGEST_SIZE], TPML_DIGEST>(digest_vec) +- }; ++ let mut digest_vec = [0u8; TPML_DIGEST_SIZE]; ++ reader.read_exact(&mut digest_vec)?; ++ let digest = deserialize_digest(&digest_vec)?; + let mut digest_list = DigestList::new(); + for i in 0..digest.count { + digest_list.add(digest.digests[i as usize].try_into()?); +-- +2.35.3 + diff --git a/rust-keylime-descriptive-error-messages.patch b/rust-keylime-descriptive-error-messages.patch new file mode 100644 index 0000000..63172ef --- /dev/null +++ b/rust-keylime-descriptive-error-messages.patch @@ -0,0 +1,43 @@ +From e20b936fc9d92ae05406cb86471d3e6fba823b7f Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Tue, 28 Jun 2022 13:47:38 +0200 +Subject: [PATCH] main: Use more descriptive message for missing files error + +Use more descriptive message when required paths are missing instead of +the generic message. + +Signed-off-by: Anderson Toshiyuki Sasaki +--- + src/main.rs | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/src/main.rs b/src/main.rs +index 9404284..ef29eb2 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -608,9 +608,22 @@ async fn main() -> Result<()> { + let payload = Arc::clone(&encr_payload_arc); + + let revocation_cert = revocation::get_revocation_cert_path(&config)?; +- let actions_dir = +- Path::new(&config.revocation_actions_dir).canonicalize()?; +- let work_dir = Path::new(&config.work_dir).canonicalize()?; ++ let actions_dir = Path::new(&config.revocation_actions_dir) ++ .canonicalize() ++ .map_err(|e| { ++ Error::Configuration(format!( ++ "Path {} set in revocation_actions_dir not found: {}", ++ &config.revocation_actions_dir, e ++ )) ++ })?; ++ ++ let work_dir = ++ Path::new(&config.work_dir).canonicalize().map_err(|e| { ++ Error::Configuration(format!( ++ "Path {} set in keylime_dir not found: {}", ++ &config.work_dir, e ++ )) ++ })?; + + let quotedata = web::Data::new(QuoteData { + tpmcontext: Mutex::new(ctx), diff --git a/rust-keylime-drop-dependencies.patch b/rust-keylime-drop-dependencies.patch new file mode 100644 index 0000000..9ff289d --- /dev/null +++ b/rust-keylime-drop-dependencies.patch @@ -0,0 +1,193 @@ +From 9229cb4673aad2cae7605e66bdf2160716e1f694 Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Thu, 9 Jun 2022 18:34:34 +0200 +Subject: [PATCH 1/4] Update clap dependency to 3.1.18 + +This change replaces clap::App with clap::Command in main.rs file. + +On commit f3fa925 the clap dependency in Cargo.lock file was updated +from version 3.0.14 to version 3.1.18. + +In clap version 3.1.0, clap::App was deprecated in favor of +clap::Command. This causes warnings during the Keylime agent build due +to the usage of the deprecated structure. + +To avoid similar issues in the future, use the tilde dependency version +requirement to allow versions >= 3.1.18 but < 3.2.0. + +Signed-off-by: Anderson Toshiyuki Sasaki +--- + Cargo.lock | 76 ++++++++++++++++++++++------------------------------- + Cargo.toml | 2 +- + src/main.rs | 2 +- + 3 files changed, 33 insertions(+), 47 deletions(-) + +diff --git a/Cargo.toml b/Cargo.toml +index 92f3974..f0c7d39 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -21,7 +21,7 @@ doc = false + actix-web = { version = "4", features = ["openssl"] } + base64 = "0.13" + cfg-if = "1" +-clap = { version = "3.0.14", features = ["derive"] } ++clap = { version = "~3.1.18", features = ["derive"] } + compress-tools = "0.12" + flate2 = "1.0.4" + futures = "0.3.6" +diff --git a/src/main.rs b/src/main.rs +index 1896104..8540597 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -51,7 +51,7 @@ mod tpm; + mod version_handler; + + use actix_web::{dev::Service, http, middleware, rt, web, App, HttpServer}; +-use clap::{App as ClapApp, Arg}; ++use clap::{Arg, Command as ClapApp}; + use common::*; + use compress_tools::*; + use error::{Error, Result}; +-- +2.35.3 + + +From c61e3f389e4bde4d0a318a571c9b3dcf8a62749f Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Tue, 17 May 2022 18:31:01 +0200 +Subject: [PATCH 2/4] Drop unused dependency rustc-serialize + +Signed-off-by: Anderson Toshiyuki Sasaki +--- + Cargo.lock | 7 ------- + Cargo.toml | 1 - + 2 files changed, 8 deletions(-) + +diff --git a/Cargo.toml b/Cargo.toml +index f0c7d39..0f4e4ab 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -34,7 +34,6 @@ picky-asn1-x509 = "0.6.1" + pretty_env_logger = "0.4" + reqwest = {version = "0.11", features = ["json"]} + rust-ini = "0.17" +-rustc-serialize = "0.3.24" + serde = "1.0.80" + serde_derive = "1.0.80" + serde_json = { version = "1.0", features = ["raw_value"] } +-- +2.35.3 + + +From f7b59a6a7739d275ffe15a915eb48a36ceafccdd Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Tue, 17 May 2022 18:56:50 +0200 +Subject: [PATCH 3/4] Drop unused dependency flate2 + +Signed-off-by: Anderson Toshiyuki Sasaki +--- + Cargo.lock | 1 - + Cargo.toml | 1 - + src/tpm.rs | 3 --- + 3 files changed, 5 deletions(-) + +diff --git a/Cargo.toml b/Cargo.toml +index 0f4e4ab..69d2eec 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -23,7 +23,6 @@ base64 = "0.13" + cfg-if = "1" + clap = { version = "~3.1.18", features = ["derive"] } + compress-tools = "0.12" +-flate2 = "1.0.4" + futures = "0.3.6" + hex = "0.4" + libc = "0.2.43" +diff --git a/src/tpm.rs b/src/tpm.rs +index 355dd0d..43129f1 100644 +--- a/src/tpm.rs ++++ b/src/tpm.rs +@@ -20,8 +20,6 @@ use openssl::{ + pkey::{Id, PKeyRef, Public}, + }; + +-use flate2::{write::ZlibEncoder, Compression}; +- + use tss_esapi::{ + abstraction::{ + ak, +@@ -635,7 +633,6 @@ pub(crate) fn quote( + #[cfg(test)] + pub mod testing { + use super::*; +- use flate2::read::ZlibDecoder; + use tss_esapi::constants::structure_tags::StructureTag; + use tss_esapi::structures::{Attest, AttestBuffer, DigestList, Ticket}; + use tss_esapi::tss2_esys::Tss2_MU_TPMT_SIGNATURE_Unmarshal; +-- +2.35.3 + + +From c3f0b4f603089d38715535f8e16b7a40f413e4de Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Thu, 9 Jun 2022 16:21:06 +0200 +Subject: [PATCH 4/4] Make wiremock an optional dependency + +Make a wiremock optional, enabled when the 'testing' feature is enabled. +The goal is to reduce the number of dependencies, with the downside that +the test code coverage will drop. + +Wiremock is currently used only on 'registrar_agent' tests to mock +responses from the registrar service. + +Note: wiremock was moved to be an optional regular dependency because +optional dev-dependencies are not supported. +see: https://github.com/rust-lang/cargo/issues/1596 + +Signed-off-by: Anderson Toshiyuki Sasaki +--- + Cargo.toml | 7 +++++-- + src/registrar_agent.rs | 1 + + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/Cargo.toml b/Cargo.toml +index 69d2eec..5052512 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -43,16 +43,19 @@ tss-esapi = "7.1.0" + thiserror = "1.0" + uuid = {version = "0.8", features = ["v4"]} + zmq = {version = "0.9.2", optional = true} ++# wiremock was moved to be a regular dependency because optional ++# dev-dependencies are not supported ++# see: https://github.com/rust-lang/cargo/issues/1596 ++wiremock = {version = "0.5", optional = true} + + [dev-dependencies] + actix-rt = "2" +-wiremock = "0.5" + + [features] + # The features enabled by default + default = ["with-zmq", "legacy-python-actions"] + # this should change to dev-dependencies when we have integration testing +-testing = [] ++testing = ["wiremock"] + # Whether the agent should be compiled with support to listen for notification + # messages on ZeroMQ + with-zmq = ["zmq"] +diff --git a/src/registrar_agent.rs b/src/registrar_agent.rs +index 85b5931..b02ba48 100644 +--- a/src/registrar_agent.rs ++++ b/src/registrar_agent.rs +@@ -149,6 +149,7 @@ pub(crate) async fn do_register_agent( + } + } + ++#[cfg(feature = "testing")] + #[cfg(test)] + mod tests { + use super::*; +-- +2.35.3 + diff --git a/rust-keylime-set-supplementary-groups.patch b/rust-keylime-set-supplementary-groups.patch new file mode 100644 index 0000000..eba875a --- /dev/null +++ b/rust-keylime-set-supplementary-groups.patch @@ -0,0 +1,162 @@ +From 4ec807b1bbcfaa67f85d0c2659b1f439c2f540b4 Mon Sep 17 00:00:00 2001 +From: Anderson Toshiyuki Sasaki +Date: Fri, 24 Jun 2022 16:25:54 +0200 +Subject: [PATCH] permissions: Set supplementary groups when dropping + privileges + +This allows the agent to run with the user primary group and have the +access given by the supplementary groups. + +Fixes: #414 + +Signed-off-by: Anderson Toshiyuki Sasaki +--- + src/permissions.rs | 70 ++++++++++++++++++++++++++++++++++------------ + 1 file changed, 52 insertions(+), 18 deletions(-) + +diff --git a/src/permissions.rs b/src/permissions.rs +index 279a6dd..86e3fae 100644 +--- a/src/permissions.rs ++++ b/src/permissions.rs +@@ -2,7 +2,7 @@ + // Copyright 2021 Keylime Authors + + use crate::error::{Error, Result}; +-use libc::{gid_t, uid_t}; ++use libc::{c_char, c_int, gid_t, uid_t}; + use log::*; + use std::os::unix::ffi::OsStrExt; + use std::{ +@@ -13,10 +13,9 @@ use std::{ + ptr, + }; + +-#[derive(Debug)] + pub(crate) struct UserIds { +- uid: uid_t, +- gid: gid_t, ++ passwd: libc::passwd, ++ group: libc::group, + } + + pub(crate) fn get_gid() -> gid_t { +@@ -47,14 +46,14 @@ impl TryFrom<&str> for UserIds { + let group = parts[1]; + + // Get gid from group name +- let gid = if let Ok(g_cstr) = CString::new(group.as_bytes()) { ++ let grnam = if let Ok(g_cstr) = CString::new(group.as_bytes()) { + let p = unsafe { libc::getgrnam(g_cstr.as_ptr()) }; + if p.is_null() { + let e = io::Error::last_os_error(); + error!("Could not get group {}: {}", group, e); + return Err(Error::Conversion(e.to_string())); + } +- unsafe { (*p).gr_gid } ++ unsafe { (*p) } + } else { + return Err(Error::Conversion(format!( + "Failed to convert {} to CString", +@@ -63,14 +62,14 @@ impl TryFrom<&str> for UserIds { + }; + + // Get uid from user name +- let uid = if let Ok(u_cstr) = CString::new(user.as_bytes()) { ++ let passwd = if let Ok(u_cstr) = CString::new(user.as_bytes()) { + let p = unsafe { libc::getpwnam(u_cstr.as_ptr()) }; + if p.is_null() { + let e = io::Error::last_os_error(); + error!("Could not get user {}: {}", user, e); + return Err(Error::Conversion(e.to_string())); + } +- unsafe { (*p).pw_uid } ++ unsafe { (*p) } + } else { + return Err(Error::Conversion(format!( + "Failed to convert {} to CString", +@@ -78,7 +77,10 @@ impl TryFrom<&str> for UserIds { + ))); + }; + +- Ok(UserIds { uid, gid }) ++ Ok(UserIds { ++ passwd, ++ group: grnam, ++ }) + } + } + +@@ -88,22 +90,51 @@ impl TryFrom<&str> for UserIds { + pub(crate) fn run_as(user_group: &str) -> Result<()> { + let ids: UserIds = user_group.try_into()?; + +- // Drop supplementary groups +- if unsafe { libc::setgroups(0, ptr::null()) } != 0 { ++ // Set gid ++ if unsafe { libc::setgid(ids.group.gr_gid) } != 0 { + let e = io::Error::last_os_error(); +- error!("Could not drop supplementary groups: {}", e); ++ error!("Could not set group id: {}", e); + return Err(Error::Permission); + } + +- // Set gid +- if unsafe { libc::setgid(ids.gid) } != 0 { ++ // Get list of supplementary groups ++ let mut sup_groups: [gid_t; 32] = [0u32; 32]; ++ let mut ngroups: c_int = 32; ++ if unsafe { ++ libc::getgrouplist( ++ ids.passwd.pw_name, ++ ids.group.gr_gid, ++ sup_groups.as_mut_ptr(), ++ &mut ngroups, ++ ) ++ } < 0 ++ { ++ // Allocate a Vec and try again ++ let mut sup_groups: Vec = Vec::with_capacity(ngroups as usize); ++ if unsafe { ++ libc::getgrouplist( ++ ids.passwd.pw_name, ++ ids.group.gr_gid, ++ sup_groups.as_mut_ptr(), ++ &mut ngroups, ++ ) ++ } < 0 ++ { ++ error!("Could not get list of supplementary groups"); ++ return Err(Error::Permission); ++ } ++ } ++ ++ // Set supplementary groups ++ if unsafe { libc::setgroups(ngroups as usize, sup_groups.as_ptr()) } != 0 ++ { + let e = io::Error::last_os_error(); +- error!("Could not set group id: {}", e); ++ error!("Could not set supplementary groups: {}", e); + return Err(Error::Permission); + } + + // Set uid +- if unsafe { libc::setuid(ids.uid) } != 0 { ++ if unsafe { libc::setuid(ids.passwd.pw_uid) } != 0 { + let e = io::Error::last_os_error(); + error!("Could not set user id: {}", e); + return Err(Error::Permission); +@@ -126,9 +157,12 @@ pub(crate) fn chown(user_group: &str, path: &Path) -> Result<()> { + return Err(Error::Permission); + } + +- // change directory owner to root ++ // change directory owner + let c_path = CString::new(path.as_os_str().as_bytes())?; +- if unsafe { libc::chown(c_path.as_ptr(), ids.uid, ids.gid) } != 0 { ++ if unsafe { ++ libc::chown(c_path.as_ptr(), ids.passwd.pw_uid, ids.group.gr_gid) ++ } != 0 ++ { + error!("Failed to change file {} owner.", path.display()); + return Err(Error::Permission); + } diff --git a/rust-keylime-show-path-missing-cert.patch b/rust-keylime-show-path-missing-cert.patch new file mode 100644 index 0000000..9ad01e7 --- /dev/null +++ b/rust-keylime-show-path-missing-cert.patch @@ -0,0 +1,20 @@ +--- a/src/main.rs 2022-06-28 16:54:37.559307146 +0200 ++++ b/src/main.rs 2022-06-28 17:37:39.512350575 +0200 +@@ -512,7 +512,16 @@ + let ssl_context; + if config.mtls_enabled { + let keylime_ca_cert = +- crypto::load_x509(Path::new(&config.keylime_ca_path))?; ++ match crypto::load_x509(Path::new(&config.keylime_ca_path)) { ++ Ok(t) => Ok(t), ++ Err(e) => { ++ error!( ++ "Certificate not installed: {}", ++ config.keylime_ca_path ++ ); ++ Err(e) ++ } ++ }?; + + cert = crypto::generate_x509(&nk_priv, &config.agent_uuid)?; + mtls_cert = Some(&cert); diff --git a/sources b/sources index 0a44cf5..a9d649c 100644 --- a/sources +++ b/sources @@ -1,2 +1,2 @@ -SHA512 (rust-keylime-0.1.0~20220602gitc98e381-vendor.tar.xz) = 9860a61b03d9658fc9f7a5eb515761ac581358cd6e85b2f2fd6d41bd55f33779c8c109a8081a953f513c6da6355c3106d9c7e25d35b77742c9954982b3e7dc7b -SHA512 (rust-keylime-0.1.0~20220602gitc98e381.tar.gz) = 9802a00e6993f5059a5b9720ce6da6516c200a9960864cf5b8e64d42d0c3ef545fc15527f9782011633062867859e020f51ac1e64a97a65ab0fdf370a9bf1bec +SHA512 (rust-keylime-0.1.0~20220603gitaed51c7.tar.gz) = 0a045b0caa13a582a1270428edb49a7e20cc7df15b749458a9ddb2b84c05f240225d9e876a0cc082978dc5b52f7e0175cbbc3b937edd1ffed68e252be3ea17f8 +SHA512 (rust-keylime-0.1.0~20220603gitaed51c7-vendor.tar.xz) = 071cec539b70dc25ca8a03fbc17a185d0d8bc3eb90d120da72abfa056712a41e773cc5f372d2d4dd1e6f13b8aba448c200492c830d2f2241c7cb27e5a2833352