This is an archive of the discontinued LLVM Phabricator instance.

[asan] Add strndup/__strndup interceptors if targeting linux.
ClosedPublic

Authored by pgousseau on Mar 29 2017, 3:57 AM.

Diff Detail

Event Timeline

pgousseau created this revision.Mar 29 2017, 3:57 AM
pgousseau updated this revision to Diff 93354.Mar 29 2017, 4:08 AM

Fix bad copy paste in lit test.

kcc added inline comments.Mar 29 2017, 4:53 PM
lib/asan/asan_interceptors.cc
574 ↗(On Diff #93354)

this needs to go to lib/sanitizer_common/sanitizer_common_interceptors.inc and removed from lib/msan/msan_interceptors.cc

filcab added inline comments.Mar 30 2017, 5:46 AM
lib/asan/asan_interceptors.h
77 ↗(On Diff #93354)

This one (the plain strdup) should be intercepted in all SANITIZER_POSIX platforms. And it seems Android might have it: https://android.googlesource.com/platform/bionic/+/donut-release/libc/string/strndup.c
https://android.googlesource.com/platform/bionic/+/android-7.1.1_r28/libc/include/string.h

pgousseau updated this revision to Diff 93675.Mar 31 2017, 9:52 AM

Thank you Kostya and Filipe for the comments, I have made the following changes:

  • Moved proposed interceptors into sanitizer_common_interceptors.inc
  • Moved existing strndup msan interceptor into sanitizer_common_interceptors.inc
  • Added common function COMMON_INTERCEPTOR_STRNDUP_IMPL
  • Added intercept_strndup flag true by default
  • Enabled strndup interceptor on POSIX
filcab added inline comments.Apr 11 2017, 10:40 AM
lib/sanitizer_common/sanitizer_common_interceptors.inc
340

Should the context be __strndup?
It's probably ok as it is if the __strndup function is not supposed to be user-visible.

lib/sanitizer_common/tests/sanitizer_test_utils.h
127

We should also enter here if defined(__APPLE__) and if defined(__FreeBSD__), I think.
Can't think of more OS we support that should be here.

I'm not sure we should be taking Android out of the picture, as it seems strndup is available, AFAICT. @kcc/@vitalybuka (or others who might be working on Android) can you confirm if we should expect strndup to be available?

test/asan/TestCases/strndup_oob_test.cc
9 ↗(On Diff #93675)

I don't think this should require Linux. It should have Windows as unsupported, but should work on all (?) POSIX.
Maybe just put it in TestCases/Posix?

eugenis added inline comments.Apr 11 2017, 1:51 PM
lib/msan/msan_interceptors.cc
1339

I don't like that the code tries to combine two very different implementations in one "common" interceptor - one that calls REAL(strlen) and one that uses malloc directly.

Common interceptor should implement the logic of strndup, and call individual sanitizers only to update their specific state - READ_RANGE at the start, and something like COPY_RANGE after.

I think the common implementation should use malloc directly.

lib/sanitizer_common/sanitizer_common_interceptors.inc
325

this should use strnlen, like the msan interceptor it is replacing

lib/sanitizer_common/tests/sanitizer_test_utils.h
127

Yes, strndup is available on Android.

Thanks Filipe/Eugenis for the comments, one question I have is, since my change modifies the behaviour of msan strndup interceptor (cf. added msan/strndup.cc test), should I keep the msan change as part of this patch or do you prefer a separate review?

lib/msan/msan_interceptors.cc
1339

Makes sense. Will update patch.

lib/sanitizer_common/sanitizer_common_interceptors.inc
325

Makes sense thanks.

340

Yes I think strndup is preferred because this is also the case with strdup/strndup in asan_interceptors.cc

lib/sanitizer_common/tests/sanitizer_test_utils.h
127

Sounds good will do.

test/asan/TestCases/strndup_oob_test.cc
9 ↗(On Diff #93675)

Makes sense thanks!

eugenis edited edge metadata.Apr 12 2017, 11:46 AM

Keep it as one change.

pgousseau updated this revision to Diff 96921.Apr 27 2017, 8:04 AM

Hi Eugenis/Filipe,

I have implemented the requested changes:

  • Enabling strndup interceptor on all posix platforms including android
  • Unsupport test on win32
  • Implemented common logic of strndup in common interceptor and added COMMON_INTERCEPTOR_COPY_STRING

Let me know what you think!

Thanks,

Pierre

pgousseau marked 9 inline comments as done.Apr 27 2017, 8:06 AM
eugenis added inline comments.
lib/sanitizer_common/sanitizer_common_interceptors.inc
330

MSan needs COPY_STRING for correctness. Without out, the destination buffer would be left uninitialized (poisoned). It needs to happen regardless of intercept_strndup.

Please add a test for this.

345

Please avoid code duplication. Move the interceptor body to COMMON_INTERCEPTOR_STRNDUP_IMPL

349

Hmm I have a vague recollection of tsan having problems with interceptors calling other interceptors. On the other hand, tsan interceptor for strdup calls REAL(strdup), which ends up in the malloc interceptor. Dmitry?

355

internal_memcpy

pgousseau updated this revision to Diff 97107.Apr 28 2017, 8:32 AM

Thanks Eugeny for the comments,

I have made the requested changes:

  • call COPY_STRING regardless of intercept_strndup
  • modified msan test to check poisoning is preserved
  • Moved common implementation into COMMON_INTERCEPTOR_STRNDUP_IMPL
  • Use internal_memcpy
eugenis accepted this revision.May 1 2017, 2:23 PM

LGTM

lib/sanitizer_common/tests/sanitizer_test_utils.h
127

maybe simply #if !defined(_MSC_VER)

This revision is now accepted and ready to land.May 1 2017, 2:23 PM
This revision was automatically updated to reflect the committed changes.
pgousseau marked 2 inline comments as done.
pgousseau reopened this revision.May 2 2017, 6:30 AM

Reverted the change in rL301909.
The change seems to cause 2 build failures.
Undeclared __interceptor_malloc in esan_interceptors.cc.
Undeclared strnlen on OSX buildbots.

This revision is now accepted and ready to land.May 2 2017, 6:30 AM
pgousseau updated this revision to Diff 97439.May 2 2017, 6:32 AM

Attempt to fix build failures:

  • add declaration of __interceptor_malloc in esan_interceptors.cc
  • replace REAL(strnlen) by internal_strnlen

Ping! Is it ok to recommit?

This revision was automatically updated to reflect the committed changes.

One of the test I have added (strndup_oob_test.cc) is failing on the s390 linux bot (cf http://lab.llvm.org:8011/builders/clang-s390x-linux/builds/8096) .
I have marked the test as unsupported on s390 for now in rL302789 if that's ok?

strndup_oob_test.cc also fails on armv7l-unknown-linux-gnueabihf (cf http://lab.llvm.org:8011/builders/clang-cmake-thumbv7-a15-full-sh/builds/1521).
I have marked it as unsupported in rL302807 as this is a known issue.

vitalybuka added inline comments.May 17 2017, 6:07 PM
compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc
230 ↗(On Diff #98598)

Min() is redundant here, as (internal_strnlen(s, size) <= size)

233 ↗(On Diff #98598)

must be "COMMON_INTERCEPTOR_READ_RANGE(ctx, s, Min(copy_length + 1, size)); "

(copy_length + 1) is a problem if "s" is not zero terminated

vitalybuka added inline comments.May 17 2017, 6:11 PM
compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc
233 ↗(On Diff #98598)

I am going to extend test and create a patch for this.

pgousseau added inline comments.May 18 2017, 2:37 AM
compiler-rt/trunk/lib/sanitizer_common/sanitizer_common_interceptors.inc
233 ↗(On Diff #98598)

Makes sense yes thanks! Now that this has been reverted in rL303324, do you still plan on making a patch for it?

pgousseau reopened this revision.May 18 2017, 8:07 AM

Reopening after issue was found and reverted in rL303339

This revision is now accepted and ready to land.May 18 2017, 8:07 AM
pgousseau updated this revision to Diff 99440.May 18 2017, 8:27 AM
  • Fix off by one issue using Vitaly's fix.
  • Expanded msan and asan unit tests to check for the correct handling of non zero terminated strings.
vitalybuka added inline comments.May 18 2017, 12:58 PM
lib/sanitizer_common/sanitizer_common_interceptors.inc
229

probably should be COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min(size, copy_length + 1));

pgousseau updated this revision to Diff 99530.May 19 2017, 2:05 AM

Invert arguments positions in Min call.

lib/sanitizer_common/sanitizer_common_interceptors.inc
229

Sounds good, I have updated the patch.

Ping! Latest comment has been addressed, ok to commit?

Invert arguments positions in Min call.

I don't think the order of the arguments matters here. Vitaly's comment was about READ_STRING vs READ_RANGE.

pgousseau updated this revision to Diff 100836.May 31 2017, 1:49 AM

Replaced READ_RANGE by READ_STRING

Invert arguments positions in Min call.

I don't think the order of the arguments matters here. Vitaly's comment was about READ_STRING vs READ_RANGE.

Yes that makes more sense thanks, patch updated!

vitalybuka requested changes to this revision.May 31 2017, 10:55 AM

Looking.

This revision now requires changes to proceed.May 31 2017, 10:55 AM
vitalybuka accepted this revision.May 31 2017, 11:13 AM

LGTM

test/asan/TestCases/Posix/strndup_oob_test.cc
28

Maybe another simple test

// RUN: %clang_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clang_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clang_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clang_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s

// When built as C on Linux, strndup is transformed to __strndup.
// RUN: %clang_asan -O3 -xc %s -o %t && not %run %t 2>&1 | FileCheck %s

// Unwind problem on arm: "main" is missing from the allocation stack trace.
// UNSUPPORTED: win32,s390,armv7l-unknown-linux-gnueabihf

#include <string.h>

char kChars[] = {'f', 'o', 'o'};

int main(int argc, char **argv) {
  char *copy = strndup(kChars, 3);
  copy = strndup(kChars, 10);
  // CHECK: AddressSanitizer: global-buffer-overflow
  // CHECK: {{.*}}main {{.*}}.cc:[[@LINE-2]]
  return *copy;
}
This revision is now accepted and ready to land.May 31 2017, 11:13 AM
This revision was automatically updated to reflect the committed changes.

LGTM

Thanks, patch committed with the extra test.