-
Notifications
You must be signed in to change notification settings - Fork 11
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
Backend implementation #7
Conversation
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did an initial pass. I still need to take a closer look at the tests.
|
||
/// Comparison to perform when matching a condition. | ||
#[derive(Clone, Debug, PartialEq)] | ||
pub enum SeccompCmpOp { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: not all names follow the same convention. Some names have Seccomp
as a prefix, others do not. I would drop Seccomp
from all of them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reasoning behind this is so that we can easily distinguish the types that make up the IR (intermediate representation). All such types have Seccomp*
embedded in their name.
This will make for more readable code once we add the JSON frontend types, those being named like JsonRule
, JsonFilter
, etc.
/// * `offset` - The given jump offset to the start of the next rule. | ||
/// | ||
fn into_eq_bpf(self, offset: u8) -> Vec<sock_filter> { | ||
let (msb, lsb) = self.split_value(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having you looked into de-duplicating the into_
functions? I wonder if we could reduce the duplicated code while still keep the readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have, but I couldn't find a better way
src/backend/filter.rs
Outdated
bpf | ||
}) | ||
.collect(); | ||
let chain_len: usize = chain.iter().map(std::vec::Vec::len).sum(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Vec::len
instead of std::vec::...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
let mut built_syscall = Vec::with_capacity(chain_len + 2); | ||
built_syscall.push(BPF_JUMP( | ||
BPF_JMP | BPF_JEQ | BPF_K, | ||
// Safe because linux system call numbers are nowhere near the u32::MAX value. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we define them as i64
then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
because that's what libc expects for the syscall and that's what's used for the syscall numbers in rust's libc crate: https://docs.rs/libc/0.2.98/libc/constant.SYS_open.html.
I think it's better to have the cast here than duplicating it across countless system calls in user filters.
This struct will be used to parametrise the filters with the target architecture they are compiled for. The compilation logic will embed the architecture check so that we make sure the BPF programs are not installed on different architecures (which may have different system call numbers). Signed-off-by: alindima <alindima@amazon.com>
Module containing constants, types and helper functions used in the BPF codegen. The TargetArch::get_audit_value uses constants from the BPF module for associating the TargetArch variant to the right audit value used in the BPF compilation. Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
@alindima Thank you for the great work. I finished a draft of integrating Cloud Hypervisor with your PR, and can confirm it works as expected with both SeccompAction Trap and Log. Overall, I think the new interface (APIs and Types) are pretty good and cleaner. Admittedly it requires lots of changes due to the dramatic interface changes. Only one comment/open-question: I wonder whether we should include some similar macros to make it easier (or more readable) to define complex |
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Renamed the filter_action to match_action and the default_action to mismatch_action, to make them slightly more expressive and easier to understand. Signed-off-by: alindima <alindima@amazon.com>
Signed-off-by: alindima <alindima@amazon.com>
Thank you @likebreath for your work on integrating seccompiler in Cloud hypervisor, it's great to hear it works as expected!
Great to hear the interface has been indeed improved. Unfortunately it does require quite a lot of changes, but most of them are repetitive (and automatable with regex find&replace) and the one-time character of the changes I think make the effort worth it 😄
That is a good question. I've given the issue some thought. The two macros have a pretty small implementation and are quite an opinionated way of instantiating the objects. For example, other users of the library may not want to Given the above, I think it would be fine to keep those small macros in CH for now. What do you think? Of course, we can revisit this choice later on if we come up with better abstractions that make the library easier to use for everybody. |
Right. That's something I wanted to improve hopefully at the time of landing the integration to CH (after landing your PR of course).
This sounds good to me.
Agree. Improving abstractions over creating complex conditions definitely worth a revisit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are still a few std::u32::max
calls that should be replaced with u32::max
.
fn validate_seccomp_filter( | ||
rules: Vec<(i64, Vec<SeccompRule>)>, | ||
validation_fn: fn(), | ||
should_fail: Option<bool>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: It is a bit hard to understand how to use this parameter, specifically what is the meaning of None
. We could define an enum in which we have 3 options (with some better names maybe):
enum Return {
Errno(u32),
NoErrno,
NA,
}
This PR implements the Rust IR and the logic for compiling it into BPF code.
In order for the design to be fully implemented, we need to add the JSON frontend, which will come in a future PR.