Discussion:
BPF64: proposal of platform-independent hardware-friendly backwards-compatible eBPF alternative
(too old to reply)
Vadim Goncharov
2024-09-10 01:05:44 UTC
Permalink
Hello!

We don't need ELF relocations!
We want better loop control!
No so little parameters,
Verifier! Leave our code alone!
-- Ping Floyd

I've recently had some experience with Linux's ePBF in it's XDP, and this left
quite negative impression. I was following via https://github.com/xdp-project/xdp-tutorial
and after 3rd lesson was trying to create a simple program for searching TCP
timestamp option and incrementing it by one. As you know, eBPF tool stack
consists of at least clang and eBPF verifier in the kernel, and after two dozen
tries eBPF verifier still didn't accept my code. I was digging into verifier
sources, and the abysses opened in front of me! Carefully and boringly going
via disassembler and verifier output, I've found that clang optimizer ignores
just checked register - patching one byte in assembler sources (and target .o)
did help. I've filed https://github.com/iovisor/bcc/issues/5062 with details
if one curious.

So, looking at eBPF ecosystem, I must say it's a Frankenstein. Sewn from good,
sometimes brilliant parts, it's a monster in outcome. Verifier is in it's own
right, compiler/optimizer is in it's own right... But at the end you even
don't have a high-level programming language! You must write in C, relatively
low-level C, and restricted subset of C. This requires very skilled
professionals - it's far from something not even user-friendly, but at least
sysadmin-friendly, like `ipfw` or `iptables` firewall rules.

Thus I looked at the foundation of eBPF architecture, with which presuppositions
in mind it was created with. In fact, it tries to be just usual programming
after checks - that is, with all that pointers. It's too x86-centric and
Linux-centric - number of registers was added just ten. So if you look at the
GitHub ticket above, when I tried to add debug to program - you know, just
specific `printf()`s - it failed verifier checks again because compiler now
had to move some variables between registers and memory, as there is limit on
just 5 arguments to call due to limit of 5 registers! And verifier, despite
being more than 20,000 lines of code, still was not smart enough to track info
between registers and stack.

So, if we'd started from beginning, what should we do? Remember classic BPF:
it has very simple validator due to it's Virtual Machine design - only forward
jumps, checks for packet boundaries at runtime, etc. You'd say eBPF tries for
performance if verifier's checks were passed? But in practice you have to toss
in as much packet boundary checks as near to actual access as possible, or
verifier may "forget" it, because of compiler optimizer. So this is not of
much difference for checking if access is after packet in classic BPF - the
same CMP/JUMP in JIT if buffer is linear, and if your OS has put packet in
several buffers, like *BSD or DPDK `mbuf`'s, the runtime check overhead is
negligible in comparison.

Ensuring kernel stability? Just don't allow arbitrary pointers, like original BPF.
Guaranteed termination time? It's possible if you place some restrictions. For
example, don't allow backward jumps but allow function calls - in case of
stack overflow, terminate program. Really need backward jumps? Let's analyze
for what purpose. You'll find these are needed for loops on packet contents.
Solve it but supporting loops in "hardware"-controlled loops, which can't be
infinite.

Finally, platforms. It's beginning of sunset of x86 era now - RISC is coming.
ARM is now not only on mobiles, but on desktops and servers. Moreover, it's
era of specialized hardware accelerators - e.g. GPU, neural processors. Even
general purpose ARM64 has 31 register, and specialized hardware can
implement much more. Then, don't tie to Linux kernel - BPF helpers are very
rigid interface, from ancient era, like syscalls.

So, let's continue *Berkeley* Packet Filter with Berkeley RISC design - having
register window idea, updated by SPARC and then by Itanium (to not waste
registers). Take NetBSD's coprocessor functions which set is passed with
a context, instead of hardcoded enums of functions - for example, BPF maps is
not something universal, both NetBSD and FreeBSD have their own tables in
firewall.

Add more features actually needed for *network* processor - e.g. 128-bit
registers for IPv6 (eBPF axed out even BPF_MSH!). And do all of this in fully
backwards-compatible way - new language should allow to run older programs
from e.g. `tcpdump` to run without any modifications, binary-compatible
(again, eBPF does not do this - it's incompatible with classiv BPF and uses
a translator from it).

Next, eBPF took "we are masquerading usual x86 programming" way not only just
in assembly language. They have very complex ELF infrastructure around it which
may be not suitable for every network card - having pc-addressed literals, as
in RISC processors allows for much simpler format: just BLOB of instructions.
BPF64 adds BPF_LITERAL "instruction" of varying length (it's interpreted by
just skipping over contents as if it was jump), which, if have special
signatures and format, allow for this BLOB of instructions to contain some
metadata about itself for loading, much simpler than ELF (esp. with DWARF).
enum bpf_func_id___x { BPF_FUNC_snprintf___x = 42 /* avoid zero */ };
That is, ancient syscall-like way of global constant, instead of context. A
"context" here is the structure passed with code to execution which contains
function pointers of what is available to this user code, in spirit of
NetBSD's `bpf_ctx_t` for their BPF_COP/BPF_COPX extensions. This is not only
provides better way than "set in stone" syscall-like number, but BPF64 goes
further and defines an "packages" in running kernel with namespaces to allow
e.g. Foo::Bar::baz() function to call Foo::quux() from another BPF program,
populating ("linking") it's context with needed function without relocations.
These "packages" expected to be available to admin in e.g. sysctl tree, with
descriptions, versioning and other attributes.
First, a BPF program using bpf_trace_printk() has to have a GPL-compatible license.
Another hard limitation is that bpf_trace_printk() can accept only up to 3 input arguments (in addition to fmt and fmt_size). This is quite often pretty limiting and you might need to use multiple bpf_trace_printk() invocations to log all the data. This limitation stems from the BPF helpers ability to accept only up to 5 input arguments in total.
Previously, bpf_trace_printk() allowed the use of only one string (%s) argument, which was quite limiting. Linux 5.13 release lifts this restriction and allows multiple string arguments, as long as total formatted output doesn't exceed 512 bytes. Another annoying restriction was the lack of support for width specifiers, like %10d or %-20s. This restriction is gone now as well
Helper function bpf_snprintf
Outputs a string into the str buffer of size str_size based on a format string stored in a read-only map pointed by fmt.
Each format specifier in fmt corresponds to one u64 element in the data array. For strings and pointers where pointees are accessed, only the pointer values are stored in the data array. The data_len is the size of data in bytes - must be a multiple of 8.
Formats %s and %p{i,I}{4,6} require to read kernel memory. Reading kernel memory may fail due to either invalid address or valid address but requiring a major memory fault. If reading kernel memory fails, the string for %s will be an empty string, and the ip address for %p{i,I}{4,6} will be 0. Not returning error to bpf program is consistent with what bpf_trace_printk() does for now.
Returns
The strictly positive length of the formatted string, including the trailing zero character. If the return value is greater than str_size, str contains a truncated string, guaranteed to be zero-terminated except when str_size is 0.
Or -EBUSY if the per-CPU memory copy buffer is busy.
static long (* const bpf_snprintf)(char *str, __u32 str_size, const char *fmt, __u64 *data, __u32 data_len) = (void *) 165;
So. In summary: BPF64 has not only traditional ("firewall on network packets")
area of use but also suitable - and having goals to design in mind - for:

* non-network. e.g. syscall arguments checking
* network protocols passing untrusted code which can be run by other side in
restricted sandbox (e.g. muSCTP custom (de)compression rules)
* an alternative to https://capnproto.org/rpc.html for multi-method
calls on high-latency links (e.g. MQTT5-like and/or for environments
when Cap’n Proto itself is not applicable, e.g. no direct connections)

I've put a sketch of design to https://github.com/nuclight/bpf64 with files:

