Skip to content

Commit

Permalink
libpriv/importer: move path-checking logic to Rust
Browse files Browse the repository at this point in the history
This moves the path-checking logic to Rust.
Additionally it tweaks the /opt conditions to use absolute paths.
  • Loading branch information
lucab authored and cgwalters committed May 10, 2021
1 parent ffb8353 commit 7c7d004
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 34 deletions.
63 changes: 63 additions & 0 deletions rust/src/importer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//! Logic for unpacking and importing an RPM.
//!
//! The design here is to reuse libarchive's RPM support for most of it.
//! We do however need to look at file capabilities, which are part of the header.
//! Hence we end up with two file descriptors open.
// SPDX-License-Identifier: Apache-2.0 OR MIT

/// Whether absolute `path` is allowed in OSTree content.
///
/// When we do a unified core, we'll likely need to add /boot to pick up
/// kernels here at least. This is intended short term to address
/// https://github.com/projectatomic/rpm-ostree/issues/233
pub fn path_is_ostree_compliant(path: &str) -> bool {
if matches!(path, "/" | "/usr" | "/bin" | "/sbin" | "/lib" | "/lib64") {
return true;
}

if path.starts_with("/bin/")
|| path.starts_with("/sbin/")
|| path.starts_with("/lib/")
|| path.starts_with("/lib64/")
{
return true;
}

if path.starts_with("/usr/") && !path.starts_with("/usr/local") {
return true;
}

false
}

/// Whether absolute `path` belongs to `/opt` hierarchy.
pub fn path_is_in_opt(path: &str) -> bool {
path == "/opt" || path.starts_with("/opt/")
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_path_is_compliant() {
let ostree_cases = &["/", "/usr", "/usr/share", "/bin/foo"];
for entry in ostree_cases {
assert_eq!(path_is_ostree_compliant(entry), true, "{}", entry);
assert_eq!(path_is_in_opt(entry), false, "{}", entry);
}

let opt_cases = &["/opt", "/opt/misc"];
for entry in opt_cases {
assert_eq!(path_is_ostree_compliant(entry), false, "{}", entry);
assert_eq!(path_is_in_opt(entry), true, "{}", entry);
}

let denied_cases = &["/var", "/etc", "/var/run", "/usr/local", "", "./", "usr/"];
for entry in denied_cases {
assert_eq!(path_is_ostree_compliant(entry), false, "{}", entry);
assert_eq!(path_is_in_opt(entry), false, "{}", entry);
}
}
}
12 changes: 10 additions & 2 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ pub mod ffi {
) -> Result<DeploymentLayeredMeta>;
}

// importer.rs
extern "Rust" {
fn path_is_in_opt(path: &str) -> bool;
fn path_is_ostree_compliant(path: &str) -> bool;
}

// initramfs.rs
extern "Rust" {
fn get_dracut_random_cpio() -> &'static [u8];
Expand Down Expand Up @@ -528,11 +534,13 @@ pub(crate) use extensions::*;
mod fedora_integration;
mod history;
pub use self::history::*;
mod importer;
pub(crate) use importer::*;
mod initramfs;
pub(crate) use self::initramfs::*;
mod isolation;
mod journal;
pub(crate) use self::journal::*;
mod initramfs;
pub(crate) use self::initramfs::*;
mod lockfile;
pub(crate) use self::lockfile::*;
mod live;
Expand Down
33 changes: 17 additions & 16 deletions src/libpriv/rpmostree-importer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -610,18 +610,6 @@ append_tmpfiles_d (RpmOstreeImporter *self,
}
}

/* When we do a unified core, we'll likely need to add /boot to pick up
* kernels here at least. This is intended short term to address
* https://github.com/projectatomic/rpm-ostree/issues/233
*/
static gboolean
path_is_ostree_compliant (const char *path)
{
g_assert (*path == '/');
path++;
return (*path == '\0' || rpmostree_relative_path_is_ostree_compliant (path));
}

static OstreeRepoCommitFilterResult
compose_filter_cb (OstreeRepo *repo,
const char *path,
Expand All @@ -636,6 +624,10 @@ compose_filter_cb (OstreeRepo *repo,

gboolean error_was_set = (error && *error != NULL);

/* Sanity check that path is absolute */
g_assert (path != NULL);
g_assert (*path == '/');

/* Are we filtering out docs? Let's check that first */
if (self->doc_files && g_hash_table_contains (self->doc_files, path))
return OSTREE_REPO_COMMIT_FILTER_SKIP;
Expand Down Expand Up @@ -699,11 +691,11 @@ compose_filter_cb (OstreeRepo *repo,
else if (!error_was_set)
{
/* And ensure the RPM installs into supported paths.
* Note that we rewrite opt in handle_translate_pathname, but
* Note that we rewrite /opt in handle_translate_pathname, but
* this gets called with the old path, so handle it here too. */
if (!(path_is_ostree_compliant (path) ||
g_str_equal (path, "opt") ||
g_str_has_prefix (path, "opt/")))
bool is_supported = rpmostreecxx::path_is_ostree_compliant (path) ||
rpmostreecxx::path_is_in_opt (path);
if (!is_supported)
{
if ((self->flags & RPMOSTREE_IMPORTER_FLAGS_SKIP_EXTRANEOUS) == 0)
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
Expand Down Expand Up @@ -737,6 +729,11 @@ unprivileged_filter_cb (OstreeRepo *repo,
gpointer user_data)
{
RpmOstreeImporter *self = ((cb_data*)user_data)->self;

/* Sanity check that path is absolute */
g_assert (path != NULL);
g_assert (*path == '/');

/* Are we filtering out docs? Let's check that first */
if (self->doc_files && g_hash_table_contains (self->doc_files, path))
return OSTREE_REPO_COMMIT_FILTER_SKIP;
Expand Down Expand Up @@ -779,6 +776,10 @@ rojig_filter_cb (OstreeRepo *repo,
if (error_was_set)
return OSTREE_REPO_COMMIT_FILTER_SKIP;

/* Sanity check that path is absolute */
g_assert (path != NULL);
g_assert (*path == '/');

self->n_rojig_total++;

if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
Expand Down
13 changes: 0 additions & 13 deletions src/libpriv/rpmostree-util.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1133,19 +1133,6 @@ rpmostree_timestamp_str_from_unix_utc (guint64 t)
return g_strdup_printf ("(invalid timestamp)");
}

gboolean
rpmostree_relative_path_is_ostree_compliant (const char *path)
{
g_assert (path);
g_assert (*path != '/');
return (g_str_equal (path, "usr") || (g_str_has_prefix (path, "usr/")
&& !g_str_has_prefix (path, "usr/local/")) ||
g_str_equal (path, "bin") || g_str_has_prefix (path, "bin/") ||
g_str_equal (path, "sbin") || g_str_has_prefix (path, "sbin/") ||
g_str_equal (path, "lib") || g_str_has_prefix (path, "lib/") ||
g_str_equal (path, "lib64") || g_str_has_prefix (path, "lib64/"));
}

char*
rpmostree_maybe_shell_quote (const char *s)
{
Expand Down
3 changes: 0 additions & 3 deletions src/libpriv/rpmostree-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,9 +320,6 @@ rpmostree_str_to_auto_update_policy (const char *str,
char*
rpmostree_timestamp_str_from_unix_utc (guint64 t);

gboolean
rpmostree_relative_path_is_ostree_compliant (const char *path);

char*
rpmostree_maybe_shell_quote (const char *s);

Expand Down

0 comments on commit 7c7d004

Please sign in to comment.