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

Repository
rL LLVM

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
330 ↗(On Diff #93675)

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 ↗(On Diff #93675)

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 ↗(On Diff #93675)

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
315 ↗(On Diff #93675)

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

lib/sanitizer_common/tests/sanitizer_test_utils.h
127 ↗(On Diff #93675)

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 ↗(On Diff #93675)

Makes sense. Will update patch.

lib/sanitizer_common/sanitizer_common_interceptors.inc
315 ↗(On Diff #93675)

Makes sense thanks.

330 ↗(On Diff #93675)

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 ↗(On Diff #93675)

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
314 ↗(On Diff #96921)

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.

329 ↗(On Diff #96921)

Please avoid code duplication. Move the interceptor body to COMMON_INTERCEPTOR_STRNDUP_IMPL

333 ↗(On Diff #96921)

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?

339 ↗(On Diff #96921)

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 ↗(On Diff #93675)

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

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

233

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

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

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
232 ↗(On Diff #99440)

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
232 ↗(On Diff #99440)

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
27 ↗(On Diff #100836)

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.