* The `nuc_ts_prog_kern.c` (and it's include `nuc_ts_common_kern_user.h`) is
XDP/eBPF program (for Linux 6.5) for parsing TCP packet and incrementing
it's Timestamp option, if any, recording statisitics intop eBPF map.
* The `nuc_ts_incr.baw` (and it's include `nuc_ts_incr.bah`) is the equivalent
program doing the same thing, but in a new BPF64 Assembler Wrapper language,
not yet written and subject to change. Note this is a lower-level language
than C, viewed as intermediate solution until BPF64 becomes stable, after
which more higher-level language (higher than C) should be written, at least
as expressible as `tcpdump` (`libpcap`) one.
* `bpf64spec.md` for draft of Specification, but currently it's more in a
"a draft of draft" state :-)

I am requesting comments about this architecture before implementing,
especially from people knowledgeable in JIT compilers, because, though while
I see BPF64 much more simpler than eBPF (probably just several man-months to
implement), my sabbatical has ended - and design mistakes are much harder to
fix when implementation already exists.
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Poul-Henning Kamp
2024-09-10 06:38:50 UTC
Permalink
--------
Counter proposal:

1. Define the Lua execution environment in the kernel.

2. Add syscall to submit a precompiled Lua program (as bytecode)

3. Add syscall to execute submitted Lua program

And yes: I'm being 100% serious.

If we are going to reinvent "Channel Programs" 67 years after IBM
came up with them for their 709 vacuum tube computer, at the very
least we should use a sensible language syntax.

Poul-Henning
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
***@FreeBSD.ORG | TCP/IP since RFC 956
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Vadim Goncharov
2024-09-10 11:45:57 UTC
Permalink
On Tue, 10 Sep 2024 06:38:50 +0000
Post by Poul-Henning Kamp
--------
1. Define the Lua execution environment in the kernel.
2. Add syscall to submit a precompiled Lua program (as bytecode)
Anyone who thinks "any generic bytecode" misses the main point, see
below.
Post by Poul-Henning Kamp
3. Add syscall to execute submitted Lua program
And yes: I'm being 100% serious.
Well, preparing spec/letter in a rush I probably forgot the main reason
for BPF (and successors) to exist thinking it's obviuos: safety.

Let's restate: *BPF* allows UNTRUSTED user code to be executed SAFELY
in kernel.

It's easy for your Lua code (or whatever) code to hang kernel by
infinite loop. Or crash it by access on arbitrary pointer. That's why
original BPF has no backward jumps and memory access, and eBPF's
nightmare verifier walks all code paths and check pointers.

And that's why DTrace also has it's own VM and bytecode in kernel
(see https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-924.pdf Chapter 7)

Your "counter proposal" was essentially available for all these decades
in form "oh, just write KLD in C instead of that limited tcpdump".
Post by Poul-Henning Kamp
If we are going to reinvent "Channel Programs" 67 years after IBM
came up with them for their 709 vacuum tube computer, at the very
least we should use a sensible language syntax.
Don't know what that is, quick googling shows something modern on AMQP.

But Lua at least doesn't have *sensible* syntax, Perl or Tcl much better.
And I'm surprised why Fort, being available in loader, wasn't ported
for all these years.
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
David Chisnall
2024-09-10 12:59:02 UTC
Permalink
Post by Vadim Goncharov
It's easy for your Lua code (or whatever) code to hang kernel by
infinite loop. Or crash it by access on arbitrary pointer. That's why
original BPF has no backward jumps and memory access, and eBPF's
nightmare verifier walks all code paths and check pointers.
I’m not convinced by the second: Lua has a GC’d heap, you’d need to expose FFI things to it that did unsafe things, and that’s equally a problem for eBPF.

The first is not a problem. The Lua interpreter has a bytecode limit. You can define a bounded number of bytecodes that it will execute. The problem comes from the standard library. Things like string.gmatch can have high-order polynomial complexity and so it’s possible for a Lua program that executes a small number of bytecodes to create a string that takes a vast amount of time to match on. Again, this is also a problem for eBPF if you expose a similar function, the solution is to not expose functions with large data-dependent runtimes to untrusted script.

More generally, there are a lot of problems with interpreting or JITing untrusted code in the kernel in *any* runtime. Speculative execution makes it easy to use these as primitives to leak kernel secrets, either via timing of the programs themselves, using the JIT to generate gadgets, or by leaking data via cache priming.

Both eBPF and Lua have these problems.

The thing I would like to see for our current use of semi-trusted Lua in the kernel (ZFS channel programs) is a way of exposing them (under /dev/something) as file descriptors and modifying the ioctls that run them to take a file descriptor argument. I would like to separate the two operations:

- Load a channel program.
- Run a channel program.

In the post-Spectre world, the former remains a privileged operation. Even though Linux pretends it isn’t, allowing arbitrary (even arbitrary constrained) code to run in the kernel’s address space is a problem. Invoking such code; however, should follow the same rules as everything else. A trusted entity should be able to load a pile of Lua / eBPF / BPF64 / whatever programs into the kernel and then set up permissions so that sandboxed programs (and jails) can use a defined subset of them.

David
Vadim Goncharov
2024-09-10 22:12:28 UTC
Permalink
On Tue, 10 Sep 2024 15:58:25 +0100
Post by David Chisnall
Post by Vadim Goncharov
I am not an experience assembler user and don't understand how
Spectre works - that's why I've written RFC letter even before spec
finished - but isn't that (Spectre) an x86-specific thing? BPF64
has more registers and primarily target RISC architectures if we're
speaking of JIT.
No, speculative execution vulnerabilities are present in any CPUs
that do speculative execution that does not have explicit mitigations
against them (i.e. all that have shipped now). Cache side channels
are present in any system with caches and do not have explicit
mitigations (i.e. all that have shipped so far).
Mitigations around these things are an active research area, but so
far everything that’s been proposed has a performance hit and several
of them were broken before anyone even implemented them outside a
simulator.
Post by Vadim Goncharov
And BPF64 is meant as backwards-compatible extension of existing
BPF, that is, it has bytecode interpreter (for(;;) switch/case) as
primary form and JIT only then - thus e.g. JIT can be disabled for
non-root users in case of doubt. eBPF can't do this - it always
exists in native machine code form at execution, bytecode is only
for verifier stage.
This has absolutely no impact on cache side channels. The JIT makes
some attacks harder but prime-and-probe attacks are still possible.
Wait, do you want to say that problem is not in JIT, that is, that
current BPF (e.g. tcpdump) present in the kernel - are also vulnerable?
Also, let's classify vulnerabilities. Is speculative execution
vulnerability the same as cache side channels? In any case, what impact
is? E.g. attacker could leak secrets, but *where* would them leak? BPF
typically returns one 32-bit number as a verdict (often as just
boolean), is it really attack vector? That is, may be solution is just
"don't give read access to BPF-writable memory segments to untrusteds".

Next, if problem is with timing, then isn't that enough to just
restrict BPF code on having access to timers with resolution high
enough?
Post by David Chisnall
BPF can be loaded only by root, who can also load kernel modules and
map /dev/[k]mem, and FreeBSD does not protect the root <-> kernel
boundary.
Wrong. It is possible for decades to do `chmod a+r /dev/bpf*` and run
tcpdump as non-root, which will load BPF code into kernel. Is *that*
also a vulnerability, and if so, why it was never reported?
Post by David Chisnall
Please read some of the (many) attacks on eBPF to better understand
the security landscape here. It’s a *very* hard problem to solve.
Finally, the most big (in effort) question: suppose we limited to
trusted root user etc. so it's of no concern. Are there now any
objections/suggestions/comments on (rest of) BPF64 ?
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Justin Hibbits
2024-09-10 14:29:19 UTC
Permalink
On Tue, 10 Sep 2024 13:59:02 +0100
Post by Vadim Goncharov
It's easy for your Lua code (or whatever) code to hang kernel by
infinite loop. Or crash it by access on arbitrary pointer. That's
why original BPF has no backward jumps and memory access, and eBPF's
nightmare verifier walks all code paths and check pointers.
I’m not convinced by the second: Lua has a GC’d heap, you’d need to
expose FFI things to it that did unsafe things, and that’s equally a
problem for eBPF.
The first is not a problem. The Lua interpreter has a bytecode
limit. You can define a bounded number of bytecodes that it will
execute. The problem comes from the standard library. Things like
string.gmatch can have high-order polynomial complexity and so it’s
possible for a Lua program that executes a small number of bytecodes
to create a string that takes a vast amount of time to match on.
Again, this is also a problem for eBPF if you expose a similar
function, the solution is to not expose functions with large
data-dependent runtimes to untrusted script.
More generally, there are a lot of problems with interpreting or
JITing untrusted code in the kernel in *any* runtime. Speculative
execution makes it easy to use these as primitives to leak kernel
secrets, either via timing of the programs themselves, using the JIT
to generate gadgets, or by leaking data via cache priming.
Both eBPF and Lua have these problems.
The thing I would like to see for our current use of semi-trusted Lua
in the kernel (ZFS channel programs) is a way of exposing them (under
/dev/something) as file descriptors and modifying the ioctls that run
them to take a file descriptor argument. I would like to separate
- Load a channel program.
- Run a channel program.
In the post-Spectre world, the former remains a privileged operation.
Even though Linux pretends it isn’t, allowing arbitrary (even
arbitrary constrained) code to run in the kernel’s address space is a
problem. Invoking such code; however, should follow the same rules
as everything else. A trusted entity should be able to load a pile
of Lua / eBPF / BPF64 / whatever programs into the kernel and then
set up permissions so that sandboxed programs (and jails) can use a
defined subset of them.
David
This sounds a lot like IBM i / OS400 / System/360, or even Singularity
from Microsoft, which uses a trusted JIT or AOT compiler to convert
arbitrary bytecode to constrained machine code, so the machine code
translator becomes the only trusted party, to accept or reject the
arbitrary source (byte)code from the user.

- Justin


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Alexander Nasonov
2024-09-10 19:04:40 UTC
Permalink
Post by Poul-Henning Kamp
A) How powerful do you want the downloaded bytecode to be ?
...
Post by Poul-Henning Kamp
There are basically two possible answers to A.
Either the downloaded code is "real", which means it can include
loops, function calls etc. or it is a "toy" which relies on
Brinch-Hansen's "all arrows point to the right" argument to prove
that it will always terminate.
BPF can be easily modified to have functions and calls but it will
increase worst case execution complexity to quadratic and the stack
growth will have to be watched closely:

