Re: [musl] RFC: adding Linux vsyscall-disable and similar backwards-incompatibility flags to ELF headers?

From: Andy Lutomirski
Date: Wed Sep 02 2015 - 00:32:47 EST


On Tue, Sep 1, 2015 at 9:18 PM, Rich Felker <dalias@xxxxxxxx> wrote:
> On Tue, Sep 01, 2015 at 08:39:27PM -0700, Andy Lutomirski wrote:
>> On Tue, Sep 1, 2015 at 7:54 PM, Rich Felker <dalias@xxxxxxxx> wrote:
>> > On Tue, Sep 01, 2015 at 05:51:44PM -0700, Andy Lutomirski wrote:
>> >> Hi all-
>> >>
>> >> Linux has a handful of weird features that are only supported for
>> >> backwards compatibility. The big one is the x86_64 vsyscall page, but
>> >> uselib probably belongs on the list, too, and we might end up with
>> >> more at some point.
>> >>
>> >> I'd like to add a way that new programs can turn these features off.
>> >> In particular, I want the vsyscall page to be completely gone from the
>> >> perspective of any new enough program. This is straightforward if we
>> >> add a system call to ask for the vsyscall page to be disabled, but I'm
>> >> wondering if we can come up with a non-syscall way to do it.
>> >>
>> >> I think that the ideal behavior would be that anything linked against
>> >> a sufficiently new libc would be detected, but I don't see a good way
>> >> to do that using existing toolchain features.
>> >>
>> >> Ideas? We could add a new phdr for this, but then we'd need to play
>> >> linker script games, and I'm not sure that could be done in a clean,
>> >> extensible way.
>> >
>> > Is there a practical problem you're trying to solve? My understanding
>> > is that the vsyscall nonsense is fully emulated now and that the ways
>> > it could be used as an attack vector have been mitigated.
>>
>> They've been mostly mitigated, but not fully. See:
>>
>> http://googleprojectzero.blogspot.com/2015/08/three-bypasses-and-fix-for-one-of.html
>
> That looks like it would be mitigated by not having any mapping there
> at all and having the kernel just catch the page fault and emulate
> rather than filling it with trapping opcodes for the kernel to catch.
>

Oddly, that causes a compatibility problem. There's a program called
pin that does dynamic instrumentation and actually expects to be able
to read the targets of calls. The way that Linux handles this now is
to put a literal mov $NR, %rax; syscall; ret sequence at the syscall
address but to mark the whole page NX so that any attempt to call it
traps. The trap gets fixed up if the call looks valid (properly
aligned, etc) and the process gets SIGSEGV if not.

This caught me by surprise when I implemented vsyscall emulation the first time.

>> I'm also waiting for someone to find an exploit that uses one of the
>> vsyscalls as a ROP gadget.
>
> This sounds more plausible. gettimeofday actually writes to memory
> pointed to by its arguments. The others look benign.
>
>> > If this is not the case, I have what sounds like an elegant solution,
>> > if it works: presumably affected versions of glibc that used this used
>> > it for all syscalls, so if the process has made any normal syscalls
>> > before using the vsyscall addresses, you can assume it's a bug/attack
>> > and and just raise SIGSEGV. If there are corner cases this doesn't
>> > cover, maybe the approach can still be adapted to work; it's cleaner
>> > than introducing header cruft, IMO.
>>
>> Unfortunately, I don't think this will work. It's never been possible
>> to use the vsyscalls for anything other than gettimeofday, time, or
>> getcpu, so I doubt we can detect affected glibc versions that way.
>
> I thought the idea of the old vsyscall was that you always call it
> rather than using a syscall instruction and it decides whether it can
> do it in userspace or needs to make a real syscall. But if it was only
> called from certain places, then yes, I think you're right that my
> approach doesn't work.

No, it's actually just three separate functions, one for each of
gettimeofday, time, and getcpu.

--Andy
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/