(CEL version) Add experimental syscall_overrides config option#3369
(CEL version) Add experimental syscall_overrides config option#3369stevenengler wants to merge 2 commits intoshadow:mainfrom
syscall_overrides config option#3369Conversation
|
Intriguing! It is a significant dependency to bring in, but otoh the flexibility this would provide to give users an alternative to patching shadow would be pretty nice. Did you consider any more-established extension languages like lua or guile? |
My reasons for using CEL were that it's pure-rust (no need to install and link to a separate interpreter), you can explicitly compile it to bytecode ahead of time so is probably decently fast, it's straightforward to add to shadow (about 100 lines of code), and it's simple (expressions are similar to a weakly typed C). That being said I'm not very familiar with lua or guile, so they might be a better choice. I think if there's a nice way to optionally link to an interpreter so that users don't need to install one to use shadow, but only if they want to use this feature, that could work too. |
Those seem like pretty good reasons. Looking at crate.io a bit, it looks like there's a fairly mature and popular crate mlua for lua. My main reasoning for considering it instead of CEL is that I think more devs have prior experience with lua, and that it's a quite mature and fast language designed for pretty much this purpose. It's a more full-featured and therefore complex language, which would be a tradeoff. The implementation "LuaJit" (which the mlua wrapper supports) is quite fast and does JIT-compilation. It isn't pure rust though; I think the user would need a system lua dev package installed so that it can be linked in. It might be worth giving it a try to see what what that would look like and how it compares. I don't really feel super strongly about lua in particular, but generally it seems worth being a bit careful about this decision. Even if we call it an "experimental" feature, in practice if users start using it they could develop a fair bit of investment into it, making it pretty disruptive if we take it away again or switch to a different language. (I didn't see a similarly popular/mature crate for guile)
I think that could be done fairy easily at compile time by making it a cargo feature. |
Maybe this is an argument in favor of cel over lua. It's limited nature would prevent users from doing anything much more complex than the intended use case of "custom error codes for unimplemented features" |
|
Overall this seems positive and helpful! I think this approach is interesting and a powerful way for users to override syscalls. Some thoughts:
|
Eh, that argument loses some weight once we start advising users to use the feature to get their use-case working. OTOH I don't think we'd recommend doing anything more than the simple "one-liner"s as in Steven's example, so it hopefully wouldn't be hugely disruptive if we change or remove this feature later. But yeah I'm fine with moving forward with CEL. No extra system dependencies + fairly constrained such that users can't do anything too involved with it SGTM |
syscall_overrides config optionsyscall_overrides config option
I added a Lua version in #3375. I'd expect the performance to be lower since the only way I can see to make it work requires recompiling each expression every time.
I noticed that mlua has the "vendored" feature, which seems to solve this problem. I'm guessing it builds the C interpreter.
Yeah a downside of Lua is that I don't think you can require the user to write a pure function, which means they can modify global state and do other things. Maybe you could write an expression that proxies shadow's network requests to the real internet :) |
This allows users to override the behaviour of emulated syscalls using CEL expressions.
ef18ed8 to
377e1c2
Compare
Here are the unscientific numbers when doing a clean main (d82059b):
syscall-stub (377e1c2; this PR):
syscall-stub-lua (b40e02f):
So this PR adds about 20 seconds (~7% increase) to a clean build. This biggest reason is that cel-interpreter requires the lalrpop crate: (Aside: we build syn twice since cbindgen hasn't published a new release in a while.) Edit: Added timings for the Lua version. |
|
I'm becoming more confused about the build time. Creating a new project with a dependency of 'cel-interpreter' takes a total of 20 seconds to build and the lalrpop sub-dependency builds in 8.8 seconds (2.4 seconds for codegen). When adding a dependency of lalrpop to shadow without even using it, lalrpop builds in 51 seconds (43 seconds for codegen). I don't understand why it takes significantly longer to build in Shadow, especially when it's not even used. Code was compiled in debug mode with I think the only thing we can do is to put this |

In #3280 we discussed allowing users to add stubs for features that Shadow is missing. There are a lot of different features that users may want to add stubs for (ex: syscalls, socket options, ioctl commands, misc syscall flags, etc).
This PR adds an experimental
syscall_overridesconfiguration option that allows you to add custom overrides for syscalls. This allows you to add simple/limited custom syscall implementations using CEL expressions.There have been two recent requests for stubs/workarounds: One for having setsockopt with
SOL_IPandIP_BIND_ADDRESS_NO_PORTreturn 0, and one for returningEINVALfrom sendfile. This feature would support both these usecases without needing to modify Shadow.There are some downsides:
SOL_IP) and the third is 24 (IP_BIND_ADDRESS_NO_PORT), then the syscall should return 0.@robgjansen @sporksmith Do you have any feelings about this approach?