- always jump forward (within the current function),
- always call backwards (outside of the current function).

Backward jumps (within the current function) can be implemented
with some kind of slowly closing door. For instance, in packet
filtering, the first backward jump disables access to the first
byte, the second backward jump disables access to the second byte,
etc.

In general, it will require a special counter but BPFJIT compiler
should be able to spot simple loops that process at least one
byte on each iteration and minimise runtime overhead.
Post by Poul-Henning Kamp
...
The answer to that is that you can write them in /any/ programming
language you want, as long as the interpreter for the resulting
(byte-)code an spot attempts to jump backwards, and refuse to
do so, if so configured.
I guess it will work for a simple single-pass interpreter that
generates bytecode as it reads source code but anything more
complicated may reshuffle bytecode and some forward jumps may
become backward jumps etc.
Post by Poul-Henning Kamp
And that is why I say: If we're going to do this, let us do
it with Lua: It's already in our tree and it will do the
job nicely.
Lua is a good choice, IMO but we likely need a subset of Lua (e.g.
no metatables, no C or paused GC with a periodic lua_State rotations
to collect garbage).

Alex


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Rob Wing
2024-09-10 23:05:21 UTC
Permalink
Doesn't NetBSD have Lua in the kernel...anyone have any experience with it?

re BPF64:

looks like hand waving, proposing two unwritten languages that extends an
ISA that is still being drafted by IETF...hmm

you can make anything look good on paper but the devil is in the
details...which there are plenty of
Post by Vadim Goncharov
On Tue, 10 Sep 2024 15:58:25 +0100
Post by David Chisnall
Post by Vadim Goncharov
I am not an experience assembler user and don't understand how
Spectre works - that's why I've written RFC letter even before spec
finished - but isn't that (Spectre) an x86-specific thing? BPF64
has more registers and primarily target RISC architectures if we're
speaking of JIT.
No, speculative execution vulnerabilities are present in any CPUs
that do speculative execution that does not have explicit mitigations
against them (i.e. all that have shipped now). Cache side channels
are present in any system with caches and do not have explicit
mitigations (i.e. all that have shipped so far).
Mitigations around these things are an active research area, but so
far everything that’s been proposed has a performance hit and several
of them were broken before anyone even implemented them outside a
simulator.
Post by Vadim Goncharov
And BPF64 is meant as backwards-compatible extension of existing
BPF, that is, it has bytecode interpreter (for(;;) switch/case) as
primary form and JIT only then - thus e.g. JIT can be disabled for
non-root users in case of doubt. eBPF can't do this - it always
exists in native machine code form at execution, bytecode is only
for verifier stage.
This has absolutely no impact on cache side channels. The JIT makes
some attacks harder but prime-and-probe attacks are still possible.
Wait, do you want to say that problem is not in JIT, that is, that
current BPF (e.g. tcpdump) present in the kernel - are also vulnerable?
Also, let's classify vulnerabilities. Is speculative execution
vulnerability the same as cache side channels? In any case, what impact
is? E.g. attacker could leak secrets, but *where* would them leak? BPF
typically returns one 32-bit number as a verdict (often as just
boolean), is it really attack vector? That is, may be solution is just
"don't give read access to BPF-writable memory segments to untrusteds".
Next, if problem is with timing, then isn't that enough to just
restrict BPF code on having access to timers with resolution high
enough?
Post by David Chisnall
BPF can be loaded only by root, who can also load kernel modules and
map /dev/[k]mem, and FreeBSD does not protect the root <-> kernel
boundary.
Wrong. It is possible for decades to do `chmod a+r /dev/bpf*` and run
tcpdump as non-root, which will load BPF code into kernel. Is *that*
also a vulnerability, and if so, why it was never reported?
Post by David Chisnall
Please read some of the (many) attacks on eBPF to better understand
the security landscape here. It’s a *very* hard problem to solve.
Finally, the most big (in effort) question: suppose we limited to
trusted root user etc. so it's of no concern. Are there now any
objections/suggestions/comments on (rest of) BPF64 ?
--
Rob Wing
2024-09-11 00:55:15 UTC
Permalink
Post by Vadim Goncharov
What's the point to waste resources on writing thing that is known to
be not accepted to base system from the very beginning?
what's the point of talking about thing you're never going to write/finish
even if it was accepted?

Or even bikesheds are in short supply now?


have you considered calling it eBPF++ or BPF128?

at any rate, don't claim the sky is falling on the grounds that I think
your proposal is far fetched

if you think you've got a great idea and have a need for it, then write it
and use it - if other people adopt it, even better

all the best to your endeavors and don't let the naysayers hold you back

-Rob
Poul-Henning Kamp
2024-09-12 07:13:12 UTC
Permalink
Post by Vadim Goncharov
Because - and I've written that from the beginning - wrong architecture
will cost too much if your code already exists, than if fixed before
that. So I've received worthy feedback describing problems; not that
were good solutions yet, though...
And when people do not agree with your proposed architecture "FreeBSD is dying!!!1!!" ?
Post by Vadim Goncharov
Not you. FreeBSD already had precedent when already written and
https://lists.freebsd.org/pipermail/cvs-src/2007-October/082398.html
and that happened by exactly the same person with similar tone (not you).
Yes, I will resist all bad architecture.
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
***@FreeBSD.ORG | TCP/IP since RFC 956
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Bob Bishop
2024-09-10 11:51:08 UTC
Permalink
Hi,
Post by Poul-Henning Kamp
--------
1. Define the Lua execution environment in the kernel.
2. Add syscall to submit a precompiled Lua program (as bytecode)
3. Add syscall to execute submitted Lua program
And yes: I'm being 100% serious.
If we are going to reinvent "Channel Programs" 67 years after IBM
came up with them for their 709 vacuum tube computer, at the very
least we should use a sensible language syntax.
+1

We did something like this at $work years ago with FORTH, to do weird things in a driver.
Post by Poul-Henning Kamp
Poul-Henning
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.
--
Bob Bishop
***@gid.co.uk






--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Vadim Goncharov
2024-09-10 23:47:35 UTC
Permalink
On Tue, 10 Sep 2024 15:05:21 -0800
Post by Rob Wing
Doesn't NetBSD have Lua in the kernel...anyone have any experience with it?
Lua is not suitable for the discussed problem domains, don't listen to
those who did not read material and did not understand short
descriptions.
Post by Rob Wing
looks like hand waving, proposing two unwritten languages that
extends an ISA that is still being drafted by IETF...hmm
What's the point to waste resources on writing thing that is known to
be not accepted to base system from the very beginning? FreeBSD already
had precedent when a *ready* code framework was rejected be some FreeBSD
users' enemy, leaving FreeBSD users to suck with absolutely *no*
alternative (yep, sensors) - as ridiculous as if it was to say "current
BSD firewalls are inferior to Linux so we'll better sit without that
bad code (and firewall) AT ALL". Yes, the situation in networking for
us was for many years - and still is - exactly so.

