Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SAST and application security

SAST and application security

The PVS-Studio team talks about how static analysis can help write applications that comply with international standards including MISRA, CWE, CVE, SEI CERT etc.
To learn more about PVS-Studio as a SAST solution, click here: https://pvs-studio.com/en/pvs-studio/sast/

PVS-Studio

July 07, 2023
Tweet

More Decks by PVS-Studio

Other Decks in Programming

Transcript

  1. 3/52 The problem • The amount of code is growing

    • Error density grows non- linearly • Everybody wants quality and SAFE code • Old QA methods are not good enough
  2. 4/52 • Linux Kernel 1.0.0 : 176 250 lines •

    Linux Kernel 4.11.7: 18 373 471 lines • Photoshop 1.0 : 128 000 lines • Photoshop CS 6 : 10 000 000 lines Code volume growth for some projects
  3. 5/52 Error density (per 1 KLOC) 0 20 40 60

    80 100 < 2 2-16 16-64 64-512 > 512 "Estimating Software Costs: Bringing Realism to Estimating" (Capers Jones, 2007)
  4. 9/52 “Find the error” attraction (Mono) V3012 The '?:' operator,

    regardless of its conditional expression, always returns one and the same value: Color.FromArgb (150, 179, 225). ProfessionalColorTable.cs 258
  5. 13/52 • Doesn’t replace, but compliments code review • Allows

    controlling code quality in large projects • Early detection of issues • Maximum code coverage • Detection of various error patterns Static code analysis
  6. 15/52 • It’s difficult to find even the simplest of

    combinations: (A + B == B + A) • Macros: who will expand them? • Types: who will calculate typedef chains? • Values: how to find out that an array index is out of bounds? Regular expressions just don’t work!
  7. 16/52 So, what works? • Pattern-based analysis • Type inference

    • Symbolic execution • Data-flow analysis • Method annotations
  8. 17/52 Pattern-based analysis Linux Kernel static ssize_t lp8788_show_eoc_time(struct device *dev,

    struct device_attribute *attr, char *buf) { struct lp8788_charger *pchg = dev_get_drvdata(dev); char *stime[] = { "400ms", "5min", "10min", "15min", "20min", "25min", "30min" "No timeout" }; .... } V653 A suspicious string consisting of two parts is used for array initialization. It is possible that a comma is missing. Consider inspecting this literal: "30min" "No timeout". lp8788-charger.c 657
  9. 18/52 Type inference template<class T, size_t N> struct X {

    T A[N]; void Foo() { memset(A, 0, sizeof(T) * 10); } }; void Do() { X<int, 5> a; a.Foo(); } V512 Instantiate X < int, 5 >: A call of the 'memset' function will lead to overflow of the buffer 'A'. test.cpp 127
  10. 19/52 Symbolic execution void F(int X) { int A =

    X; int B = X + 10; int Q[5]; Q[B - A] = 1; } V557 Array overrun is possible. The 'B - A' index is pointing beyond array bound. test.cpp 126
  11. 20/52 Data-flow analysis static const int kDaysInMonth[13] = { 0,

    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; bool ValidateDateTime(const DateTime& time) { if (time.year < 1 || time.year > 9999 || time.month < 1 || time.month > 12 || time.day < 1 || time.day > 31 || ....) { return false; } if (time.month == 2 && IsLeapYear(time.year)) { return time.month <= kDaysInMonth[time.month] + 1; } else { return time.month <= kDaysInMonth[time.month]; } } protobuf (Chromium) V547 Expression 'time.month <= kDaysInMonth[time.month] + 1' is always true. time.cc 83 V547 Expression 'time.month <= kDaysInMonth[time.month]' is always true. time.cc 85
  12. 21/52 Method annotations public boolean equals(Object other) { if (other

    instanceof Id) { Id that = (Id) other; return purchaseSequence.equals(this.purchaseSequence) && that.purchaseNumber == this.purchaseNumber; } else { return false; } } V6009 Function 'equals' receives odd arguments. Inspect arguments: this, 1. PurchaseRecord.java 57 Hibernate
  13. 24/52 The growth of potential vulnerabilities 5632 16555 0 2000

    4000 6000 8000 10000 12000 14000 16000 18000 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 https://www.cvedetails.com
  14. 25/52 SAST - Static Application Security Testing • Static analysis

    is aimed to detect and eliminate vulnerabilities • Vulnerabilities are common errors (according to NIST, more than 60%) • SAST tools help prevent vulnerabilities and support secure development standards: CWE, MISRA, SEI CERT etc.
  15. 27/52 Detection of vulnerabilities It is optimal to search for

    known vulnerabilities in old code: • Analogy – antivirus software • No false positives • But only knows issues can be found • Especially useful in large old projects For new code, it is more efficient to search for defects in order to prevent against vulnerabilities.
  16. 28/52 Tarry not! 0 1000 2000 3000 4000 5000 6000

    7000 8000 Development Build QA Release Phase Cost to Fix a Security Defect ($) NIST: National Institute of Standards and Technology
  17. 30/52 The path to a real vulnerability CWE - Common

    Weakness Enumeration CVE - Common Vulnerabilities and Exposures
  18. 31/52 CWE • CWE™ is a community-developed list of common

    software security weaknesses • https://cwe.mitre.org • A list of more than 800 potential vulnerabilities, which can become real
  19. 32/52 CWE: examples • CWE-14: Compiler Removal of Code to

    Clear Buffers • CWE-20: Improper Input Validation • CWE-91: XML Injection • CWE-457: Use of Uninitialized Variable • CWE-467: Use of sizeof() on a Pointer Type • CWE-562: Return of Stack Variable Address
  20. 33/52 CWE-14 (Compiler Removal of Code to Clear Buffers) void

    win32_dealloc(struct event_base *_base, void *arg) { struct win32op *win32op = arg; .... memset(win32op, 0, sizeof(win32op)); free(win32op); } V597 The compiler could delete the 'memset' function call, which is used to flush 'win32op' object.
  21. 34/52 CWE-687 (Function Call With Incorrectly Specified Argument Value) void

    win32_dealloc(struct event_base *_base, void *arg) { struct win32op *win32op = arg; .... memset(win32op, 0, sizeof(win32op)); free(win32op); } V579 The memset function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument.
  22. 35/52 CWE-563 (Assignment to Variable without Use) public string Region

    { get {....} set { if (String.IsNullOrEmpty(value)) { this.linker.s3.region = "us-east-1"; } this.linker.s3.region = value; } } V3008 The 'this.linker.s3.region' variable is assigned values twice successively. Perhaps this is a mistake.
  23. 36/52 CWE-674 (Uncontrolled Recursion) OnFailure? onFailure = null; public OnFailure?

    OnFailure { get { return this.OnFailure; } set { this.onFailure = value; } } V3110 Possible infinite recursion inside 'OnFailure' property.
  24. 37/52 CVE • CVE® is a list of publicly known

    cybersecurity vulnerabilities • https://cve.mitre.org/ • A list of more than 114 000 actual vulnerabilities found in existing software
  25. 38/52 CVE-2012-2122 typedef char my_bool; my_bool check_scramble(const char *scramble_arg, const

    char *message, const uint8 *hash_stage2) { .... return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE); } V642 [CWE-197] Saving the 'memcmp' function result inside the 'char' type variable is inappropriate. The significant bits could be lost breaking the program's logic.
  26. 39/52 CVE-2013-4258 if (NasConfig.DoDaemon) { openlog("nas", LOG_PID, LOG_DAEMON); syslog(LOG_DEBUG, buf);

    closelog(); } else { errfd = stderr; } Network Audio System V618 [CWE-134] It's dangerous to call the 'syslog' function in such a manner, as the line being passed could contain format specification. The example of the safe code: printf("%s", str).
  27. 40/52 CVE-2014-1266 static OSStatus SSLVerifySignedServerKeyExchange(....) { .... if ((err =

    SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail; goto fail; if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail; .... fail: .... } V640 [CWE-483] The code's operational logic does not correspond with its formatting. V779 [CWE-561] Unreachable code detected. It is possible that an error is present.
  28. 42/52 MISRA C/C++ • Motor Industry Software Reliability Association •

    Coding standard, which decreases the probability of making an error – for highly dependable embedded systems • Proprietary • MISRA C 2012 consists of 143 rules • MISRA C++ 2008 c consists of 228 rules
  29. 43/52 MISRA C/C++ (some rules) • Don’t use octal literals

    • Don’t use goto • Any function must have a single exit point • Don’t use standard library functions (atof/…/abort/exit/getenv/system/…) • Don’t use dynamic allocations • Don’t use unions • Every case must end with break or throw
  30. 44/52 SEI CERT • Coding standard • Developed by CERT

    (CERT Coordination Center, CERT/CC) • Meant for C, C++, Java, Perl • Very similar to CWE
  31. 45/52 SEI CERT (some rules) • MSC06-C: Beware of compiler

    optimizations • INT33-C: Ensure that division and remainder operations do not result in divide-by-zero errors • EXP33-C, EXP53-CPP: Do not read uninitialized memory • ARR01-C: Do not apply the sizeof operator to a pointer when taking the size of an array • DCL30-C: Declare objects with appropriate storage durations
  32. 47/52 How to adopt and use SAST correctly • Choose

    your analyzer • Configure it • Check the project, consider the current set of warnings as “technical debt” • Work on new warnings • Build SAST into CI systems • Adopt SAST at developer workstations • …. • PROFIT!!!
  33. 48/52 Minimising loses • Introduction of a vulnerability • Direct

    and indirect loses: • Exploitation • Bug bounty • Reputation • Correction • Issuing an update $ $ $ $ $ $ $
  34. 49/52 Minimising loses • Introduction of a vulnerability • Detection

    with SAST, correction • Direct and indirect loses: • Exploitation • Bug bounty • Reputation • Correction • Issuing an update $ $ $ $ $ $ $
  35. 50/52 Summary ⚫ Security issues are costly if they get

    into the end product ⚫ SAST tools – one of the ways to detect vulnerabilities ⚫ Nonetheless, use other available methods ⚫ If a company makes money off of code, it is obliged to make the code secure