Friday, June 30, 2023

Re: Immutable Page Protections

Justin Handville <nanolith@gmail.com> wrote:

> Theo de Raadt <deraadt@openbsd.org> wrote:
>
> > > It's a cheap defense in depth protection that simplifies my use
> > > case.
>
> > But I don't see a real security benefit of what you are trying to do.
>
> There may not be. At this point, it's more idiomatic. Don't need code?
> Don't keep it. It's an experimental feature. I'm not too broken up if I
> can't use it anymore. I'll find other ways, and I can always just patch
> the kernel.

I think you are confused by something.

Attackers won't use the text you are unmapping, their method will use
the text you have not unmapped.

You will need to argue that I am wrong before you go any further.

> I arrived at this feature because it's similar to a technique in
> firmware, where code access can be trivially narrowed with an MPU. The
> threat there is easier to perceive, since often there isn't a well
> defined kernel in which access to hardware or cryptography can be
> encapsulated with better guarded entry points.

That argument holds no water with me.

> I think that the immutable flag feature is useful, and I think that
> making it automatic is a great security mitigation. I'm just curious
> whether a feature like drop_this_init_code_I_will_never_call_again()
> would also be useful.

Attackers won't use the text you are unmapping, their method will use
the text you have not unmapped.

> Pledge and unveil can limit the impact of system calls, but within the
> program itself, attackers can find unintended ways of using code.

AGAIN: Attackers won't use the text you are unmapping, their method will use
the text you have not unmapped. That is what they do with ROP. You are
probably capable of removing 5% of your text segment, but the attacker is
going to use the other 95% of your text segment which, due to static-linking,
you have placed at very convenient fixed-offset locations relative to whatever
bug they find to exercise.

> One
> salient example I can think of where this may be dangerous is in a more
> dynamic language where eval() or the code generator is needed at
> startup, but is no longer needed after the program enters steady state.
> We've seen plenty of attacks, like Log4J, where sloppy features can be
> used to exploit a naked eval(). Certainly, one solution is to limit what
> libraries are being used. But, another is to go a la carte as with
> pledge, and say, "I no longer need eval(), so drop it."

You are confusing mechanism. pledge blocks the operation in the kernel,
not in the address space. You think you can block the operation in the
existing operating system. A ROP attacker will perform his operations
without caring about the code you have unmapped, because they will use
the large swaths of text-segment you have left mapped because you need it,
and still contains a vast amount of gadgetry. And since you are using
static linking to know where your to-be-unmapped pieces are, you have
conveniently given the attacker fixed-offset locations for the gadgets.

I think you have it all backwards.

> Yes, dynamic languages are an entirely other can of worms, and they
> often have other ways to drop code. But, I think an argument could be
> made for this being useful in a static C/C++ program. Init code and
> other run-once code is still callable, which means that it's ripe for
> gadgets. ASLR and other mitigations make this harder, but not impossible
> as we've seen with various attacks to bypass these mitigations. It's
> much harder to exploit what no longer exists...

Please don't talk to me about ASLR when you are making a static binary
that has libc.a pieces at fixed offsets inside it.
>
> > I'll think about it a bit. But I am very much not convinced that those
> > text segments you have lying around are a real risk.
>
> That's the point of the thread. It's just food for thought. I know that
> features that OpenBSD develop often pop up in other operating systems.

> Dropping code, at least to me, seems like a natural progression of
> dropping access to system calls.

pledge does not drop access to system calls. It blocks the *action*
of it, inside the kernel. You are muddling things together far too much.

No comments:

Post a Comment