This is exactly the way how to loose market competition and die - just
don't try to innovate and do something better than competitor; then you
find yourself porting compatibility layers after decades of rot, like
Netlink or Linuxulator ABI, in a try to at least hobble with a cane
instead of lying in a coma.
Post by Rob Wing
you can make anything look good on paper but the devil is in the
details...which there are plenty of
So do you have to say something constructive on the real subject? Or
even bikesheds are in short supply now?
Post by Rob Wing
On Tuesday, September 10, 2024, Vadim Goncharov
Post by Vadim Goncharov
On Tue, 10 Sep 2024 15:58:25 +0100
On 10 Sep 2024, at 14:44, Vadim Goncharov
Post by Vadim Goncharov
I am not an experience assembler user and don't understand how
Spectre works - that's why I've written RFC letter even before
spec finished - but isn't that (Spectre) an x86-specific thing?
BPF64 has more registers and primarily target RISC
architectures if we're speaking of JIT.
No, speculative execution vulnerabilities are present in any CPUs
that do speculative execution that does not have explicit
mitigations against them (i.e. all that have shipped now). Cache
side channels are present in any system with caches and do not
have explicit mitigations (i.e. all that have shipped so far).
Mitigations around these things are an active research area, but
so far everything that’s been proposed has a performance hit and
several of them were broken before anyone even implemented them
outside a simulator.
Post by Vadim Goncharov
And BPF64 is meant as backwards-compatible extension of existing
BPF, that is, it has bytecode interpreter (for(;;) switch/case)
as primary form and JIT only then - thus e.g. JIT can be
disabled for non-root users in case of doubt. eBPF can't do
this - it always exists in native machine code form at
execution, bytecode is only for verifier stage.
This has absolutely no impact on cache side channels. The JIT
makes some attacks harder but prime-and-probe attacks are still
possible.
Wait, do you want to say that problem is not in JIT, that is, that
current BPF (e.g. tcpdump) present in the kernel - are also
vulnerable? Also, let's classify vulnerabilities. Is speculative
execution vulnerability the same as cache side channels? In any
case, what impact is? E.g. attacker could leak secrets, but *where*
would them leak? BPF typically returns one 32-bit number as a
verdict (often as just boolean), is it really attack vector? That
is, may be solution is just "don't give read access to BPF-writable
memory segments to untrusteds".
Next, if problem is with timing, then isn't that enough to just
restrict BPF code on having access to timers with resolution high
enough?
BPF can be loaded only by root, who can also load kernel modules
and map /dev/[k]mem, and FreeBSD does not protect the root <->
kernel boundary.
Wrong. It is possible for decades to do `chmod a+r /dev/bpf*` and
run tcpdump as non-root, which will load BPF code into kernel. Is
*that* also a vulnerability, and if so, why it was never reported?
Please read some of the (many) attacks on eBPF to better
understand the security landscape here. It’s a *very* hard
problem to solve.
Finally, the most big (in effort) question: suppose we limited to
trusted root user etc. so it's of no concern. Are there now any
objections/suggestions/comments on (rest of) BPF64 ?
--
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Vadim Goncharov
2024-09-12 00:26:14 UTC
Permalink
On Tue, 10 Sep 2024 16:55:15 -0800
Post by Rob Wing
On Tuesday, September 10, 2024, Vadim Goncharov
Post by Vadim Goncharov
What's the point to waste resources on writing thing that is known
to be not accepted to base system from the very beginning?
what's the point of talking about thing you're never going to
write/finish even if it was accepted?
Because - and I've written that from the beginning - wrong architecture
will cost too much if your code already exists, than if fixed before
that. So I've received worthy feedback describing problems; not that
were good solutions yet, though...
Post by Rob Wing
Or even bikesheds are in short supply now?
have you considered calling it eBPF++ or BPF128?
Well, first it was called fBPF as next letter from eBPF, and for 128 it
lacks 128 bit arithmetics. Then I realized that for some things there
will be different implementations in different kernels, e.g. for
atomic(9) operations, so better to call generic common thing neutral
BPF64 and e.g. fBPF be FreeBSD dialect, nBPF for NetBSD dialect...
Post by Rob Wing
at any rate, don't claim the sky is falling on the grounds that I
think your proposal is far fetched
Not you. FreeBSD already had precedent when already written and
committed code framework for device sensors was removed:
https://lists.freebsd.org/pipermail/cvs-src/2007-October/082398.html
and that happened by exactly the same person with similar tone (not you).

...well, ok, there were some really technical arguments in that case
e.g. about sysctl_add_oid() but that was the most technical of them,
all other being same arrogant rant.
Anyway, such cases are very demotivating from contributing.
Post by Rob Wing
if you think you've got a great idea and have a need for it, then
write it and use it - if other people adopt it, even better
all the best to your endeavors and don't let the naysayers hold you back
Well, what I really need is a technical help for areas I don't know, as
obviously I won't be able to write entire ecosystem alone.

For example, I don't know how many registers are available to a function
in a kernel on an ARM, MIPS and RISC-V. If I allocate too much, then
somebody will have trouble implementing JIT on such machine, as I don't
have such hardware. And e.g. https://en.wikipedia.org/wiki/MIPS_architecture
says 2 registers are for kernel - OK, and what if we are kernel itself? :-)
Do we need Thread Pointer of Global Pointer, or we can stash them to
stack? Etc.
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Vadim Goncharov
2024-09-10 13:09:15 UTC
Permalink
On Tue, 10 Sep 2024 12:24:07 +0000
Post by Poul-Henning Kamp
--------
Post by Vadim Goncharov
It's easy for your Lua code (or whatever) code to hang kernel by
infinite loop. Or crash it by access on arbitrary pointer.
Lua has pointers now ?
It's implementation has. Do you have mathematical verifier of such
loaded bytecode proving it's C interpreter will have no side effects
during it's running?
Post by Poul-Henning Kamp
Post by Vadim Goncharov
Your "counter proposal" was essentially available for all these
decades in form "oh, just write KLD in C instead of that limited
tcpdump".
You're yelling at the guy who implemented a (very fast!) firewall
where the rules were compiled to C code in a KLD.
That's exactly the way which must be avoided. See 5.2 of
https://www.usenix.org/legacy/events/bsdcon02/full_papers/lidl/lidl.pdf
Post by Poul-Henning Kamp
Post by Vadim Goncharov
Post by Poul-Henning Kamp
If we are going to reinvent "Channel Programs" 67 years after IBM
came up with them for their 709 vacuum tube computer, at the very
least we should use a sensible language syntax.
Don't know what that is, quick googling […]
Well, you probably should do some more research then, because
unawareness of history is /the/ major cause of pointlessly repeating
mistakes.
You're either trolling or completely misunderstand the problem domain.

<<Although the 709, one of the last of the vacuum-tube
computers announced by IBM, had a rather short tech-
nological life, it made an important contribution to con-
current CPU and 1/0 operations by the introduction of
I/O channels [21]. These channels actedindividually as I/O
processors with a specialized instruction repertoire. Each
channel could address and accessmemory to store orre-
trieve data quiteindependently of theCPUprogram.
Coordinationbetween the CPUandchannelprograms
wasachieved by CPU instructions for (1) conditional
branching depending on whether a channel was in opera-
tion, (2) delaying the CPU until completion of a channel
command, followed by loading of channel control regis-
ters, and (3) storing the channel control register contents
in a specified memory location.
Post by Poul-Henning Kamp
Post by Vadim Goncharov
(c) https://www.ece.ucdavis.edu/~vojin/CLASSES/EEC272/S2005/Papers/IBM-Architecture-Bashe_sep81.pdf
This has nothing to do with BPF at all. Go and read original papers on
kernel filters and why they're *such* restricted, e.g. Van Jacobson's
paper on BPF/tcpdump, aforementitioned paper on BSD/OS's IPFW (esp.
section 5.7 on loops), etc.
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Poul-Henning Kamp
2024-09-10 14:32:56 UTC
Permalink
--------
Post by Vadim Goncharov
On Tue, 10 Sep 2024 12:24:07 +0000
Post by Poul-Henning Kamp
Lua has pointers now ?
It's implementation has.
As does (e)BPF's implementation.
Post by Vadim Goncharov
Post by Poul-Henning Kamp
You're yelling at the guy who implemented a (very fast!) firewall
where the rules were compiled to C code in a KLD.
That's exactly the way which must be avoided. See 5.2 of
https://www.usenix.org/legacy/events/bsdcon02/full_papers/lidl/lidl.pdf
I didn't agree with them then, and I dont agree with them now :-)

In my implementation, the ipfw(8) worked *precisely* the same as
it always did, just a little slower because it had to run the
C-compiler.

Later I used the same trick in Varnish, where the "VCL" configuration
language is compiled into a shared library, a major performance gain.
Post by Vadim Goncharov
You're either trolling or completely misunderstand the problem domain.
[wiki quote]
This has nothing to do with BPF at all. Go and read original papers on
kernel filters and why they're *such* restricted, e.g. Van Jacobson's
paper on BPF/tcpdump, aforementitioned paper on BSD/OS's IPFW (esp.
section 5.7 on loops), etc.
Yes, I read those papers when they were fresh, and I still think I
know more about this problem domain than you will ever have to
learn.

I will admit that I have not run channel programs on a 709 myself,
I only got into that game on a 4381.

I also wrote my own prototype eBPF around 1996-97, in an attempt
to deal with some obscure protocols, but I gave up on it, precisely
because BPF was a "toy" language so it couldn't do what I needed.

There are two fundamental questions:

A) How powerful do you want the downloaded bytecode to be ?

B) What syntax to you express it in ?

There are basically two possible answers to A.

Either the downloaded code is "real", which means it can include
loops, function calls etc. or it is a "toy" which relies on
Brinch-Hansen's "all arrows point to the right" argument to prove
that it will always terminate.

Obviously there is a lot of stuff you cannot do with a "toy",
but it is a valid trade-off.

VJ had no trouble making BPF a "toy": He lost no functionality,
and it made it easier/possible to convince people that this would
not cause the same problems as IBM channel programs did.

I made VCL a "toy", also because no functionality was lost, and
it eliminated a very obvious way for webmasters, not the worlds best
programmers to begin with, to shoot their own feet.

Personally I think it should be a "securelevel" like setting if
FreeBSD's channel programs should be allowed to loop: We supply
code, not policy.

But that question is /entirely/ separate from the second question.

The answer to that is that you can write them in /any/ programming
language you want, as long as the interpreter for the resulting
(byte-)code an spot attempts to jump backwards, and refuse to
do so, if so configured.

And that is why I say: If we're going to do this, let us do
it with Lua: It's already in our tree and it will do the
job nicely.

After all, we dont want to make another mess like ACPI, do we ?

