Parse rule files with Rust

This commit is contained in:
topjohnwu
2023-05-24 19:11:56 -07:00
parent 5a94ef9106
commit 18d0cedbe2
16 changed files with 176 additions and 93 deletions
+5
View File
@@ -7,5 +7,10 @@ edition = "2021"
crate-type = ["staticlib", "rlib"]
path = "lib.rs"
[build-dependencies]
cxx-gen = { workspace = true }
[dependencies]
base = { path = "../base" }
cxx = { workspace = true }
anyhow = { workspace = true }
+10
View File
@@ -103,3 +103,13 @@ bool sepolicy::genfscon(const char *fs_name, const char *path, const char *ctx)
bool sepolicy::exists(const char *type) {
return hashtab_search(impl->db->p_types.table, type) != nullptr;
}
void sepolicy::load_rule_file(const char *file) {
rust::load_rule_file(*this, rust::Slice(
reinterpret_cast<const uint8_t *>(file), strlen(file)));
}
void sepolicy::load_rules(const std::string &rules) {
rust::load_rules(*this, rust::Slice(
reinterpret_cast<const uint8_t *>(rules.data()), rules.length()));
}
+8
View File
@@ -0,0 +1,8 @@
use crate::gen::gen_cxx_binding;
#[path = "../include/gen.rs"]
mod gen;
fn main() {
gen_cxx_binding("policy-rs");
}
+4 -2
View File
@@ -1,9 +1,10 @@
#pragma once
#include <stdlib.h>
#include <selinux.hpp>
#include <string>
#include <selinux.hpp>
#define ALL nullptr
struct sepolicy {
@@ -17,7 +18,8 @@ struct sepolicy {
// External APIs
bool to_file(c_str file);
void parse_statement(c_str stmt);
void parse_statement(c_str stmt, int len);
void parse_statement(c_str stmt) { parse_statement(stmt, strlen(stmt)); }
void load_rules(const std::string &rules);
void load_rule_file(c_str file);
+52
View File
@@ -1 +1,53 @@
use io::Cursor;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::pin::Pin;
use std::{io, str};
pub use base;
use base::*;
use crate::ffi::sepolicy;
#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("include/sepolicy.hpp");
type sepolicy;
unsafe fn parse_statement(self: Pin<&mut sepolicy>, stmt: *const c_char, len: i32);
}
#[namespace = "rust"]
extern "Rust" {
fn load_rules(sepol: Pin<&mut sepolicy>, rules: &[u8]);
fn load_rule_file(sepol: Pin<&mut sepolicy>, filename: &[u8]);
}
}
fn load_rules_from_reader<T: BufRead>(mut sepol: Pin<&mut sepolicy>, reader: &mut T) {
reader.foreach_lines(|line| {
let bytes = line.trim().as_bytes();
unsafe {
sepol
.as_mut()
.parse_statement(bytes.as_ptr().cast(), bytes.len() as i32);
}
true
});
}
pub fn load_rule_file(sepol: Pin<&mut sepolicy>, filename: &[u8]) {
fn inner(sepol: Pin<&mut sepolicy>, filename: &[u8]) -> anyhow::Result<()> {
let filename = str::from_utf8(filename)?;
let mut reader = BufReader::new(File::open(filename)?);
load_rules_from_reader(sepol, &mut reader);
Ok(())
}
inner(sepol, filename).ok_or_log();
}
pub fn load_rules(sepol: Pin<&mut sepolicy>, rules: &[u8]) {
let mut cursor = Cursor::new(rules);
load_rules_from_reader(sepol, &mut cursor);
}
+2
View File
@@ -5,6 +5,8 @@
#include <sepol/policydb/policydb.h>
#include <sepolicy.hpp>
#include "policy-rs.hpp"
struct sepol_impl : public sepolicy {
avtab_ptr_t get_avtab_node(avtab_key_t *key, avtab_extended_perms_t *xperms);
bool add_rule(const char *s, const char *t, const char *c, const char *p, int effect, bool invert);
+7 -47
View File
@@ -266,22 +266,22 @@ static bool parse_pattern_9(const Func &fn, const char *action, char *stmt) {
}
#define add_action_func(name, type, fn) \
else if (strcmp(name, action) == 0) { \
auto __fn = [=](auto && ...args){ return (fn)(args...); };\
if (!parse_pattern_##type(__fn, name, remain)) \
LOGW("Syntax error in '%s'\n\n%s\n", stmt, type_msg_##type); \
else if (strcmp(name, action) == 0) { \
auto __fn = [&](auto && ...args){ return (fn)(args...); }; \
if (!parse_pattern_##type(__fn, name, remain)) \
LOGW("Syntax error in '%.*s'\n\n%s\n", len, stmt, type_msg_##type); \
}
#define add_action(act, type) add_action_func(#act, type, act)
void sepolicy::parse_statement(const char *stmt) {
void sepolicy::parse_statement(const char *stmt, int len) {
// strtok modify strings, create a copy
string cpy(stmt);
string cpy(stmt, len);
char *remain;
char *action = strtok_r(cpy.data(), " ", &remain);
if (remain == nullptr) {
LOGW("Syntax error in '%s'\n\n", stmt);
LOGW("Syntax error in '%.*s'\n\n", len, stmt);
return;
}
@@ -310,43 +310,3 @@ void sepolicy::parse_statement(const char *stmt) {
else { LOGW("Unknown action: '%s'\n\n", action); }
}
void sepolicy::load_rule_file(const char *file) {
file_readline(true, file, [&](string_view line) -> bool {
if (line.empty() || line[0] == '#')
return true;
parse_statement(line.data());
return true;
});
}
void sepolicy::load_rules(const string &rules) {
struct cookie {
const string &s;
size_t pos;
};
cookie c{rules, 0};
FILE *fp = funopen(&c, /* read */ [](void *v, char *buf, int sz) -> int {
auto c = reinterpret_cast<cookie*>(v);
if (c->pos == c->s.length())
return 0;
size_t end = std::min(c->pos + sz, c->s.length());
int len = end - c->pos;
memcpy(buf, c->s.data() + c->pos, len);
c->pos = end;
return len;
}, /* write */ [](auto, auto, auto) -> int {
return 0;
}, /* seek */ [](auto, auto, auto) -> fpos_t {
return 0;
}, /* close */ [](auto) -> int {
return 0;
});
file_readline(true, fp, [&](string_view line) -> bool {
if (line.empty() || line[0] == '#')
return true;
parse_statement(line.data());
return true;
});
}