Skip to content

Commit 00cd273

Browse files
author
Alexey Samsonov
committedJan 21, 2014
Sanitize printf functions.
Intercept and sanitize arguments passed to printf functions in ASan and TSan (don't do this in MSan for now). The checks are controlled by runtime flag (off by default for now). Patch http://llvm-reviews.chandlerc.com/D2480 by Yuri Gribov! llvm-svn: 199729
1 parent b8013ba commit 00cd273

15 files changed

+809
-190
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %clang_asan -O2 %s -o %t
2+
// RUN: ASAN_OPTIONS=check_printf=1 %t 2>&1 | FileCheck %s
3+
// RUN: ASAN_OPTIONS=check_printf=0 %t 2>&1 | FileCheck %s
4+
// RUN: %t 2>&1 | FileCheck %s
5+
6+
#include <stdio.h>
7+
int main() {
8+
volatile char c = '0';
9+
volatile int x = 12;
10+
volatile float f = 1.239;
11+
volatile char s[] = "34";
12+
printf("%c %d %.3f %s\n", c, x, f, s);
13+
return 0;
14+
// Check that printf works fine under Asan.
15+
// CHECK: 0 12 1.239 34
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_asan -O2 %s -o %t
2+
// RUN: ASAN_OPTIONS=check_printf=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
3+
// RUN: ASAN_OPTIONS=check_printf=0 %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
4+
// RUN: %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
5+
6+
#include <stdio.h>
7+
#include <stdlib.h>
8+
#include <string.h>
9+
int main() {
10+
volatile char c = '0';
11+
volatile int x = 12;
12+
volatile float f = 1.239;
13+
volatile char s[] = "34";
14+
char *p = strdup((const char *)s);
15+
free(p);
16+
printf("%c %d %.3f %s\n", c, x, f, p);
17+
return 0;
18+
// Check that %s is sanitized.
19+
// CHECK-ON: heap-use-after-free
20+
// CHECK-ON-NOT: 0 12 1.239 34
21+
// CHECK-OFF: 0 12 1.239
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_asan -O2 %s -o %t
2+
// RUN: ASAN_OPTIONS=check_printf=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
3+
// RUN: ASAN_OPTIONS=check_printf=0 %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
4+
// RUN: %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
5+
6+
#include <stdio.h>
7+
int main() {
8+
volatile char c = '0';
9+
volatile int x = 12;
10+
volatile float f = 1.239;
11+
volatile char s[] = "34";
12+
volatile int n[1];
13+
printf("%c %d %.3f %s%n\n", c, x, f, s, &n[1]);
14+
return 0;
15+
// Check that %n is sanitized.
16+
// CHECK-ON: stack-buffer-overflow
17+
// CHECK-ON-NOT: 0 12 1.239 34
18+
// CHECK-OFF: 0 12 1.239 34
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %clang_asan -O2 %s -o %t
2+
// RUN: ASAN_OPTIONS=check_printf=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
3+
// RUN: ASAN_OPTIONS=check_printf=0 %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
4+
// RUN: %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
5+
6+
#include <stdio.h>
7+
int main() {
8+
volatile char c = '0';
9+
volatile int x = 12;
10+
volatile float f = 1.239;
11+
volatile char s[] = "34";
12+
volatile char buf[2];
13+
sprintf((char *)buf, "%c %d %.3f %s\n", c, x, f, s);
14+
puts((const char *)buf);
15+
return 0;
16+
// Check that size of output buffer is sanitized.
17+
// CHECK-ON: stack-buffer-overflow
18+
// CHECK-ON-NOT: 0 12 1.239 34
19+
// CHECK-OFF: 0 12 1.239 34
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %clang_asan -O2 %s -o %t
2+
// RUN: ASAN_OPTIONS=check_printf=1 not %t 2>&1 | FileCheck --check-prefix=CHECK-ON %s
3+
// RUN: ASAN_OPTIONS=check_printf=0 %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
4+
// RUN: %t 2>&1 | FileCheck --check-prefix=CHECK-OFF %s
5+
6+
#include <stdio.h>
7+
#include <string.h>
8+
int main() {
9+
volatile char c = '0';
10+
volatile int x = 12;
11+
volatile float f = 1.239;
12+
volatile char s[] = "34";
13+
volatile char fmt[2];
14+
memcpy((char *)fmt, "%c %d %f %s\n", sizeof(fmt));
15+
printf(fmt, c, x, f, s);
16+
return 0;
17+
// Check that format string is sanitized.
18+
// CHECK-ON: stack-buffer-overflow
19+
// CHECK-ON-NOT: 0 12 1.239 34
20+
// CHECK-OFF: 0
21+
}

‎compiler-rt/lib/msan/msan_interceptors.cc

+2
Original file line numberDiff line numberDiff line change
@@ -1291,6 +1291,8 @@ extern "C" int *__errno_location(void);
12911291
} while (false) // FIXME
12921292
#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
12931293
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
1294+
// FIXME: update Msan to use common printf interceptors
1295+
#define SANITIZER_INTERCEPT_PRINTF 0
12941296
#include "sanitizer_common/sanitizer_common_interceptors.inc"
12951297

12961298
#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) CHECK_UNPOISONED(p, s)

‎compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc

+185-19
Original file line numberDiff line numberDiff line change
@@ -569,10 +569,24 @@ INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) {
569569
#define INIT_STRPTIME
570570
#endif
571571

572-
#if SANITIZER_INTERCEPT_SCANF
573-
572+
#if SANITIZER_INTERCEPT_SCANF || SANITIZER_INTERCEPT_PRINTF
574573
#include "sanitizer_common_interceptors_scanf.inc"
575574

575+
#define FORMAT_INTERCEPTOR_IMPL(name, vname, ...) \
576+
{ \
577+
void *ctx; \
578+
va_list ap; \
579+
va_start(ap, format); \
580+
COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \
581+
int res = vname(__VA_ARGS__, ap); \
582+
va_end(ap); \
583+
return res; \
584+
}
585+
586+
#endif
587+
588+
#if SANITIZER_INTERCEPT_SCANF
589+
576590
#define VSCANF_INTERCEPTOR_IMPL(vname, allowGnuMalloc, ...) \
577591
{ \
578592
void *ctx; \
@@ -607,35 +621,24 @@ INTERCEPTOR(int, __isoc99_vfscanf, void *stream, const char *format, va_list ap)
607621
VSCANF_INTERCEPTOR_IMPL(__isoc99_vfscanf, false, stream, format, ap)
608622
#endif // SANITIZER_INTERCEPT_ISOC99_SCANF
609623

610-
#define SCANF_INTERCEPTOR_IMPL(name, vname, ...) \
611-
{ \
612-
void *ctx; \
613-
va_list ap; \
614-
va_start(ap, format); \
615-
COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__, ap); \
616-
int res = vname(__VA_ARGS__, ap); \
617-
va_end(ap); \
618-
return res; \
619-
}
620-
621624
INTERCEPTOR(int, scanf, const char *format, ...)
622-
SCANF_INTERCEPTOR_IMPL(scanf, vscanf, format)
625+
FORMAT_INTERCEPTOR_IMPL(scanf, vscanf, format)
623626

624627
INTERCEPTOR(int, fscanf, void *stream, const char *format, ...)
625-
SCANF_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
628+
FORMAT_INTERCEPTOR_IMPL(fscanf, vfscanf, stream, format)
626629

627630
INTERCEPTOR(int, sscanf, const char *str, const char *format, ...)
628-
SCANF_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
631+
FORMAT_INTERCEPTOR_IMPL(sscanf, vsscanf, str, format)
629632

630633
#if SANITIZER_INTERCEPT_ISOC99_SCANF
631634
INTERCEPTOR(int, __isoc99_scanf, const char *format, ...)
632-
SCANF_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
635+
FORMAT_INTERCEPTOR_IMPL(__isoc99_scanf, __isoc99_vscanf, format)
633636

634637
INTERCEPTOR(int, __isoc99_fscanf, void *stream, const char *format, ...)
635-
SCANF_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
638+
FORMAT_INTERCEPTOR_IMPL(__isoc99_fscanf, __isoc99_vfscanf, stream, format)
636639

637640
INTERCEPTOR(int, __isoc99_sscanf, const char *str, const char *format, ...)
638-
SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
641+
FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
639642
#endif
640643

641644
#endif
@@ -664,6 +667,167 @@ SCANF_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
664667
#define INIT_ISOC99_SCANF
665668
#endif
666669

670+
#if SANITIZER_INTERCEPT_PRINTF
671+
672+
#define VPRINTF_INTERCEPTOR_ENTER(vname, ...) \
673+
void *ctx; \
674+
COMMON_INTERCEPTOR_ENTER(ctx, vname, __VA_ARGS__); \
675+
va_list aq; \
676+
va_copy(aq, ap);
677+
678+
#define VPRINTF_INTERCEPTOR_RETURN() \
679+
va_end(aq);
680+
681+
#define VPRINTF_INTERCEPTOR_IMPL(vname, ...) \
682+
{ \
683+
VPRINTF_INTERCEPTOR_ENTER(vname, __VA_ARGS__); \
684+
if (common_flags()->check_printf) \
685+
printf_common(ctx, format, aq); \
686+
int res = REAL(vname)(__VA_ARGS__); \
687+
VPRINTF_INTERCEPTOR_RETURN(); \
688+
return res; \
689+
}
690+
691+
#define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \
692+
{ \
693+
VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \
694+
if (common_flags()->check_printf) { \
695+
printf_common(ctx, format, aq); \
696+
} \
697+
int res = REAL(vname)(str, __VA_ARGS__); \
698+
if (res >= 0 && common_flags()->check_printf) { \
699+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, res + 1); \
700+
} \
701+
VPRINTF_INTERCEPTOR_RETURN(); \
702+
return res; \
703+
}
704+
705+
#define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \
706+
{ \
707+
VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \
708+
if (common_flags()->check_printf) { \
709+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, str, size); \
710+
printf_common(ctx, format, aq); \
711+
} \
712+
int res = REAL(vname)(str, size, __VA_ARGS__); \
713+
VPRINTF_INTERCEPTOR_RETURN(); \
714+
return res; \
715+
}
716+
717+
#define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \
718+
{ \
719+
VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \
720+
if (common_flags()->check_printf) { \
721+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, strp, sizeof(char *)); \
722+
printf_common(ctx, format, aq); \
723+
} \
724+
int res = REAL(vname)(strp, __VA_ARGS__); \
725+
if (res >= 0 && common_flags()->check_printf) { \
726+
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *strp, res + 1); \
727+
} \
728+
VPRINTF_INTERCEPTOR_RETURN(); \
729+
return res; \
730+
}
731+
732+
INTERCEPTOR(int, vprintf, const char *format, va_list ap)
733+
VPRINTF_INTERCEPTOR_IMPL(vprintf, format, ap)
734+
735+
INTERCEPTOR(int, vfprintf, void *stream, const char *format, va_list ap)
736+
VPRINTF_INTERCEPTOR_IMPL(vfprintf, stream, format, ap)
737+
738+
INTERCEPTOR(int, vsnprintf, char *str, SIZE_T size, const char *format,
739+
va_list ap)
740+
VSNPRINTF_INTERCEPTOR_IMPL(vsnprintf, str, size, format, ap)
741+
742+
INTERCEPTOR(int, vsprintf, char *str, const char *format, va_list ap)
743+
VSPRINTF_INTERCEPTOR_IMPL(vsprintf, str, format, ap)
744+
745+
INTERCEPTOR(int, vasprintf, char **strp, const char *format, va_list ap)
746+
VASPRINTF_INTERCEPTOR_IMPL(vasprintf, strp, format, ap)
747+
748+
#if SANITIZER_INTERCEPT_ISOC99_PRINTF
749+
INTERCEPTOR(int, __isoc99_vprintf, const char *format, va_list ap)
750+
VPRINTF_INTERCEPTOR_IMPL(__isoc99_vprintf, format, ap)
751+
752+
INTERCEPTOR(int, __isoc99_vfprintf, void *stream, const char *format,
753+
va_list ap)
754+
VPRINTF_INTERCEPTOR_IMPL(__isoc99_vfprintf, stream, format, ap)
755+
756+
INTERCEPTOR(int, __isoc99_vsnprintf, char *str, SIZE_T size, const char *format,
757+
va_list ap)
758+
VSNPRINTF_INTERCEPTOR_IMPL(__isoc99_vsnprintf, str, size, format, ap)
759+
760+
INTERCEPTOR(int, __isoc99_vsprintf, char *str, const char *format,
761+
va_list ap)
762+
VSPRINTF_INTERCEPTOR_IMPL(__isoc99_vsprintf, str, format,
763+
ap)
764+
765+
#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF
766+
767+
INTERCEPTOR(int, printf, const char *format, ...)
768+
FORMAT_INTERCEPTOR_IMPL(printf, vprintf, format)
769+
770+
INTERCEPTOR(int, fprintf, void *stream, const char *format, ...)
771+
FORMAT_INTERCEPTOR_IMPL(fprintf, vfprintf, stream, format)
772+
773+
INTERCEPTOR(int, sprintf, char *str, const char *format, ...) // NOLINT
774+
FORMAT_INTERCEPTOR_IMPL(sprintf, vsprintf, str, format) // NOLINT
775+
776+
INTERCEPTOR(int, snprintf, char *str, SIZE_T size, const char *format, ...)
777+
FORMAT_INTERCEPTOR_IMPL(snprintf, vsnprintf, str, size, format)
778+
779+
INTERCEPTOR(int, asprintf, char **strp, const char *format, ...)
780+
FORMAT_INTERCEPTOR_IMPL(asprintf, vasprintf, strp, format)
781+
782+
#if SANITIZER_INTERCEPT_ISOC99_PRINTF
783+
INTERCEPTOR(int, __isoc99_printf, const char *format, ...)
784+
FORMAT_INTERCEPTOR_IMPL(__isoc99_printf, __isoc99_vprintf, format)
785+
786+
INTERCEPTOR(int, __isoc99_fprintf, void *stream, const char *format, ...)
787+
FORMAT_INTERCEPTOR_IMPL(__isoc99_fprintf, __isoc99_vfprintf, stream, format)
788+
789+
INTERCEPTOR(int, __isoc99_sprintf, char *str, const char *format, ...)
790+
FORMAT_INTERCEPTOR_IMPL(__isoc99_sprintf, __isoc99_vsprintf, str, format)
791+
792+
INTERCEPTOR(int, __isoc99_snprintf, char *str, SIZE_T size,
793+
const char *format, ...)
794+
FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
795+
format)
796+
797+
#endif // SANITIZER_INTERCEPT_ISOC99_PRINTF
798+
799+
#endif // SANITIZER_INTERCEPT_PRINTF
800+
801+
#if SANITIZER_INTERCEPT_PRINTF
802+
#define INIT_PRINTF \
803+
COMMON_INTERCEPT_FUNCTION(printf); \
804+
COMMON_INTERCEPT_FUNCTION(sprintf); \
805+
COMMON_INTERCEPT_FUNCTION(snprintf); \
806+
COMMON_INTERCEPT_FUNCTION(asprintf); \
807+
COMMON_INTERCEPT_FUNCTION(fprintf); \
808+
COMMON_INTERCEPT_FUNCTION(vprintf); \
809+
COMMON_INTERCEPT_FUNCTION(vsprintf); \
810+
COMMON_INTERCEPT_FUNCTION(vsnprintf); \
811+
COMMON_INTERCEPT_FUNCTION(vasprintf); \
812+
COMMON_INTERCEPT_FUNCTION(vfprintf);
813+
#else
814+
#define INIT_PRINTF
815+
#endif
816+
817+
#if SANITIZER_INTERCEPT_ISOC99_PRINTF
818+
#define INIT_ISOC99_PRINTF \
819+
COMMON_INTERCEPT_FUNCTION(__isoc99_printf); \
820+
COMMON_INTERCEPT_FUNCTION(__isoc99_sprintf); \
821+
COMMON_INTERCEPT_FUNCTION(__isoc99_snprintf); \
822+
COMMON_INTERCEPT_FUNCTION(__isoc99_fprintf); \
823+
COMMON_INTERCEPT_FUNCTION(__isoc99_vprintf); \
824+
COMMON_INTERCEPT_FUNCTION(__isoc99_vsprintf); \
825+
COMMON_INTERCEPT_FUNCTION(__isoc99_vsnprintf); \
826+
COMMON_INTERCEPT_FUNCTION(__isoc99_vfprintf);
827+
#else
828+
#define INIT_ISOC99_PRINTF
829+
#endif
830+
667831
#if SANITIZER_INTERCEPT_IOCTL
668832
#include "sanitizer_common_interceptors_ioctl.inc"
669833
INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) {
@@ -2924,6 +3088,8 @@ INTERCEPTOR(__sanitizer_clock_t, times, void *tms) {
29243088
INIT_STRPTIME; \
29253089
INIT_SCANF; \
29263090
INIT_ISOC99_SCANF; \
3091+
INIT_PRINTF; \
3092+
INIT_ISOC99_PRINTF; \
29273093
INIT_FREXP; \
29283094
INIT_FREXPF_FREXPL; \
29293095
INIT_GETPWNAM_AND_FRIENDS; \

0 commit comments

Comments
 (0)
Please sign in to comment.