Poul-Henning
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
***@FreeBSD.ORG | TCP/IP since RFC 956
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Poul-Henning Kamp
2024-09-10 13:35:11 UTC
Permalink
Post by David Chisnall
The thing I would like to see for our current use of semi-trusted Lua in
the kernel (ZFS channel programs) is a way of exposing them (under
/dev/something) as file descriptors and modifying the ioctls that run
them to take a file descriptor argument. I would like to separate the
- Load a channel program.
- Run a channel program.
In the post-Spectre world, the former remains a privileged operation.
Even though Linux pretends it isn't, allowing arbitrary (even
arbitrary constrained) code to run in the kernel's address space
is a problem. Invoking such code; however, should follow the same rules
as everything else. A trusted entity should be able to load a pile of
Lua / eBPF / BPF64 / whatever programs into the kernel and then set up
permissions so that sandboxed programs (and jails) can use a defined
subset of them.
That would be a great way to do it.
--
Poul-Henning Kamp | UNIX since Zilog Zeus 3.20
***@FreeBSD.ORG | TCP/IP since RFC 956
FreeBSD committer | BSD since 4.3-tahoe
Never attribute to malice what can adequately be explained by incompetence.


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Vadim Goncharov
2024-09-10 13:44:47 UTC
Permalink
On Tue, 10 Sep 2024 13:59:02 +0100
Post by Vadim Goncharov
It's easy for your Lua code (or whatever) code to hang kernel by
infinite loop. Or crash it by access on arbitrary pointer. That's
why original BPF has no backward jumps and memory access, and eBPF's
nightmare verifier walks all code paths and check pointers.
I’m not convinced by the second: Lua has a GC’d heap, you’d need to
expose FFI things to it that did unsafe things, and that’s equally a
problem for eBPF.
Not quite. For eBPF (and BPF64) there must be not just FFI but special
wrappers or even written from scratch functions keeping in mind they
work for restricted environment. Lua, of course, does not have such
thing - it will be needed to reimplement standard library.
The first is not a problem. The Lua interpreter has a bytecode
limit. You can define a bounded number of bytecodes that it will
execute. The problem comes from the standard library. Things like
string.gmatch can have high-order polynomial complexity and so it’s
possible for a Lua program that executes a small number of bytecodes
to create a string that takes a vast amount of time to match on.
Again, this is also a problem for eBPF if you expose a similar
function, the solution is to not expose functions with large
data-dependent runtimes to untrusted script.
In BPF64 some safety belts are supposed - e.g. on CALL/RET time is
checked, and if exceeded, program is marked unsafe and disabled.
More generally, there are a lot of problems with interpreting or
JITing untrusted code in the kernel in *any* runtime. Speculative
execution makes it easy to use these as primitives to leak kernel
secrets, either via timing of the programs themselves, using the JIT
to generate gadgets, or by leaking data via cache priming.
Both eBPF and Lua have these problems.
[...]
- Run a channel program.
In the post-Spectre world, the former remains a privileged operation.
Even though Linux pretends it isn’t, allowing arbitrary (even
arbitrary constrained) code to run in the kernel’s address space is a
problem. Invoking such code; however, should follow the same rules
as everything else. A trusted entity should be able to load a pile
of Lua / eBPF / BPF64 / whatever programs into the kernel and then
set up permissions so that sandboxed programs (and jails) can use a
defined subset of them.
I am not an experience assembler user and don't understand how Spectre
works - that's why I've written RFC letter even before spec finished - but
isn't that (Spectre) an x86-specific thing? BPF64 has more registers
and primarily target RISC architectures if we're speaking of JIT.

For BPF64 I've did separate stack as register window exactly to
mitigate ROP and it's gadgets.

And BPF64 is meant as backwards-compatible extension of existing BPF,
that is, it has bytecode interpreter (for(;;) switch/case) as primary
form and JIT only then - thus e.g. JIT can be disabled for non-root
users in case of doubt. eBPF can't do this - it always exists in native
machine code form at execution, bytecode is only for verifier stage.

^^ that's fallback if you say "safe JIT is impossible", but may be you
have advices on how to do architecture to still do it safe? As BPF64
looks doable improvement for us in much lower resource investment than
even to *porting* eBPF to *BSD.
The thing I would like to see for our current use of semi-trusted Lua
in the kernel (ZFS channel programs) is a way of exposing them (under
/dev/something) as file descriptors and modifying the ioctls that run
them to take a file descriptor argument. I would like to separate
- Load a channel program.
Didn't hear about, looked at the zfs-program(8) and see no reason why
these are called "channel" programs (just to please some old farts?)
and even reason for them to run in kernel, for same userland-utilities-achievable
things, seems doubtful.
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
David Chisnall
2024-09-10 14:58:25 UTC
Permalink
Post by Vadim Goncharov
I am not an experience assembler user and don't understand how Spectre
works - that's why I've written RFC letter even before spec finished - but
isn't that (Spectre) an x86-specific thing? BPF64 has more registers
and primarily target RISC architectures if we're speaking of JIT.
No, speculative execution vulnerabilities are present in any CPUs that do speculative execution that does not have explicit mitigations against them (i.e. all that have shipped now). Cache side channels are present in any system with caches and do not have explicit mitigations (i.e. all that have shipped so far).

Mitigations around these things are an active research area, but so far everything that’s been proposed has a performance hit and several of them were broken before anyone even implemented them outside a simulator.
Post by Vadim Goncharov
And BPF64 is meant as backwards-compatible extension of existing BPF,
that is, it has bytecode interpreter (for(;;) switch/case) as primary
form and JIT only then - thus e.g. JIT can be disabled for non-root
users in case of doubt. eBPF can't do this - it always exists in native
machine code form at execution, bytecode is only for verifier stage.
This has absolutely no impact on cache side channels. The JIT makes some attacks harder but prime-and-probe attacks are still possible.

BPF can be loaded only by root, who can also load kernel modules and map /dev/[k]mem, and FreeBSD does not protect the root <-> kernel boundary.

Please read some of the (many) attacks on eBPF to better understand the security landscape here. It’s a *very* hard problem to solve.

David
Vadim Goncharov
2024-09-11 09:05:18 UTC
Permalink
On Wed, 11 Sep 2024 10:14:44 +0800
Post by Vadim Goncharov
Post by David Chisnall
BPF can be loaded only by root, who can also load kernel modules
and map /dev/[k]mem, and FreeBSD does not protect the root <->
kernel boundary.
Wrong. It is possible for decades to do `chmod a+r /dev/bpf*` and
run tcpdump as non-root, which will load BPF code into kernel. Is
*that* also a vulnerability, and if so, why it was never reported?
This is equivalent to chmod a+w /dev/mem.
Unwise configuration decisions are not vulnerabilities.
But then a possibility to give this to non-root is. And many things are
considered vulnerabilitites even if they are only available to root -
for example, when root can be tricked into running malicious code etc.
(unconscious) actions without direct intention.

Equivalency of classic BPF to writable /dev/mem is too loud and
controversial statement. Demonstrate how it can be done on stock
FreeBSD 13 with /dev/bpf available to attacker (e.g. `sudo tcpdump`
allowed).
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
David Chisnall
2024-09-11 11:21:09 UTC
Permalink
Post by Vadim Goncharov
But then a possibility to give this to non-root is. And many things are
considered vulnerabilitites even if they are only available to root -
for example, when root can be tricked into running malicious code etc.
(unconscious) actions without direct intention.
When the root user intentionality changes some thin from a secure default to an insecure setting, it is not a security vulnerability in the system that shipped the safe defaults.
Post by Vadim Goncharov
Equivalency of classic BPF to writable /dev/mem is too loud and
controversial statement. Demonstrate how it can be done on stock
FreeBSD 13 with /dev/bpf available to attacker (e.g. `sudo tcpdump`
allowed).
Two things to unpick here. First:

Demanding a proof of concept before you accept that something is a vulnerability is how you build insecure systems. Ask the Matrix team how well that attitude has worked for them in the last few weeks. You build secure systems by defining a threat model and then evaluating primitives against that threat model, not by throwing together a bunch of primitives and saying ‘well, *I* can’t assemble them into an exploit and so no one can’.

Second, there are documented attacks on eBPF that give the equivalent of *read* access to /dev/mem. This is why BPF is restricted to root. We have a threat model. The threat model says that we do not need to ensure that BPF cannot leak kernel data indirectly because only the user who has the ability to leak kernel data directly can use it and this user has a simpler way of achieving the same result. If you allow non-root users to run code (native or against any virtual machine) then you are changing the threat model. You *must* prevent users from leaking kernel data that they could not leak via existing mechanisms.

The two most common attacks using eBPF are generally in the following two categories:

- Use eBPF to mount a speculative execution attack on the kernel. Please read up on what these can do. No one should be building a thing that runs code in the kernel without understanding speculative, cache, and timing side channels.
- Use eBPF to build a set of gadgets that you can then use to go from one memory-safety bug in the kernel to arbitrary-code execution.

This is the threat landscape in which something in the same space as eBPF must exist. A proposed design should *start* with an explanation of how it mitigates both of these categories of attack.

David



