Thanks, so can you hear me?
Yes, cool.
So hi, I'm Victor.
I work for the Red Hat.
And yeah, as Kanton said,
I'd like to talk about handling strengths,
and give you programs.
Something that has been kind of clumsy over the years.
So I'll talk about these three kayfunks.
We've introduced it in the past year.
There are a couple of reasons I want to talk about this.
First of all, obviously, so that you know about them,
and you know how to use the, you know,
what benefits they can bring.
But the second is that while implementing these,
it turned out that doing somethings in the EBP of world
may be a bit harder than you would know from traditional
other programming domains.
So that's what I'm going to touch a bit as well.
So let's start with like motivation.
Why would you want handling strengths?
Well, the short answer is because strengths are everywhere.
When it comes to BPF, especially if you be a tracing,
but not not only tracing many hoops that you can attach
your BPF programs to allow you to access strengths,
such as functions, may have arguments, which are strings.
LSM hooks may have arguments, which are strings.
When you're processing packets, or other networking data,
there are like, network protocols, which are strings.
So you want to be able to effectively,
or efficiently pass them and reasoned body strings.
Yeah, so I've got a couple of samples here, like,
for instance, like matching filesystem paths,
like you want to know if a file you're tracing is
inside your home directory, or matching process names,
which is similar thing, right?
For instance, you want to know about all the system D processes,
and the system D is not just a thing of process.
You just create a bunch of processes,
which do have the system D substring somewhere inside,
and you want to capture all of those.
But it doesn't have to be just like the simplest ones.
It can be like environment variants, which can be huge.
And there are several like attack vectors, which target environment variables.
So you want to be efficiently searching those environment variables
for like malicious substrings, et cetera.
Or as I said, like parsing protocols,
can be kind of tricky.
Now, why do we need these, like, new way of handling strings?
Why can't we use what was already there?
There's two things you have to do,
or you had to do in, like, when handling strings like manually inside BPAT.
So first of all, you would need to take the string and copy it
from the curl memory to your BPAT memory,
beat onto the stack or to your BPAT map.
And then you would usually implement a string operation,
like searching a string or something,
a substring, getting string length, whatever you want manually.
So let me show you a quick example here.
Let's have this, let's have this BPAT program,
which attaches to an LSM hook.
This is basically an LSM hook or a function,
if you will, which executes every time a program is executed
on the system.
And let's say you want to check the base name of the program,
this will be executed, right?
So you have an program executed,
it's a, you have a path, the executable,
and you want to do some searching on the base name,
so on the last part of the path.
Traditionally what you need to do,
you basically have to go through the path and find the last slash,
which divides the directory from the base name.
So what you would do here is something like this,
and I want to point out these two things.
So first of all, as I said,
you would need to copy the string into the BPAT memory.
In this case, we're copying it onto the stack,
so you can see this path variable,
so it's a local variable, so it's allocate on the BPF stack.
That's for one,
and then you would need to implement a loop
to go over the string and search for the last slash.
And as probably most of you know,
BPF and loops don't call together that well.
For instance, like for this case,
I was only able to, I had to limit the size of the buffer
for 32 bytes, otherwise verify it with the jank disk program.
Obviously, I could use modern ways of looping in BPF like BPF loop
that would allow me to go to, you know,
for longer paths, but still I'm limited by,
for instance, like for by stack size,
BPF stack is only 500 to a byte,
so it's kind of limited to the size of the path.
Or you would have to store it path into a map,
but that again brings some overhead,
which you have to deal with,
so again, not something you really want
when you want to do some like fast string processing.
So, what is the answer to this problem?
It's a so-called string k-funks,
for those who don't know k-funks,
or called the BPF kernel functions,
are sort of a modern way of exposing kernel functionality
to BPF programs.
They are very much similar to helpers,
although they have some like small differences,
they're not going to dive into.
And the string k-funks provide implementations
of the most common operations over strings,
which your BPF programs can use.
So, what are the advantages?
Well, obviously eliminating the problems
that I was just talking about,
so you don't need to reinvent the functions manually,
which is great.
Like ergonomics is really good.
And you don't need to copy the strings onto the stack,
or to the maps,
eventually lead into even like small performance benefits.
So, let's see how these are implemented,
because this is kind of interesting.
So, the first idea I had when I started working on these is,
well, the kernel already contains implementations
of the string k-funks,
well, kernel doesn't use toned library functions,
it's only implementations,
but they are simple and they are there.
Like you have the, let's take string length.
There is, this is taken directly from the kernel,
so it's a quite short, simple routine.
So, why don't we just call it, right,
from, this is like, let's enter the k-funks,
we just call the string,
or sorry, the function.
What could go wrong?
Turns out, a lot of things can go wrong,
because we are in a BPF world.
And there are a couple of properties that BPF programs
need to have.
They need to ensure, for one,
they need to ensure safety,
which means that the very file is not able to check.
So, they're very far has some limited support
for like k-funks arguments,
but it can only, since it sees this as a standard pointer,
it can only check the first byte,
it's pointing to is actually a valid memory.
But you have a loop inside,
you want to loop over the entire string,
until you find the null terminator,
and you want to reference,
you want to, you know, see the memory,
but what if the memory is not there,
it doesn't have to be patched in,
which means you would panic at the kernel,
something you don't want, obviously.
So, we need to ensure safety
and playing the reference is not the way to go.
Second, BPF programs must terminate,
you can't hang the kernel.
However, the incremental, well, all the common implementations
of foreigners is like stringling,
count with the fact that strings are null terminated,
you have the null terminator byte,
but what if you don't,
what if the string doesn't end,
then, well, that loop would look forever,
not something you want from your BPF program, right?
So, we had to cover with that different solution,
and unfortunately, it turned out that the only good enough solution
was to re-implement everything from scratch,
hopefully, well, luckily,
the string functions are sort of simple,
and this is what it looks like right now.
So, it's a bit more complicated
that what we have seen on the previous slide,
but it's not that bad.
I'm going to show you,
let's see the features of these implementations.
The first of all, we disable page folds
because we don't want page folds occurring,
execution of BPF programs.
This is something that is going to be called from inside the BPF program,
in the BPF context.
So, first of all, we disable page folds.
This card thing is kind of a nice,
it relies on a nice feature of compilers,
which will, here, insert, like,
disableing of a page fold,
and then they will enable page folds
whenever this function ends, just kind of a nice thing.
And then, instead of plain interference,
we would use this special kernel micro,
which is quite low overhead wrapper
over standard interference,
which just doesn't fall,
doesn't go into a page fold.
If the memory is not there,
what it does instead,
it jumps to this error out label.
And then, we would just return, you know,
error code for the function,
saying that, sorry, we couldn't read the memory, you provided,
but we are crushing, and I think we're just, you know,
reporting to the user that the,
we couldn't process the string,
what that was passed,
and let the user deal with it,
get any way they want.
And the third thing is,
we need to make sure,
if the string is not now terminated,
that the function eventually ends,
which means that we chose
and basically arbitrary,
a polimit on the size.
In this case, it's,
except x, x,
editor,
size max,
which is something like 65 kilobytes,
which is kind of a big enough limit,
you know, to handle most of the
common strings you will you will encounter.
However,
it makes sure that we will always terminate,
which is something BBA programs must do.
Any case we don't,
we would again return an error code
to the user so that he can,
you know, he is not defined and the function,
did something and expected.
Okay, so when it comes to the verified support,
as I said,
so as I said,
verified does have some sort of limited support
for handling or checking some properties
of the K-Funk arguments.
So in this case,
we're dealing with two kinds of arguments.
First of all,
obviously we are passing the string.
So we are passing typically not,
not terminated,
but not necessarily natural,
not terminated strings,
which can be located in,
in BBA or in the curl memory,
which we have to,
from the verified perspective,
we just have to treat them as any,
like,
generate unsafe pointers.
We can't say much about them.
Since they can be in the curl memory.
And then,
we have variants of the string.
Some string functions have,
like,
pounded variants,
so you can actually say that you want to,
run this,
you know,
search for a substring,
but you want to,
to pound it by some integer,
so we can have some integers,
which can be to channel integers here.
So when it comes to verify support for these,
like,
K-Funk arguments,
there's a couple of special suffices
that you can pass to the or you can give to the functions,
sorry,
to arguments.
So what's the following,
underscore underscore STR,
which stands for string literals,
which is not useful here,
because we don't want only literals.
We want to,
you know, pass the pointers to the strings,
located in the curl memory,
instead of just,
you know,
always like,
dealing with literals.
Then,
similarly,
we have underscore,
asy,
which,
represent like a size of a buffer,
but again,
it has to be a literal,
not something we want here,
we just want channel integers for the,
for the second time of the argument.
So again,
not something useful for us.
So what we ended up doing is we basically ended up,
using the third thing,
which is telling the very fire,
just ignore any sort of verification for this argument.
Which is something we can afford,
because,
thanks to that,
you know,
page disabled,
and get curl,
well,
no fault.
We,
we essentially have time of
safety,
so we don't need the very fire to,
give another layer of,
you know,
static safety,
because we are certain that the functions are safe,
by definition,
so we don't need to very fire,
spend any time on dealing,
or proving that those,
those arguments are safe to access,
and as we,
as I said before,
it wouldn't even be able to,
at least not with the current,
you know,
okay,
so let's see,
let's see what we have there,
what,
what you can work with at the moment,
so the initial patch set,
added like,
10-ish functions for like,
the most common read-only operations for now,
only.
So comparing strings,
getting blank,
searching substrings,
searching characters inside the,
the strings,
and what is this,
all these are like,
searching groups of characters inside the string,
and then,
a couple of folks added a few more functions,
mainly dealing with string,
comparison,
or,
yeah,
comparison and finding substrings,
without,
well,
in a case and in sensitive way,
because apparently these are useful
when dealing with some network protocols,
so they are kind of used.
So yeah,
it's the,
the API,
or the,
the library,
the function is kind of growing,
feel free to contribute,
if any other string functions,
it's,
it's not hard,
actually just read whatever is there,
and get inspired by the implementation,
it's in,
kernel slash BPS,
helpers,
or something.
I mean,
feel free to contribute.
Okay,
maybe one,
a couple more like,
specific about the,
the strings,
sort of sort of string functions,
where it comes to comparison,
which standard library functions.
So you all know string length from,
uh,
C standard library,
or,
uh, other,
you know string functions,
but there are some specific that we have here.
So first of all,
one specific is that,
uh,
the,
the string,
a function,
always return integers,
which means that whenever,
a standard library function would return the pointer,
like,
this function,
STR,
C-H-R,
uh,
gets a point,
gets a string,
and a character,
and it returns a pointer
to the first occurrence of that character inside the string.
The BPSK function,
instead returns an index.
Uh,
why is that?
Well,
the first reason is that,
since we have to treat the input pointer as unsafe,
we also have to treat,
we would also have to treat the output pointer as unsafe,
meaning that the rest of the BPS program,
shouldn't the reference that pointer directly.
Anyway,
it would have to, again,
do something like BPS property to whatever.
So it turned out that,
actually issuing our returning,
uh,
indices is,
uh,
is kind of simpler.
Here,
um,
and what it gives us as an advantage,
we can return negative articles,
which is a difference from the traditional,
uh,
traditional,
standard library functions.
We can actually,
in the fall of the user,
the something went wrong,
something,
you know,
I've already talked about,
like returning e-fold when,
uh,
the memory is not there,
or returning e-to-beek when the string is too big.
We have a couple more,
like,
e-rent when the strings are outside of the kernel,
address space,
or,
uh,
particularly for these,
like,
string,
also,
sorry,
character,
such functions,
instead of returning something like,
uh,
expressive enough,
uh,
for the user that the entry,
he was trying to search doesn't exist.
Okay.
Uh,
I'd like to,
give,
uh,
example of,
of how we could use these.
So,
let's get back to the,
to the example I had in the beginning,
uh,
again,
this is the same function.
On the left,
this is practically what we have already seen.
So,
what you have to do traditionally,
you,
uh,
then you would,
well,
this is just,
the chat,
some check for the very fire,
and then you would implement a loop,
where you would search for the last occurrence of a slash,
and then basically your base name is at,
well,
plus,
the location of the slash,
plus one,
because that's where that,
uh,
where it starts,
implementing exactly the same,
using string headphones,
uh,
is on the right side,
and you can see that it's,
considerably shorter,
uh,
you just call and,
in this case,
STR,
our CHR,
which searches the string from the right,
uh,
and searches for the last occurrence of a character,
in this case,
slash,
and then you would get the,
you know,
index,
and the only thing you have to do,
then is to check that,
uh,
well,
check for the error code,
and,
and then you can do whatever you want with that.
If you want to,
like,
if you want to read that string,
like the base name,
you still have to do,
BFF pro breed.
The difference is that,
in this case,
you have to read the entire string,
so you have to read the entire path,
which can be long.
In the,
in our case,
since we have,
like,
dynamic safety of,
of the string k-fun,
you just have to,
read the base name,
which is generally short,
and it usually will fit your BFF stack,
which is good enough.
Um,
cool.
Another use case we have,
and this is actually the first,
like,
reason why I came to implement these functions,
is that I'm maintaining this tool called BFF trace.
I hope you've heard.
And,
so historically,
it BFF trace,
when you would add new functionality,
you would,
you have to implement BFF code using,
BFF code using BFF code,
so you had,
basically have to write,
the functionality,
manually in LFF instructions,
which is,
trust me,
not something you want to do.
Uh,
so thanks to this,
k-fun,
it's much more economic to do this now,
so you just basically,
you don't call this,
built in,
uh,
string k-fun,
and thanks to that,
we finally have,
like,
nice set of functions for,
like,
manipulating strings,
like most importantly,
strings,
which is kind of,
thing that people want to do with BFF trace,
uh,
but then,
war functions are coming,
like,
getting the length of the string,
etc.,
which allows you to,
kind of, like, do,
kind of complex filtering inside your BFF trace scripts,
so inside the kernel,
uh,
which is very efficient,
and, uh,
and you don't need to,
uh,
you know,
write C code in this case,
because BFF trace is much more like easy,
to, to the BFF world.
Um,
okay,
so the last thing I want to talk about is some,
like,
ideas for future directions,
uh,
up for discussion,
or if you have any other ideas,
let me know.
So first of all,
we can obviously add more,
read only functions for now,
if you have an,
as some ideas contribute,
please,
uh,
it's already happening,
if we have seen like,
functions are coming,
uh,
the second big part of the functions we have,
omitted for now,
are those that actually do manipulate the memory,
like,
do copy or move the memory around,
like,
string copy string,
move it to trap.
Uh,
the reason we haven't implemented these at the beginning,
is that there are some,
well,
tricks you have to,
or there are some problems,
which will come,
uh,
for instance,
like,
when the source and the destination buffers overlap,
in,
uh,
in standard library functions,
you just can't,
you know,
undefined behavior,
but you can't afford to have undefined behavior,
in BPA programs.
So this would have to be,
results on how,
like,
for instance,
like,
verify,
would have to check that those two buffers don't overlap.
So we have to have to teach the very fire to do that.
Uh,
it shouldn't be that hard.
It should be like,
it's a problem that can be solved.
Only until now,
we haven't seen a use case for such functions.
So if anyone does have a use case for,
you know,
string copying functions,
or if someone wants to do like,
string copying inside your BPA programs,
just let me know.
Uh,
and when it comes to like BPA trace,
uh,
which is something I work on,
that's why I'm mentioning it here.
Uh,
So first of all,
what we need to do is evaluate this,
appropriating.
So I was saying that BPA,
thanks to this case,
because you don't need to read the entire memory in advance,
unfortunately,
BPA trace still does it.
We'll have to work on this,
uh,
to make it more efficient when it comes to string handling.
And,
uh,
yeah,
adding forever for more functions would be useful.
So the BPA trace gets even more like,
capabilities when it comes to,
just string handling.
Um,
and that's it.
Uh,
thank you for your attention,
and I'm happy to take questions.
Thank you for the talk.
Uh,
I have two questions.
First one is an obvious one,
because there is an influx now of new read-only,
uh, functions to work with strings.
There will be differences between the lens kernel,
when different functions are available probably,
just any tips on how should we handle that in our programs.
So the question is,
if I was incorrectly,
um,
that in all the words,
if I was incorrectly,
um,
that in all the version of the kernel,
you will not have these functions available, right?
Well,
um,
yeah, it's a good question.
Um,
and I don't have a,
get better answer than,
you know,
update to the latest kernel.
What BPA trace does actually,
is that it,
for most of the,
for most of the functions,
it implements like fullbacks,
which are,
uh,
handy,
and see,
so we do have like these fullback functions,
but obviously those have to,
you know,
copy things on the,
on the,
and let's copy and the,
or to the map.
So yeah,
there are less efficient,
but that's the basic interview.
And one more,
what about text encoding?
Sorry,
what about text encoding,
when you want to,
for example,
compare,
multiplied characters.
Um,
good question.
I think,
well,
this is obviously not implementing right now.
I can't imagine,
and you're string-cafying in the call,
which deals with this.
But again,
I guess that's the only,
that's the only way we can,
we can do here.
So I do have an answer to your,
uh,
a question about dealing with it on different kernel versions,
which you can do if you can,
uh,
mark a gay funk as week,
and then the loader will,
um,
if it doesn't exist,
it will still load your program,
and you can check with a,
um,
believe it's, uh,
called,
uh,
does gay has,
has gay sim,
or does gay sim exist?
And then you can,
in a core,
like way,
like dynamically fallback.
So you can write a program that runs home,
on all kernel versions,
and then you would have to fall back dynamically.
Yeah,
let me be,
we have has a way to check if,
sort of a gay funk exists in the,
the current,
run a kernel,
and core,
you can help you to handle that situation.
Yeah,
but you will have to implement it fall back,
or fail,
this up to you.
From there,
Daniel.
Yeah,
I'm sorry.
Uh,
thanks for the presentation.
Uh,
you mentioned that,
um,
contributing,
these gay functions is relatively easy.
I wonder what's the general appetite for,
like accepting them in the kernel?
Uh,
if, for instance,
I'm doing something very protocol specific.
So one,
uh,
the reason I'm asking is a context of the DNS protocol,
where we use strings as domain names,
but the encoding is really complex to parse in a BPF currently,
because you have like graphics,
length,
and go the labels until you reach the terminal label.
Uh,
so I wonder,
uh,
yeah,
was the key for deciding whether it should be,
whether it's like general enough to be accepted,
and,
uh,
and why not when I just have to write and see.
Yeah,
I mean,
it's probably the question for the maintainers of the,
you know, BPF tree.
Uh,
I would say that if the function is like,
usable in a variety of domains,
then it should be fine.
If it's a very specific to a single domain,
yeah,
it could be harder to,
to get it.
So thank you.
Yeah,
I think Daniel has,
uh,
question.
Um,
I've took two questions.
Uh,
have you measured the overhead,
like when you're disabled and re-enable,
page calls,
I think it should be pretty low,
but yes.
Uh,
uh,
I,
I didn't have some like,
very,
uh,
incomplete experiment,
let's say,
which would show that,
uh,
it's really a bit of like,
units of percent,
maybe even less.
Uh,
but I did have time to,
you know,
like,
proper measurement there.
So that's something I would,
I would like to do,
uh,
didn't have time yet.
And the,
the question was,
um,
have you looked into the kernel,
like,
maybe under the library,
so if there,
some functionality that would
implement,
like,
simplified,
like,
matching,
for example,
and whether we could also have this for,
BPS.
Right.
Uh,
yes.
So many things matching.
Uh,
it was a different location,
but I was checking,
if there are some,
like,
magics matching things in,
in the kernel,
and,
there,
there's not many,
I think,
just one or two,
which are very simple,
but I think it was,
on the last,
uh,
plumber,
that,
there were some,
like,
talks about,
uh,
rags matching in BPS.
Yes,
I think this could be a way to implement those,
I think it could be useful for BPS trace,
in particular,
I mean,
like,
there are definitely use cases,
because I've seen a couple of talks on,
on the topic,
uh,
so yeah,
I guess,
there is,
there are use cases for this.
So,
given that the,
that the new work is,
mostly driven by use cases,
or BPS trace,
how does that translate into BPS trace,
is that more in terms of performance improvement,
when internally you process strings,
or is that,
um,
new features,
new helpers to,
that you're exposed to,
you should be both.
First of all,
yes,
it should be like faster,
uh,
easier to implement new helpers for BPS trace,
thanks to these,
and second,
uh,
once we get to,
you know,
implementing those,
like,
avoiding those current,
well,
pro breed,
it should be much more efficient,
and you should be able to handle larger strings,
uh,
I think there was a question over there.
Maybe once we're coming,
I guess,
like from a user perspective,
I mean,
this would be transparent to the user,
from BPS trace point of view,
right?
So you would do the plumbing underneath?
Yes,
of course,
yeah,
it's, well,
for the user,
I guess the only,
like user visible is that,
now it's much easier to add new functions,
so,
we should get more Leo functionality,
when it comes to string handling,
uh,
into BPS trace.
I have two questions.
The first one,
whether the K-Fung helpers here,
have also been extended to cover memory search and general,
so,
mem,
and mem,
CHR for searching large memory blocks of known links,
and the second one,
whether anyone has already tried to create
a little rust nosed on the tailper for IRRS.
Uh,
so,
for the first one,
uh,
I don't think so,
uh,
we haven't,
like,
implementing the general memory search,
uh,
algorithms,
although it should be conceptually the same,
so,
uh,
I guess there will be some,
like,
smaller differences,
but I don't see any reason why those should not be,
well,
except it.
And for the second one,
if I disagree,
it was about rust,
uh,
rappers,
already.
Right,
I,
um,
I don't know,
to be honest,
I don't work on those,
but I think there are a couple of maintainers of those,
maybe in the room,
or there are some later talks on rust,
so,
you can definitely ask those people that,
uh,
better audience for a question.
Uh,
so,
the status of K-Funks,
in IIS,
that it's still working progress,
there is a PR up,
but it's going to be much soon.
And after it gets in,
we are happy to add as many rappers
for the K-Funks this,
there will be.
Thank you.
Any more questions?
Yes.
Uh,
we're going to regard in the string copy.
You were saying about the use case,
and I think there is one that is really stupid,
but I think it's a pattern there a lot.
So there is this API,
or like a API,
like a agreement and deep path.
If the file is deleted,
it's going to be returned as file,
space deleted.
And every time you have to remove this
freaking thing in user space.
So maybe this is a small thing,
but one of these use cases could be there.
Yeah?
Thanks.
All right.
When do we get the K-Funks to your best
the string as a product for an LLM?
Well, someone accepted it into the,
you know, three, two.
All right. Thank you.
Thank you.