This is an archive of the discontinued LLVM Phabricator instance.

PR20721: Don't let UBSan print inaccessible memory
ClosedPublic

Authored by samsonov on Sep 8 2014, 4:56 PM.

Details

Summary

UBSan needs to check if memory snippet it's going to print resides
in addressable memory. Similar check might be helpful in ASan with
dump_instruction_bytes option (see http://reviews.llvm.org/D5167).

Instead of scanning /proc/self/maps manually, delegate this check to
the OS kernel: try to write this memory in a syscall and assume that
memory is inaccessible if the syscall failed (e.g. with EFAULT).

Fixes PR20721.

Diff Detail

Event Timeline

samsonov updated this revision to Diff 13431.Sep 8 2014, 4:56 PM
samsonov retitled this revision from to PR20721: Don't let UBSan print inaccessible memory.
samsonov updated this object.
samsonov edited the test plan for this revision. (Show Details)
samsonov added a reviewer: eugenis.
samsonov added subscribers: rsmith, glider, Unknown Object (MLST).
ygribov added inline comments.
lib/sanitizer_common/sanitizer_posix_libcdep.cc
177

Perhaps assert that write_errno == EFAULT in case of error?

I've checked that IsAccessibleMemoryRange works on Linux and OSX on the following examples:

char *mem = (char*)mmap(0, 4096 * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
mprotect(mem + 4096, 4096, PROT_NONE);
printf("mem: %p\n", mem);
IsAccessibleMemoryRange(mem, 4095);  // 1
IsAccessibleMemoryRange(mem, 4096);  // 1
IsAccessibleMemoryRange(mem, 4097);  // 0
IsAccessibleMemoryRange(mem + 4095, 1);  // 1
IsAccessibleMemoryRange(mem + 4095, 2);  // 0
IsAccessibleMemoryRange(0, 2);  // 0

Care to add a unittest?

lib/sanitizer_common/sanitizer_posix_libcdep.cc
169

Any limits on |size|?
I think it must be an sptr greater than -1 (you're going to compare bytes_written to it) and less than kPageSize (otherwise it'll take too much time to check chunks of too big size)

173

internal_write() returns sptr, not uptr (at least it must).
Also, when bytes_written == size (assuming size != -1), internal_iserror() is always false.

eugenis added inline comments.Sep 9 2014, 1:40 AM
lib/sanitizer_common/sanitizer_posix_libcdep.cc
171

Pipes have capacity, and large writes can block.
Maybe write to /dev/null instead?

glider added a comment.Sep 9 2014, 1:52 AM

A too restrictive seccomp policy may prohibit opening /dev/null

samsonov added inline comments.Sep 9 2014, 3:28 PM
lib/sanitizer_common/sanitizer_posix_libcdep.cc
171
171

If handling EINTR is not enough, I'd rather assert that "size" argument is reasonable small.

173

I believe we have a custom calling convention for returning errno from syscalls on Linux...

samsonov updated this revision to Diff 13657.Sep 12 2014, 1:34 PM

Address reviewers' comments. Add a unit test for IsAccessibleMemoryRange.

glider accepted this revision.Sep 17 2014, 5:33 AM
glider added a reviewer: glider.

LGTM

lib/sanitizer_common/sanitizer_win.cc
526

I suggest making this function always return true and adding a FIXME

This revision is now accepted and ready to land.Sep 17 2014, 5:33 AM
emaste added a subscriber: emaste.Sep 17 2014, 6:01 AM
samsonov added inline comments.Sep 17 2014, 11:02 AM
lib/sanitizer_common/sanitizer_posix_libcdep.cc
169

I pass beg/end instead and check that beg <= end and end - beg < 10*pagesize

177

Done

lib/sanitizer_common/sanitizer_win.cc
526

Done.

samsonov updated this object.Sep 17 2014, 11:04 AM
samsonov edited edge metadata.
samsonov closed this revision.Sep 17 2014, 11:05 AM