--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Vadim Goncharov
2024-09-11 23:57:17 UTC
Permalink
On Wed, 11 Sep 2024 12:21:09 +0100
Post by David Chisnall
Post by Vadim Goncharov
But then a possibility to give this to non-root is. And many things
are considered vulnerabilitites even if they are only available to
root - for example, when root can be tricked into running malicious
code etc. (unconscious) actions without direct intention.
When the root user intentionality changes some thin from a secure
default to an insecure setting, it is not a security vulnerability in
the system that shipped the safe defaults.
This is just not true. See, for example, FreeBSD-SA-17:06.openssh for
vulnerability disabled by default, and workaround proposed to return
to default (disabled) state.
Post by David Chisnall
Post by Vadim Goncharov
Equivalency of classic BPF to writable /dev/mem is too loud and
controversial statement. Demonstrate how it can be done on stock
FreeBSD 13 with /dev/bpf available to attacker (e.g. `sudo tcpdump`
allowed).
Demanding a proof of concept before you accept that something is a
vulnerability is how you build insecure systems. Ask the Matrix team
how well that attitude has worked for them in the last few weeks. You
build secure systems by defining a threat model and then evaluating
primitives against that threat model, not by throwing together a
bunch of primitives and saying ‘well, *I* can’t assemble them into an
exploit and so no one can’.
Second, there are documented attacks on eBPF that give the equivalent
of *read* access to /dev/mem. This is why BPF is restricted to root.
Stop. Just stop, and re-read carefully. You (and perhaps Philip)
confusing two things: BPF and eBPF (and BPF64 third), all completely
different beasts. Last two letters in this thread, I was talking about
classic BPF existing in *BSD for decades (on FreeBSD allowed to have
permissions on dev/bpf*). So you assert that THIS classic BPF also
vulnerable to aforementioned attacks, and thus SA must be issued, just
like that FreeBSD-SA-17:06.openssh, with a fix (at least preventing
changing default permissions) of hole existing for *decades*. This is
too strong assertion to be accepted without proofs, and as I can deduce
from your other words and readings about Spectre (see below), this
statement is not true (classic /dev/bpf is not vulnerable).
Post by David Chisnall
We have a threat model. The threat model says that we do not need to
ensure that BPF cannot leak kernel data indirectly because only the
user who has the ability to leak kernel data directly can use it and
this user has a simpler way of achieving the same result. If you
allow non-root users to run code (native or against any virtual
machine) then you are changing the threat model. You *must* prevent
users from leaking kernel data that they could not leak via existing
mechanisms.
- Use eBPF to mount a speculative execution attack on the kernel.
Please read up on what these can do. No one should be building a
thing that runs code in the kernel without understanding speculative,
cache, and timing side channels.
This is the threat landscape in which something in the same space as
eBPF must exist. A proposed design should *start* with an explanation
of how it mitigates both of these categories of attack.
Again, you are talking about eBPF here, not classic BPF. So far Spectre
was mentioned as example of those speculative, cache, and timing side
channels: https://en.wikipedia.org/wiki/Spectre_(security_vulnerability)
refers to mitigations e.g. in Firefox -
https://www.mozilla.org/en-US/security/advisories/mfsa2018-01/
with key phrase

"The precision of performance.now() has been reduced from 5μs to 20μs,"

So to prevent this class of attacks you need to deprive untrusted code
from (precise) timers. And if we then go eBPF sources, we see at
https://elixir.bootlin.com/linux/v6.10/source/include/uapi/linux/bpf.h#L1884
* u64 bpf_ktime_get_ns(void)
* Description
* Return the time elapsed since system boot, in nanoseconds.
* Does not include time the system was suspended.
* See: **clock_gettime**\ (**CLOCK_MONOTONIC**)

This is because eBPF is used in Linux as one-catch-all for tracing and
profiling - they do not have DTrace. And we have. And BPF don't need to
be DTrace and don't need timers.

Thus, we can conclude, your eBPF assertion is simply not applicable to
*BSD classic BPF, and consequently, to current state of BPF64 which
don't include any timers or time sources available to user code at all.
Post by David Chisnall
- Use eBPF to build a set of gadgets that you can then use to go
from one memory-safety bug in the kernel to arbitrary-code execution.
This requires further explanations (including to ensure we're not
mixing things again). As far as I can see currently, this is also not
applicable to BPF64 due to lack of pointers.
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
David Chisnall
2024-09-12 11:04:35 UTC
Permalink
Post by Vadim Goncharov
This is just not true. See, for example, FreeBSD-SA-17:06.openssh for
vulnerability disabled by default, and workaround proposed to return
to default (disabled) state.
No, this was changing from one supported expected-secure setting to another. If you make a device directly usable by non-root users, you are expected to understand the security implications.
Post by Vadim Goncharov
Stop. Just stop, and re-read carefully.
I have read carefully. I am not sure at this point whether you are intentionally failing to engage in good faith or if you simply do not understand the security landscape that you are operating in and have no interest in learning. Either way, it is not productive to keep having this conversation so this will be my last comment in this thread.
Post by Vadim Goncharov
You (and perhaps Philip)
confusing two things: BPF and eBPF (and BPF64 third), all completely
different beasts.
They are all mechanisms for running semi-trusted / untrusted code in the kernel.
Post by Vadim Goncharov
Last two letters in this thread, I was talking about
classic BPF existing in *BSD for decades (on FreeBSD allowed to have
permissions on dev/bpf*).
FreeBSD allows you to change the permissions on anything in /dev/. It is up to you to understand the security implications of doing this. Allowing non-root access to /dev/bpf has security implications. I do it for my user on a couple of single-user FreeBSD dev boxes, because I also have root on these systems and so anything WireShark can do on my behalf, I can also do via su. There is no security issue because my threat model *for this system* is such that I can accept a weaker posture than the default. There are legitimate reasons for broadening the permissions on these systems.
Post by Vadim Goncharov
So you assert that THIS classic BPF also
vulnerable to aforementioned attacks, and thus SA must be issued, just
like that FreeBSD-SA-17:06.openssh, with a fix (at least preventing
changing default permissions) of hole existing for *decades*.
No, for the same reason that there’s no security advisory if you `chmod +r /dev/mem`. There’s a reason that both /dev/mem and /dev/bpf are restricted to root by default. Anyone who relaxes these permissions must understand what they’re doing and have a threat model that can justify why it’s acceptable.

By analogy with FreeBSD-SA-17:06.openssh: this SA applied where password login was enabled. Enabling password authentication weakens the security of OpenSSH and so is not done by default, but that was not the problem that merited the SA. The SA was issued because it had the additional effect of allowing remote attackers to mount a denial of service attack. We would not issue an OpenSSH SA saying ‘enabling password authentication weakens security because people can log in with passwords, which are less secure than SSH keys’. The expectation is that anyone changing this setting knows what they’re doing. If it is not a problem for their use case, they can do it. Precisely the same logic applies to allowing non-root access to /dev/bpf or /dev/mem.
Post by Vadim Goncharov
This is
too strong assertion to be accepted without proofs, and as I can deduce
from your other words and readings about Spectre (see below), this
statement is not true (classic /dev/bpf is not vulnerable).
I have not built a PoC, but I would fully expect that it’s possible to build an attack that first primes the cache and trains the branch predictor and then runs a crafted BPF program that has an out-of-bounds read (which executes only in speculation) to leak kernel memory (including contents of the direct map, so anything owned by another process on the same system), and then inspects the contents of the cache to see the value that was observed in speculation. All of the necessary primitives are there.

If you are designing a system that expects non-root users to be able to run code in the kernel, the onus is on you to explain why it is safe. The default assumption must be that it is unsafe.

David
Gavin D. Howard
2024-09-10 14:41:20 UTC
Permalink
Hello,

New user here, not a contributor.
Post by Vadim Goncharov
Ensuring kernel stability? Just don't allow arbitrary pointers, like original BPF.
Guaranteed termination time? It's possible if you place some restrictions. For
example, don't allow backward jumps but allow function calls - in case of
stack overflow, terminate program. Really need backward jumps? Let's analyze
for what purpose. You'll find these are needed for loops on packet contents.
Solve it but supporting loops in "hardware"-controlled loops, which can't be
infinite.
If I understand Turing-completeness correctly, the "no backward jumps
but allow recursion and quit on stack overflow" is exactly equivalent to
having non-infinite loops.

I'm not entirely sure, but I think the lack of backwards jumps would be
"simple" to check on LLVM IR: just make sure that a basic block does not
jump, directly or indirectly, to a basic block that dominates it. [1]

[1]: https://en.wikipedia.org/wiki/Dominator_(graph_theory)

And then the stack overflow mechanic would be an entirely runtime check,
which is safer than pure static checking.

But the good thing about this is that FreeBSD could use LLVM IR as the
BPF64 language, which means any language that compiles to LLVM is a
possible target.

As for restricting access, I think it would be possible to check the
instructions in LLVM IR for any unsafe instructions or calls to
restricted functions.

The downsides:

* Someone would need to write an LLVM analyze pass or whatever they're
called. Maybe more than one.
* The kernel would need the ability to compile LLVM IR, making LLVM part
of the Ring 0 domain.
* Either that, or someone builds an LLVM-to-bytecode translator.
* But the analysis pass(es) must still live in the kernel.
* There would need to be tutorials or some docs on how to write whatever
language so that backwards jumps are avoided.

Please take my words with a full dose of salt; I'm not an expert on this
or on FreeBSD goals.

