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.
4. 4/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
5. 5/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
10. 10/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
14. 14/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
16. 16/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!
17. 17/52
So, what works?
• Pattern-based analysis
• Type inference
• Symbolic execution
• Data-flow analysis
• Method annotations
18. 18/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
19. 19/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
20. 20/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
26. 26/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.
28. 28/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.
31. 31/52
The path to a real vulnerability
CWE - Common Weakness
Enumeration
CVE - Common Vulnerabilities
and Exposures
32. 32/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
33. 33/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
34. 34/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.
35. 35/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.
36. 36/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.
37. 37/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.
38. 38/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
39. 39/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.
40. 40/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).
41. 41/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.
43. 43/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
44. 44/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
45. 45/52
SEI CERT
• Coding standard
• Developed by CERT (CERT Coordination Center,
CERT/CC)
• Meant for C, C++, Java, Perl
• Very similar to CWE
46. 46/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
48. 48/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!!!
49. 49/52
Minimising loses
• Introduction of a vulnerability
• Direct and indirect loses:
• Exploitation
• Bug bounty
• Reputation
• Correction
• Issuing an update
$
$
$
$
$
$
$
50. 50/52
Minimising loses
• Introduction of a vulnerability
• Detection with SAST, correction
• Direct and indirect loses:
• Exploitation
• Bug bounty
• Reputation
• Correction
• Issuing an update
$
$
$
$
$
$
$
51. 51/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