You
Okay, okay, so and then finally we'll talk about how we can actually implement a supervisor
that runs on Intel TDX.
Okay, just very briefly about me, my name is Tondonan.
My name is Dejop, is I do from the development, but I also developed a lot of other stuff in my spare time,
and I also do a lot of security research, as Joel alluded to.
I really like writing rust cards, and I also really enjoy writing low-level,
kernel development stuff, and so like writing kernels, spoodlers, all that sort of low-level hardware stuff.
I just want to quick note all the opinions presented in this talk, and I want to put both of my employer or any of my previous employers, you know, to go.
Okay, so on a very high level, what is machine?
The basic idea behind machine is to have workloads that transform inputs into outputs,
and then have the integrity of all of that protected.
So we don't want a potential in malicious hypervisor or in the other entity to mess with the input,
the workload itself, or the output, or the output then.
And the way we do this is that we use virtual machine-based confidential computing technologies,
for example initially AMD SVSMP, but in this talk I'll actually present how we actually
are protected to IntelTDX as well.
Yeah.
Okay, and so for example, one of the networking use cases for this, and also the primary use case,
I had to mind with this, was to implement a trusted compiler cache.
So usually, like as you all know,
the company code is fairly complicated and processing in terms of process.
And if you want to catch that, that could potentially save a lot of energy.
The problem there, then, is that if there's a malicious party that injects malicious data into that cache,
you suddenly can't trust the data in there anymore, and you might potentially get infected.
And so in those cases, we want to protect the integrity of the actual input file,
and we want to protect the integrity of the actual workload, which, in this case, might be, for example, GCC.
And we also want to protect the integrity of the actual builds and compile binary that we get out in the end.
And so those are exactly the entities that you could, for example, use a machine,
the output will end with the output file and also an industrial port.
And there's another whole separate process where you can actually use the industrial port,
to verify that all the inputs are output, output, belong together,
and that nothing was tampered with doing all of those processes.
One thing that's really cool about machine is that usually with conventional conventional,
conventional confidential VMs, you have workload directly exposed to the supervisor.
The problem is that the workload is in a lot of cases,
despite very nature, very complicated.
Usually it's like on how operating system might be a Linux kernel or something,
but the point is that it's very large, and that also naturally opens up a letter of place for potential attacks.
What's special about machine is that it places a third entity in the middle of tools,
which is called the supervisor.
And the basic idea is that all data flows through the supervisor.
So the hypervisor never has any chances to talk to the workload,
and that reduces the attack surface for potential experts a lot,
because all data that ever passes to the workload is sanitized.
Another nice thing about the supervisor is that it completely abstracts away
all of the confidential computing technology related stuff that's needed.
So the workload doesn't have to care if it's running on AMD,
or IntelGX, the supervisor just provides hardware independent abstractions
that the workload can then use.
Yeah.
So to summarize, the supervisor acts as a sort of firewall,
and the projects to workload from the hypervisor.
At this point, you might be asking why can we trust the supervisor,
but not the workload itself.
And the answer to that is that the supervisor is much much much smaller.
So, yeah, on IntelTDX, it's a little bit less than 2,000 lines of code,
or in the S&P it's a little bit more than 2,000 lines of code.
But either way, it's way, way smaller than the actual kernel that's used to run the workload,
which is completely custom, but currently happens to be around roughly 31,000 lines of code.
The supervisor's just much smaller, and so if someone wants to audit a system,
the idea is that they just have the supervisor,
they don't even have to look at the workload puzzle,
and so also if the workload evolves over time,
that doesn't have to be re-ordered,
it's only the supervisor that has to be audited,
and considering that the supervisor is pretty much feature complete,
there are no major changes expected in the future.
Another nice thing is that because the supervisor is so small,
we can also apply a lot of hardware mitigations and other mitigations
that would be more complicated to apply on the whole workload itself.
And so, for example, we use some hardware mitigations,
like shadow spec and forward branch breaking,
but we also use some more esoteric stuff.
For example, there is no heap, which just glutes all the whole class of memory corruption
with little bullities, like heap rate at once.
But there's also some even more esoteric stuff,
we actually could put our boot, the page tables at compile time,
and then the runtime we never even have to change them,
and just once again, it's going to simplify stuff,
and makes it a lot more secure, hopefully.
Of course, then the question becomes,
how can we actually enforce at a hardware level,
that the hypervisor never talks to the workload itself,
and the only talks to the supervisor.
On IntelTDX, this is implemented using a special feature,
called TGAttitioning.
And the basic idea is that you have your confidential VM,
and within that you have the main partition,
but then you can also spawn secondary petitions.
And you can sort of think of this as like nested VMs.
It's not quite the same, but yeah.
Also important to point out that even though they are like separate entities
within the same VM, they are used to having cryptic keys,
and so the main partition can access the memory of all other petitions,
but not necessarily the other way around.
And so in the end, as I said, this works a lot like VMs,
and nested VMs, and in the sense that the main partition
pretty much just drives the other petitions,
like a hypervisor usually would.
And this is of course really nice,
because hypervisors have a lot of world access,
and can do a lot of restrictions,
that just, if you just want to workload on their metal,
or like in a bare VM, that just wouldn't work.
And so, like for example, one of the things that we can do,
is that the first partition, the supervisor,
can restrict the secondary partition,
so that the secondary partition doesn't have
the ability to access hypervisors shared memory.
Another thing that we can do is like this goes more on the realm of like hypervisor mitigations,
where we can actually make the kernel code that's used by workload completely mutable.
In an ideal work we probably wouldn't need this,
but if there is some vulnerability somewhere in there,
maybe this eventually helps it because, well,
if the kernel code is mutable, that prevents a lot of attacks.
Another thing that's interesting is that,
usually even with confidential VMs that we have today,
the hypervisor is still in charge of injecting interrupts.
And that has actually led to issues in the past.
There have been some vulnerabilities in black Linux and so on.
And once again, this is something that the supervisor abstracts away.
The supervisor is in charge of injecting all interrupts
and to the workload.
And of course, the supervisor also has to protect against other attacks,
but again, the supervisor is much smaller,
and so hopefully it's much easier to get a correct solution there,
and that because it doesn't have the kernel of the content,
it can be a case.
The case is only has the kernel simply cases.
Yeah, and so this then brings us to what this supervisor actually do.
I told you that it doesn't do a lot,
but I mean, it still has to do some things.
There are basically three stages.
There's a setup stage where the supervisor loads up
and a few inputs, as well as the kernel,
and makes them accessible to the secondary partition,
which is like the workload partition.
Then we enter the stage where we actually execute the workload,
that basically works kind of like a normal hypervisor,
and that you first check if there are any interrupts that need to be injected.
Then you run the workload, eventually the workload exits,
and either through some like natural event,
or in some cases the workload can actually also request some services from the supervisor,
and then those events get handled,
and then we start a loop all over.
Eventually the workload finishes,
it has produced its output file,
and then the last step is that we create the station report
that hopefully makes it,
yeah, hopefully it can convince a very faring party,
that the input file and the workload were able
to create that output.
Yeah, and now we go through some of those steps in a bit more detail.
So the first problem is how can we actually,
how can the supervisor verify that the input file is correct?
There are a couple of requirements here.
The first one is that obviously the input file needs to be part of the
attestation report, otherwise anyone that wants verified
the attestation report can't make sure that it input file hasn't been
tempered with.
But there's also secondary requirement to that,
which is that ideally we don't want the supervisor to be able
to lie about the input file that was provided.
And the reason for that is that somehow if there is a malicious input file,
that exploits the supervisor,
we don't want the supervisor to lie that maybe it was the malicious file,
which is an attestation report for like in benign file,
that user actually wanted to run with.
The other requirement is that we don't want the input file
to be part of the launch management itself.
So if you know those confidential computing technologies,
they have like the launch management itself,
which has like all the initial code and some other segments.
And we don't want the input file to be part of the launch management.
The reason for that is that of course launch management is highly
specific.
And ideally we want to have the deployment,
where we can pre-compete all those values ahead of time,
and then have the input file be separate from that,
so it doesn't have to be involved in all the computations.
And on GDX, we can actually solve this quite neatly,
using this all-configured measurement config,
and the basic idea is that the measurement config,
at GD field, is one field that's supplied at one of the
launch, and it can be changed,
and basically that field just contains a hash of the file.
And when the server has a load up,
it doesn't really look at the input file,
but before it does anything on the grid,
it just competes a hash over that file,
and then makes sure that the measurement config ad fields,
matches the input file,
and hopefully because it doesn't actually look at the input file that much,
and it's unlikely for a malicious input file
to exploit the supervisor or our shown at this stage.
Next up, we'll talk about how the primary petitions
or the supervisor can actually restrict memory accesses
made by the secondary petitions.
There are two ways to sustain.
The first one is fairly simple, which is the TDX,
just exposes a bit, that can be used to prevent
all hypervisor access, hypervisor, let me share accesses
by the secondary petitions.
And by just disabling that,
we can just do that out.
It doesn't matter how badly the workload possibly messes up.
It can be possible for the workload to accidentally access
memory that's shared with the hypervisor,
which once again just eliminates a whole class of bugs.
The other way, the primary petitions can influence the memory
that's accessible by the secondary petitions
is through a so-called TDX call, which is just the TDX thing,
where we can request stuff from the hardware.
And with this particular one, which is like memory page attribute right,
we can set permission bits for secondary petitions.
And so basically at the beginning when the guest launchers,
all memory is only ever accessible to the primary petitions,
so the supervisor.
But if you want to make memory accessible to the secondary petitions,
we can set the value bit.
And as soon as the value bit is actually set,
the workload can then access that memory.
But there's not just a value bit.
There are also few other bits.
So for example, there are like the null rewrite bits,
that you use to.
But there are also expu bits.
There are actually two expu bits.
One is for kernel mode and one is for user mode.
And there are also some other more complicated ones that.
Yeah.
But so the way this is done actually use is that, for example,
for the workload kernel, we just marked that as valid readable
and kernel mode executable.
For the inner binary and also the inner file,
we just marked that as valid and readable.
And we don't ever need to write to it.
And as we don't execute it, because before we execute it,
we actually copy it into some other memory that is hope black in.
That's basically like the generic memory that mushroom uses for most things.
And that memory is then actually used smart as readable,
whiteable and user mode executable.
But once again, like if there are some exploit in there,
the workload kernel can't ever execute that code.
That's in that memory region.
And because it's not marked as a kernel mode executable,
it's only marked as user mode executable.
So I mean, that's just your generic hypervisor,
hypervisor mitigation stuff.
Which brings me to one of my last topics is then how do we execute the workload,
which is of course really bad.
We don't just want to set up all the memory.
And there is another TV guest call VPN.
So I think virtual processor enter is what it's short for.
And there's very pretty much like the instruction that
hypervisor would usually use.
So they're like on the hypervisor, you use the launch of the
and the resume.
Inside, like for with the get partitioning, you just use this one.
And basically when you use this instruction,
the first partition stops running.
And then set the secondary partition stops running.
At some point the secondary partitioning stops running for some reason or another.
And then the primary partition gets some information about why it's stop running.
And then can handle that event and go in.
And so it turns out even though we're like kind of fighting in smaller
live-a-visors, there are actually very few things that can actually happen.
And so there are only three things that can happen in practice.
The first one is the TDX requires the primary partition to handle
CPU ID instructions for secondary petitions.
The other one is that of course we want the workload to request some services for this
one.
That's mostly used for scheduling.
Like for example, if the workload wants to wake up another
CPU, it uses the Supervisor for that, because that's platform specific.
The other thing is memory hub plug.
If the workload wants to request some memory,
it clearly has to talk the hypervisor, but we don't want the workload to try
the hypervisor.
And so that's one of the things that the Supervisor actually takes care of.
And then the last thing of course is that the whole thing,
the goal of this was to produce an output file.
And once again, this is a potential interaction point between the workload and
the hypervisor.
And so all of that also gets taken care of.
By the Supervisor, the Supervisor also transferred transfer server output out.
Lastly, the last thing we do is as I said,
we don't want the hypervisor to inject interrupts into the workload.
And so that's also another thing that we the Supervisor might potentially get
VM exits for, and that it can then emulate.
Yeah, just very briefly for attestation them.
Once again, this is another to the guest call that can be made.
And then basically, we just popular three fields.
Or they get the popular automatically.
The first two ones are the code and input.
So as I talked about, the input gets, let's put into the measurement configuration
at E fields.
As we get launched, the TDX module automatically puts, like launch measurement in
the MLTD field.
And the Supervisor then puts an hash of the output file into the reportile
that field.
And so what's really nice then is that the first two actually completely immutable
after launch.
So it doesn't matter how badly the Supervisor potentially gets compromised.
The only thing that it can ever influence the output file.
And the assumption is that the main threat model is that the input, the code and the
input are malicious.
But of course, if there are malicious, that will show the native facial report.
And so that just can't happen.
Last, the TD reports are actually only verifiable on a local system.
If you want to do remote attestation, you need to turn that into a TD code.
And that's another thing that's actually doesn't have to be done in the VM at all.
That can actually be done by the host.
And so yeah, there's a service that grants on the host that can transform one into
the other.
And that's basically it.
If you're interested in this, there's also another topic that has last year where
I'll talk about a little bit more of the details for AMD as CVS and P.
And if you want, you can check out the course or feel free to ask any questions
if you have any.
Thank you.
I'm not sure about the last one.
Thank you very much.
Thank you.
Okay.
So.
Okay.
So.
Okay.
So the question was, if the host is actually turning the TD report into a TD code,
then it's actually messing with that.
And that like kind of eliminates like if the host can mess with that, that eliminates
integrity guarantees.
And so the answer to that is that it's not actually the host that does the conversion.
It's.
It's like a quoting and you know, it's called.
And that actually converts one issue to the other.
So it's just the host that talks to the quoting and claim and actually does the conversion.
And it's not too much that the host is really doing the conversion.
It's just handling that communication because there's really no reason for like the supervisor or the
counsel to do that.
If you can just ask the host to do that.
So that's not a problem.
Okay.
Please do.
Okay.
Come talk to him in the hallway.
If you have more questions.
But now we.
Use the last 10 minutes for writing that for people around.
Thank you.