Gavin Howard


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Gavin D. Howard
2024-09-12 06:29:38 UTC
Permalink
Post by Vadim Goncharov
Post by Gavin D. Howard
If I understand Turing-completeness correctly, the "no backward jumps
but allow recursion and quit on stack overflow" is exactly equivalent
to having non-infinite loops.
Sure, but then look at practical usefulness: suppose you have stack of
32 frames (current limit of eBPF and BPF64). Then you can have only 31
iterations on a loop, loosing ability to call more functions from loop
body.
That is true.

However, I wonder if everyone is going at this the wrong way. More
specifically, I wonder if we are targeting the entirely wrong level.
Maybe verifying bytecode or some other low-level code form is just too
hard. What if it were easier just to provide a higher level language
that had enough restrictions to be just barely not Turing-complete.

To test that idea, I did a quick experiment.

I have been working on a language called Yao for the past three years.
One feature I planned for the future was the ability to restrict what
packages and keywords are available at compile time. I had already
put in the plumbing, but I just hadn't implemented it.

But I decided to quickly implement it as an experiment.

First, I needed a stack limit:

https://git.yzena.com/Yzena/Yc/commit/99c822bf7b

Now, you can run this:

```
$ ./release/yc yao --max-stack-depth=32 <script>
```

and you get the same max stack depth as eBPF.

Next, restricting keywords. One unique thing about Yao is that *every*
keyword is imported like you would import functions, even standard ones
like `if` and `while`. This means that if a keyword is not allowed, I
can just skip importing it, and it's like it doesn't even exist.

So I built a way to skip importing the `while` keyword and any other
keyword that would make the language Turing-complete. Crucially, though,
it still includes a `foreach` loop, so backwards jumps are still
possible.

A script with a `while` loop is `tools/rig_slam.yao` in the same repo.
If you run:

```
$ make # This bootstraps the repo.
$ ./release/yc yao tools/rig_slam.yao
```

you will get a panic when it tries to parse the `while` loop because I
haven't implemented the parsing:

```
Panic: Unimplemented
Source: /home/gavin/Yzena/Code/yc-git/yc/src/yao/keywords.c:2310
Function: yao_parse_while()
```

But if you run this:

```
$ ./release/yc yao --max-stack-depth=32 --lang-mode=iterative \
tools/rig_slam.yao
```

you get a compile error, and it doesn't even try to parse the `while`:

```
yc: tools/rig_slam.yao[145:2]
Parse error: Incomplete variable declaration for name: while

yc: tools/rig_slam.yao[145:8]
Invalid token: Expected semicolon (';')
```

(You also get a different panic after that because Yao has bugs.)

Anyway, essentially, the "iterative" language mode with a max stack
depth makes Yao non-Turing-complete, but with a way to loop.

You can try that with `tools/format.yao`, which has a `foreach` loop:

```
$ ./release/yc yao --max-stack-depth=32 --lang-mode=iterative \
tools/format.yao
```

and it still works.

I'm not saying Yao as an eBPF replacement is a good idea; it's not. But
I think this demonstrates that a simple high-level language with a
simple compiler and a simple VM might be a viable method of implementing
an eBPF-like thing without a complex verifier.

Yes, the compiler and VM would need to be in the kernel, but that might
already be the case with the JIT in Linux.

Anyway, my point is that before FreeBSD accepts BPF64, it might be a
good idea to sit down and consider all of the options, brainstorm ideas
together, and make an excellent design.

And it could very well be that BPF64 *is* the best design! I don't know;
I'm not a kernel guy, nor am I an expert compiler guy.
Post by Vadim Goncharov
Post by Gavin D. Howard
* But the analysis pass(es) must still live in the kernel.
* There would need to be tutorials or some docs on how to write
whatever language so that backwards jumps are avoided.
So BPF64 took simplicity pass: while you have tutorials etc. it's still
very hard to write (non-toy) code that passes verifier. I think a
language where you do not need backward jumps but have usable
constructs (so you just can't write bad code), even BAW, is a better
way to go than try to train people to fight with unnecessary Cerber.
Yes, I think you are right on this, which IMO just points to a
high-level language. Such a language can have whatever constructs are
safe, but by its very nature, it will be restricted such that dangerous
code is impossible.

It would also be easier to write code that passes the "verifier" if the
verifier is actually the compiler.

Anyway, I hope I don't sound too critical; I don't have the chops to
judge BPF64. Plus, I can tell you put in a lot of work.

Gavin Howard


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Kevin P. Neal
2024-10-14 01:26:57 UTC
Permalink
Post by Gavin D. Howard
But the good thing about this is that FreeBSD could use LLVM IR as the
BPF64 language, which means any language that compiles to LLVM is a
possible target.
Please don't do this.

The LLVM IR language is a moving target. IR that works in one version is
not guaranteed to work in prior versions. There is an upgrade step where
it tries to read in older IR, but writing out older IR is a problem. It
can be solved, I think the DirectX LLVM backend ("DXIL") does this, but I
still suggest you not do this.
Post by Gavin D. Howard
As for restricting access, I think it would be possible to check the
instructions in LLVM IR for any unsafe instructions or calls to
restricted functions.
* Someone would need to write an LLVM analyze pass or whatever they're
called. Maybe more than one.
Close. "Analysis pass".
Post by Gavin D. Howard
* The kernel would need the ability to compile LLVM IR, making LLVM part
of the Ring 0 domain.
* Either that, or someone builds an LLVM-to-bytecode translator.
* But the analysis pass(es) must still live in the kernel.
LLVM is huge. Really huge. A codebase that large has no business being in
the kernel.
--
Kevin P. Neal http://www.pobox.com/~kpn/
"14. Re-reading No. 13, I realize that it's quite possible I'm losing my
mind. I'm glad that for the most part I'm not aware it's happening."
-- from "20 things I'm thankful for": Fortune, Nov 29, 2004, page 230


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Cy Schubert
2024-10-14 02:49:12 UTC
Permalink
Post by Kevin P. Neal
Post by Gavin D. Howard
But the good thing about this is that FreeBSD could use LLVM IR as the
BPF64 language, which means any language that compiles to LLVM is a
possible target.
Please don't do this.
The LLVM IR language is a moving target. IR that works in one version is
not guaranteed to work in prior versions. There is an upgrade step where
it tries to read in older IR, but writing out older IR is a problem. It
can be solved, I think the DirectX LLVM backend ("DXIL") does this, but I
still suggest you not do this.
Post by Gavin D. Howard
As for restricting access, I think it would be possible to check the
instructions in LLVM IR for any unsafe instructions or calls to
restricted functions.
* Someone would need to write an LLVM analyze pass or whatever they're
called. Maybe more than one.
Close. "Analysis pass".
Post by Gavin D. Howard
* The kernel would need the ability to compile LLVM IR, making LLVM part
of the Ring 0 domain.
* Either that, or someone builds an LLVM-to-bytecode translator.
* But the analysis pass(es) must still live in the kernel.
LLVM is huge. Really huge. A codebase that large has no business being in
the kernel.
An interpreter in the kernel. What could possibly go wrong with that?
--
Cheers,
Cy Schubert <***@cschubert.com>
FreeBSD UNIX: <***@FreeBSD.org> Web: https://FreeBSD.org
NTP: <***@nwtime.org> Web: https://nwtime.org

e^(i*pi)+1=0




--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
David Chisnall
2024-10-14 07:33:33 UTC
Permalink
Post by Kevin P. Neal
It
can be solved, I think the DirectX LLVM backend ("DXIL") does this, but I
still suggest you not do this.
NaCl and SPIR made this mistake first. WebAssembly and SPIR-V learned the lesson.
Post by Kevin P. Neal
LLVM is huge. Really huge. A codebase that large has no business being in
the kernel.
Many years ago, I wrote a proof of concept BPF to LLVM IR compiler. The idea was that a trusted userspace component could do the BPF compilation and load binary code into the kernel. BPF would still be BPF and so have the same guarantees, but compiling it would be faster (on average, each BPF bytecode was slightly more than one x86 instruction after LLVM optimisations had run). LLVM was still in the TCB though, even in userspace. I didn’t peruse it because LLVM is *not* safe in the presence of untrusted inputs.

More generally, the LLVM IR model is similar to C. It allows arbitrary pointer casts and arbitrary pointer arithmetic. It is not a good starting point for anything that you want to analyse for security. LLVM analyses take advantage of undefined behaviour. An in-bounds address calculation instruction is an assertion from the front end that the result will be in bounds. Optimisations are free to rely on this, even when they can’t prove it, because it is undefined behaviour to claim something is in bounds when it is not. The same is true of a lot of other properties on the IR. Many are not computable to recover post facto, they rely on translation from a higher-level language that enforces the properties by construction.

David



--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Vadim Goncharov
2024-09-10 15:17:11 UTC
Permalink
On Tue, 10 Sep 2024 14:41:20 +0000
Post by Gavin D. Howard
Hello,
New user here, not a contributor.
Post by Vadim Goncharov
Ensuring kernel stability? Just don't allow arbitrary pointers,
like original BPF. Guaranteed termination time? It's possible if
you place some restrictions. For example, don't allow backward
jumps but allow function calls - in case of stack overflow,
terminate program. Really need backward jumps? Let's analyze for
what purpose. You'll find these are needed for loops on packet
contents. Solve it but supporting loops in "hardware"-controlled
loops, which can't be infinite.
If I understand Turing-completeness correctly, the "no backward jumps
but allow recursion and quit on stack overflow" is exactly equivalent
to having non-infinite loops.
Sure, but then look at practical usefulness: suppose you have stack of
32 frames (current limit of eBPF and BPF64). Then you can have only 31
iterations on a loop, loosing ability to call more functions from loop
body.
Post by Gavin D. Howard
I'm not entirely sure, but I think the lack of backwards jumps would
be "simple" to check on LLVM IR: just make sure that a basic block
does not jump, directly or indirectly, to a basic block that
dominates it. [1]
[1]: https://en.wikipedia.org/wiki/Dominator_(graph_theory)
And then the stack overflow mechanic would be an entirely runtime
check, which is safer than pure static checking.
But the good thing about this is that FreeBSD could use LLVM IR as the
BPF64 language, which means any language that compiles to LLVM is a
possible target.
As for restricting access, I think it would be possible to check the
instructions in LLVM IR for any unsafe instructions or calls to
restricted functions.
* Someone would need to write an LLVM analyze pass or whatever they're
called. Maybe more than one.
* The kernel would need the ability to compile LLVM IR, making LLVM
part of the Ring 0 domain.
* Either that, or someone builds an LLVM-to-bytecode
translator.
Well, using LLVM were supposed for higher-level languages when
bytecode is no longer experimental, utilizing full power of optimizer,
but for direct using... let's see how they use it in Linux currently:

1) you write .c code, relatively low-level/restricted, with eBPF .h-s
2) clang turns .c into LLVM IR file (yes, this step is separate, may be
things has changed since then, but at least it was so)
3) file with LLVM IR turned to eBPF bytecode in ELF file
4) ELF .o loaded by ip(8) or specialized loader into kernel
5) verifier checks it and most probably will return error to you :)
6) bytecode is JIT-compiled in kernel and then may be run

