Skip to content

Commit bf5963b

Browse files
author
Balazs Benics
committed
[analyzer] Fix taint rule of fgets and setproctitle_init
There was a typo in the rule. `{{0}, ReturnValueIndex}` meant that the discrete index is `0` and the variadic index is `-1`. What we wanted instead is that both `0` and `-1` are in the discrete index list. Instead of this, we wanted to express that both `0` and the `ReturnValueIndex` is in the discrete arg list. The manual inspection revealed that `setproctitle_init` also suffered a probably incomplete propagation rule. Reviewed By: Szelethus, gamesh411 Differential Revision: https://reviews.llvm.org/D119129
1 parent b099e1e commit bf5963b

File tree

4 files changed

+22
-10
lines changed

4 files changed

+22
-10
lines changed

clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
559559
{{"atoll"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
560560
{{"fgetc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
561561
{{"fgetln"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
562-
{{"fgets"}, TR::Prop({{2}}, {{0}, ReturnValueIndex})},
562+
{{"fgets"}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
563563
{{"fscanf"}, TR::Prop({{0}}, {{}, 2})},
564564
{{"sscanf"}, TR::Prop({{0}}, {{}, 2})},
565565
{{"getc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
@@ -632,7 +632,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
632632
if (TR::UntrustedEnv(C)) {
633633
// void setproctitle_init(int argc, char *argv[], char *envp[])
634634
GlobalCRules.push_back(
635-
{{{"setproctitle_init"}}, TR::Sink({{2}}, MsgCustomSink)});
635+
{{{"setproctitle_init"}}, TR::Sink({{1, 2}}, MsgCustomSink)});
636636
GlobalCRules.push_back({{"getenv"}, TR::Source({{ReturnValueIndex}})});
637637
}
638638

clang/test/Analysis/taint-checker-callback-order-has-definition.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,9 @@ void top(const char *fname, char *buf) {
2525
(void)fgets(buf, 42, fp); // Trigger taint propagation.
2626
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: -1
2727
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: 0
28-
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: 1
2928
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: 2
30-
29+
//
3130
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: -1
3231
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 0
33-
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 1
3432
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 2
3533
}

clang/test/Analysis/taint-checker-callback-order-without-definition.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,11 @@ void top(const char *fname, char *buf) {
1919

2020
(void)fgets(buf, 42, fp); // Trigger taint propagation.
2121

22-
// FIXME: Why is the arg index 1 prepared for taint?
23-
// Before the call it wasn't tainted, and it also shouldn't be tainted after the call.
24-
2522
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: -1
2623
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: 0
27-
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: 1
2824
// CHECK-NEXT: PreCall<fgets(buf, 42, fp)> prepares tainting arg index: 2
2925
//
3026
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: -1
3127
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 0
32-
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 1
3328
// CHECK-NEXT: PostCall<fgets(buf, 42, fp)> actually wants to taint arg index: 2
3429
}

clang/test/Analysis/taint-generic.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ extern FILE *stdin;
5858

5959
#define bool _Bool
6060

61+
char *getenv(const char *name);
6162
int fscanf(FILE *restrict stream, const char *restrict format, ...);
6263
int sprintf(char *str, const char *format, ...);
6364
void setproctitle(const char *fmt, ...);
65+
void setproctitle_init(int argc, char *argv[], char *envp[]);
6466
typedef __typeof(sizeof(int)) size_t;
6567

6668
// Define string functions. Use builtin for some of them. They all default to
@@ -404,3 +406,20 @@ void testConfigurationSinks(void) {
404406
void testUnknownFunction(void (*foo)(void)) {
405407
foo(); // no-crash
406408
}
409+
410+
void testProctitleFalseNegative() {
411+
char flag[80];
412+
fscanf(stdin, "%79s", flag);
413+
char *argv[] = {"myapp", flag};
414+
// FIXME: We should have a warning below: Untrusted data passed to sink.
415+
setproctitle_init(1, argv, 0);
416+
}
417+
418+
void testProctitle2(char *real_argv[]) {
419+
char *app = getenv("APP_NAME");
420+
if (!app)
421+
return;
422+
char *argv[] = {app, "--foobar"};
423+
setproctitle_init(1, argv, 0); // expected-warning {{Untrusted data is passed to a user-defined sink}}
424+
setproctitle_init(1, real_argv, argv); // expected-warning {{Untrusted data is passed to a user-defined sink}}
425+
}

0 commit comments

Comments
 (0)