0

I came accross this clang article for taint analysis:

https://clang.llvm.org/docs/analyzer/user-docs/TaintAnalysisConfiguration.html#clangsa-taint-configuration-example

In the article, it is mentioned that source and sink can be specified using a YAML file. Any idea how this YAML file can be provided to either scan-build or clang-tidy commands? I don't see a clear option that can be used with scan-build to provide this file. And, for clang-tidy, when I write that content in the .clang-tidy file, clang exists with error saying that it can't identify the 'Propagation' key.

For clang-tidy which comes with clang-17 on ubuntu 22.04 I tried

clang-tidy -checks alpha.security.taint.TaintPropagation ../llvmTaintAnalysis.c

It doesn't report any errors, but it doesn't show the analysis result since, I am not able to define the source/sink of the taint.

Here is the code that I need to test, the source is the argument of the function update_len_value, and the sink is the argument of the function update_len_here.

#include <stdio.h>

#define MAX_SIZE 4

struct s_len_t {
  unsigned int *plen;
};

struct s_s_len_t {
  struct s_len_t *s_len;
};

void update_len_here(unsigned int *plen4)
{
  *plen4 = 1000;
}

void intermediate3(unsigned int *plen3)
{
  update_len_here(plen3);
}

void intermediate2(unsigned int *plen2)
{
  intermediate3(plen2);
}

void intermediate1(struct s_len_t *s_len)
{
  intermediate2(s_len->plen);
}

void update_len_value(struct s_s_len_t *s_s_len)
{
  intermediate1(s_s_len->s_len);
}

int main()
{
  unsigned int var = 5;

  struct s_len_t s_len;
  struct s_s_len_t s_s_len = {.s_len = &s_len};
  struct s_s_len_t *p_s_s_len = &s_s_len;
  p_s_s_len->s_len->plen = &var;

  update_len_value(p_s_s_len);

  char srcArray[MAX_SIZE] = {0};
  char destArray[MAX_SIZE] = {0};

  for (int i = 0; i < *p_s_s_len->s_len->plen; i++) {
      destArray[i] = srcArray[i];
  }

  return destArray[0];
}
F1o0T
  • 1
  • 1

1 Answers1

0

Short answer

To specify (say) taint-config.yaml as the taint configuration file to scan-build, add these arguments:

-analyzer-config alpha.security.taint.TaintPropagation:Config=taint-config.yaml

Complete example

Here is the test input file, modified a little (look for **ADDED** and **CHANGED**, one each, plus a few added comments):

// test.c
// https://stackoverflow.com/questions/76547817/unable-to-provide-the-yaml-config-file-for-clang-taint-analysis-clang-tidy-and-s

#include <stdio.h>

#define MAX_SIZE 4

struct s_len_t {
  unsigned int *plen;
};

struct s_s_len_t {
  struct s_len_t *s_len;
};

// The argument to this function is a taint sink, and is configured as
// such in 'taint-config.yaml'.
void update_len_here(unsigned int *plen4)
{
  *plen4 = 1000;
}

void intermediate3(unsigned int *plen3)
{
  update_len_here(plen3);
}

void intermediate2(unsigned int *plen2)
{
  intermediate3(plen2);
}

void intermediate1(struct s_len_t *s_len)
{
  intermediate2(s_len->plen);
}

// The argument to this function is meant to be a taint source.  But
// that's not really how sources work since they arise from call sites.
void update_len_value(struct s_s_len_t *s_s_len)
{
  intermediate1(s_s_len->s_len);
}

// So, instead, in 'taint-config.yaml', we will configure this function
// as a source, and call it in 'main()' in order to build the argument
// to 'update_len_value'.
unsigned int *get_tainted_ptr(); // **ADDED**

int main()
{
  unsigned int var = 5;

  struct s_len_t s_len;
  struct s_s_len_t s_s_len = {.s_len = &s_len};
  struct s_s_len_t *p_s_s_len = &s_s_len;
  p_s_s_len->s_len->plen = get_tainted_ptr(); // **CHANGED** (was '&var')

  update_len_value(p_s_s_len);

  char srcArray[MAX_SIZE] = {0};
  char destArray[MAX_SIZE] = {0};

  for (int i = 0; i < *p_s_s_len->s_len->plen; i++) {
      destArray[i] = srcArray[i];
  }

  return destArray[0];
}

Configuration file:

# taint-config.yaml
# Configuration file for TaintPropagation checker.

Propagations:
  # The return value of 'get_tainted_ptr' is a taint source.
  - Name: get_tainted_ptr
    DstArgs: [-1]

Sinks:
  # The first argument of 'update_len_here' is a taint sink.
  - Name: update_len_here
    Args: [0]

# EOF

Command and output:

$ scan-build -enable-checker alpha.security.taint.TaintPropagation \
    -analyzer-config alpha.security.taint.TaintPropagation:Config=taint-config.yaml \
    gcc -c test.c
scan-build: Using '/home/scott/opt/clang+llvm-14.0.0-x86_64-linux-gnu-ubuntu-18.04/bin/clang-14' for static analysis
test.c:25:3: warning: Untrusted data is passed to a user-defined sink [alpha.security.taint.TaintPropagation]
  update_len_here(plen3);
  ^~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
scan-build: Analysis run complete.
scan-build: 1 bug found.
scan-build: Run 'scan-view /tmp/scan-build-2023-06-25-034948-65899-1' to examine bug reports.

Observe that the console output only reports the place that tainted data reaches the sink.

To see the full data flow path, run the scan-view command shown in that output. That will open a web browser to show more details. In the web browser, navigating to the finding will show the code interspersed with taint flow path information like this:

Screenshot of web browser showing taint flow

What about clang-tidy?

I was unable to get the taint checkers to report anything when using clang-tidy. I suspect that is because they are part of the Cross Translation Unit analysis system, and either clang-tidy cannot do CTU or it requires something more complicated than just running it in the usual way. (The linked documentation page does not explain how to do CTU with either clang-tidy or scan-build.)

Scott McPeak
  • 8,803
  • 2
  • 40
  • 79
  • Thanks Scott McPeak for your time, detailed answer, and for providing the way how the YAML file can be given to scan-build command. However, I ran the same example you provided with clang 17, but I don't get the same results like yours. I am still investigating why, but if you have any idea what could be the problem, please let me know. – F1o0T Jun 27 '23 at 10:19
  • @F1o0T There is no clang+llvm 17 at https://github.com/llvm/llvm-project/releases . The most recent there is 16.0.6. There is also no clang-17 at https://packages.ubuntu.com/search?keywords=clang&searchon=names&suite=jammy&section=all . The latest there is clang-15. So I don't know how to get the version you are using. – Scott McPeak Jun 27 '23 at 17:07