Linux people are in mood "let's throw more man-months instead of
thinking of better design", eBPF infrastructure consists of hundreds of
thousandls lines of code, but seems that utilizing LLVM IR directly
required too much resources even from them so was rejected.
Post by Gavin D. Howard
* But the analysis pass(es) must still live in the kernel.
* There would need to be tutorials or some docs on how to write
whatever language so that backwards jumps are avoided.
So BPF64 took simplicity pass: while you have tutorials etc. it's still
very hard to write (non-toy) code that passes verifier. I think a
language where you do not need backward jumps but have usable
constructs (so you just can't write bad code), even BAW, is a better
way to go than try to train people to fight with unnecessary Cerber.
Post by Gavin D. Howard
Please take my words with a full dose of salt; I'm not an expert on
this or on FreeBSD goals.
BPF64 is not FreeBSD-only, you can see several non-FreeBSD mailing lists
here. It can be cross-platform and independent enough to be implemented
in e.g. network card or switch, for performance - having more registers
allows to achieve better results then eBPF for same goal.
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Vadim Goncharov
2024-10-10 22:23:53 UTC
Permalink
On Thu, 12 Sep 2024 06:29:38 +0000
Post by Gavin D. Howard
Post by Vadim Goncharov
Post by Gavin D. Howard
If I understand Turing-completeness correctly, the "no backward
jumps but allow recursion and quit on stack overflow" is exactly
equivalent to having non-infinite loops.
Sure, but then look at practical usefulness: suppose you have stack
of 32 frames (current limit of eBPF and BPF64). Then you can have
only 31 iterations on a loop, loosing ability to call more
functions from loop body.
That is true.
However, I wonder if everyone is going at this the wrong way. More
specifically, I wonder if we are targeting the entirely wrong level.
Maybe verifying bytecode or some other low-level code form is just too
hard. What if it were easier just to provide a higher level language
that had enough restrictions to be just barely not Turing-complete.
The problem is, then you need compiler of this language in target
environment, e.g. kernel, because you cannot trust that compiler's
output was not modified in a circumventing way.
Post by Gavin D. Howard
To test that idea, I did a quick experiment.
I have been working on a language called Yao for the past three years.
One feature I planned for the future was the ability to restrict what
packages and keywords are available at compile time. I had already
put in the plumbing, but I just hadn't implemented it.
But I decided to quickly implement it as an experiment.
https://git.yzena.com/Yzena/Yc/commit/99c822bf7b
```
$ ./release/yc yao --max-stack-depth=32 <script>
```
and you get the same max stack depth as eBPF.
Next, restricting keywords. One unique thing about Yao is that *every*
keyword is imported like you would import functions, even standard
ones like `if` and `while`. This means that if a keyword is not
allowed, I can just skip importing it, and it's like it doesn't even
exist.
So I built a way to skip importing the `while` keyword and any other
keyword that would make the language Turing-complete. Crucially,
though, it still includes a `foreach` loop, so backwards jumps are
still possible.
This reminds me of Tcl which has very little syntax, and everything in
"common syntax", like "if" and "while", is in standard library (and
thus defining new syntax constructs is possible to some extent).

However, Tcl, while attractive for task, suffers from problems:
1) "Everything is a string" is incompatible with high performance
2) like Lua, it is too general-pupose - not designed for such security
3) again like Lua and Rust, is maintained outside of *BSD src tree.
Post by Gavin D. Howard
A script with a `while` loop is `tools/rig_slam.yao` in the same repo.
```
$ make # This bootstraps the repo.
$ ./release/yc yao tools/rig_slam.yao
```
you will get a panic when it tries to parse the `while` loop because I
```
Panic: Unimplemented
yao_parse_while() ```
```
$ ./release/yc yao --max-stack-depth=32 --lang-mode=iterative \
tools/rig_slam.yao
```
```
yc: tools/rig_slam.yao[145:2]
Parse error: Incomplete variable declaration for name: while
yc: tools/rig_slam.yao[145:8]
Invalid token: Expected semicolon (';')
```
(You also get a different panic after that because Yao has bugs.)
Anyway, essentially, the "iterative" language mode with a max stack
depth makes Yao non-Turing-complete, but with a way to loop.
```
$ ./release/yc yao --max-stack-depth=32 --lang-mode=iterative \
tools/format.yao
```
and it still works.
I'm not saying Yao as an eBPF replacement is a good idea; it's not.
But I think this demonstrates that a simple high-level language with a
simple compiler and a simple VM might be a viable method of
implementing an eBPF-like thing without a complex verifier.
Probably interesting ideas to borrow, but I've tried to lurk in your
repository for 28 minutes and did not find any tutorial, introduction
or commented example of program longer than helloworld or fizzbuzz. For
BPF64, I've put relatively long example in both C and commented
translation to new language - as with learning new human languages,
first something in language already known to reader.
Post by Gavin D. Howard
Yes, the compiler and VM would need to be in the kernel, but that
might already be the case with the JIT in Linux.
No, they keep compiler outside of kernel. And JIT is relatively dumb to
translate prepared bytecode.

In fact, having only VM in kernel is consistent with using for
non-kernel environments, like network interface card hardware or
passing to remote server for remote procedure call - yes, these are
also as important targets as BSD kernel. And no hardware engineer in
sane mind will not design a CPU for a human-readable high-level
language, only bytecode VM - maximum that ever was in industry was for
still relatively low level languages, like Forth CPUs (even Lisp
machines did not run Lisp directly).
Post by Gavin D. Howard
Anyway, my point is that before FreeBSD accepts BPF64, it might be a
good idea to sit down and consider all of the options, brainstorm
ideas together, and make an excellent design.
So what are other options to consider&
Post by Gavin D. Howard
And it could very well be that BPF64 *is* the best design! I don't
know; I'm not a kernel guy, nor am I an expert compiler guy.
Post by Vadim Goncharov
Post by Gavin D. Howard
* But the analysis pass(es) must still live in the kernel.
* There would need to be tutorials or some docs on how to write
whatever language so that backwards jumps are avoided.
So BPF64 took simplicity pass: while you have tutorials etc. it's
still very hard to write (non-toy) code that passes verifier. I
think a language where you do not need backward jumps but have
usable constructs (so you just can't write bad code), even BAW, is
a better way to go than try to train people to fight with
unnecessary Cerber.
Yes, I think you are right on this, which IMO just points to a
high-level language. Such a language can have whatever constructs are
safe, but by its very nature, it will be restricted such that
dangerous code is impossible.
It would also be easier to write code that passes the "verifier" if
the verifier is actually the compiler.
This restricts to only one high-level language. Of course, it may look
like

INSERT INTO conntrack FROM current_packet(), time_now() + 60;
DELETE FROM conntrack WHERE expire < time_now();

but I'd better think about .NET-like to allow for different languages
better suited for different areas, not only network.
Post by Gavin D. Howard
judge BPF64. Plus, I can tell you put in a lot of work.
Thanks, you are first one who noticed this.
--
WBR, @nuclight


--
Posted automagically by a mail2news gateway at muc.de e.V.
Please direct questions, flames, donations, etc. to news-***@muc.de
Loading...