Re: BTI interaction between seccomp filters in systemd and glibc mprotect calls, causing service failures

From: Szabolcs Nagy
Date: Mon Oct 26 2020 - 12:58:38 EST


The 10/26/2020 16:24, Dave Martin via Libc-alpha wrote:
> Unrolling this discussion a bit, this problem comes from a few sources:
>
> 1) systemd is trying to implement a policy that doesn't fit SECCOMP
> syscall filtering very well.
>
> 2) The program is trying to do something not expressible through the
> syscall interface: really the intent is to set PROT_BTI on the page,
> with no intent to set PROT_EXEC on any page that didn't already have it
> set.
>
>
> This limitation of mprotect() was known when I originally added PROT_BTI,
> but at that time we weren't aware of a clear use case that would fail.
>
>
> Would it now help to add something like:
>
> int mchangeprot(void *addr, size_t len, int old_flags, int new_flags)
> {
> int ret = -EINVAL;
> mmap_write_lock(current->mm);
> if (all vmas in [addr .. addr + len) have
> their mprotect flags set to old_flags) {
>
> ret = mprotect(addr, len, new_flags);
> }
>
> mmap_write_unlock(current->mm);
> return ret;
> }

if more prot flags are introduced then the exact
match for old_flags may be restrictive and currently
there is no way to query these flags to figure out
how to toggle one prot flag in a future proof way,
so i don't think this solves the issue completely.

i think we might need a new api, given that aarch64
now has PROT_BTI and PROT_MTE while existing code
expects RWX only, but i don't know what api is best.

> libc would now be able to do
>
> mchangeprot(addr, len, PROT_EXEC | PROT_READ,
> PROT_EXEC | PROT_READ | PROT_BTI);
>
> while systemd's MDWX filter would reject the call if
>
> (new_flags & PROT_EXEC) &&
> (!(old_flags & PROT_EXEC) || (new_flags & PROT_WRITE)
>
>
>
> This won't magically fix current code, but something along these lines
> might be better going forward.
>
>
> Thoughts?
>
> ---Dave