# Security and Dependability Aspects
---
###### tags: `NCKU`, `lesson`, `splint`
---
## Revision record
| version | comment | author |
| ------- | ------------------------ | -------- |
| v0.1.0 | document built | Marco Ma |
| v0.1.1 | 16.1 and 16.2 update | Marco Ma |
| v0.1.2 | section Annotation added | Marco Ma |
| v0.2.0 | reference list added | Marco Ma |
---
## Outline
* Introduction
* Annotation
* 16.1 Introduction to SPLINT
* 16.2 Basic Checks
* 16.3 Memory Management
* 16.4 Buffer Overflows
* 16.5 Function Interface Annotations
* 16.6 Summary
---
## Introduction
Splint is a static code analysis tool, it could detect problems like memory leak, null pointer, buffer overflow, etc.
## Annotation
| Annotation | meaning |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------- |
| ```/*@only@*/``` | the pointer is the only one which pointed to the data |
| ```/*@owned@*/``` | pointer has responsibility to free the storage it points to |
| ```/*@dependent@*/``` | the object might share by mulit pointer, in other words, pointer doesn't have the responsibility to free the storage |
| ```/*@in@*/``` | the value is completely defined |
| ```/*@out@*/``` | the value might not completely defined |
| ```/*@requires@*/``` | the condition following must be true before the function start |
| ```/*@ensures@*/``` | the condition following must be true after the function return |
| ```/*@maxSet(buf)@*/``` | ```char buf[MAXSIZE]``` we have ```maxSet(buf) = MAXSIZE - 1``` |
| ```/*@maxRead(buf)@*/``` | highest index for buf which has init already |
| ```/*@modifies@*/``` | list which variables a function may modify |
| ```/*@special@*/``` | argument handle with further annotation |
| ```/*@uses@*/``` | function has read permission, argument defined before function start |
| ```/*@sets@*/``` | function has write permission, argument memory allocated before function start and defined before function end |
| ```/*@allocates@*/``` | function needs to allocated memory for this argument, error if memory allocated already |
| ```/*@defines@*/``` | function needs to allocated memory and defined this argument |
| ```/*@releases@*/``` | function needs to release memory for this argument |
---
## Outline (Tseng)
:::info
1. Introduction
- what is static code analysis?
- why the static code analysis is popular in Embedded System?
- what's the downside?
- Static code analysis contain a lot of false positive
- others
- how to achieve?
- step 1 2 3
-
3. Basic Checks
- annotation and flags
- 4 examples
- NULL pointer
- enumerated data type
- boolean data type
- control flow
4. Memory Management
- pointer issues
-
:::
## 16.1 Introduction to SPLINT
### goal: introduce 1. static code analysis, 2. SPLINT
Basically we use ***flag*** and ***annotation*** to control SPLINT.
Where flag is defined in terminal:
``` splint -flag +flag code.c```
And annotation is defined in code:
```/*@null@*/ int *p;```
We use ```+``` to turn on a flag, and ```-``` to turn off a flag.
Also, we could use ```=``` to reset a flag to default or specified a value.
- What is static code analysis?
- check the your program on source code level
- check your source code through some "annotation" which was marked by programmers
- static code analysis won't execute code, in other words, this tool don't need the runtime support and OS support.
- Why the static code analysis is popular in Embedded System?
- It's lightweight and no OS/platform dependency
- What's the downside?
- Static code analysis contain a lot of false positive
---
extension:
1. scale approximately linearly with the size of the program
2. Because of 1., full interprocedural analysis is expensive, instead, each **procedure is checked independently**
3. through detailed interface information which includes the parameter and return value, global variables
step:
1. get the annotation
2. check function body with annotation (check: return value, parameters, global variables used by the function)
3. after 2., be assumed to be true (mark? annotation to true?)
---
## 16.2 Basic Checks
### NULL
```/*@null*/ int num;``` Value of ```num``` could be ```NULL```.
```/*@null*/ int *fun(){}``` return of function ```fun``` could be ```NULL```.
### enum
enum is a datatype, for example:
```cpp=
enum Action{stop, sit, stand, walk, run};
//where stop = 1, sit = 2, stand = 3, etc.
Action action = stop;
printf("%d\n",action);
action = walk;
printf("%d\n",action);
action = stand;
printf("%d\n",action);
```
the output would be:
```cpp=
1
4
3
```
```/*@ -enumint @*/``` Cannot put ```int``` value directly into a ```enum``` datatype, for example:
```cpp=
/*@ -enumint @*/
Action action = 1;
```
Result in having warning ```Variable action initialized to type int```
### Summary:
Introduce some basic checking, for example:
1. NULL pointer
2. enumerated data type
3. boolean data type
4. control flow
| Flag | Effect |
|:---------- |:------ |
| useder | When set, it enables checks concerning the use of a location before it has been initialized |
| mustdefine | When this flag
| impotus |
| charint |
| charindex |
| enumint |
| enumindex |
| booltype |
| predboolptr |
| predboolint |
| predboolothers |
| eval-order |
| casebreak |
| misscase |
| noeffect |
| retvalint |
| retvalbool |
| retvalother |
---
| Annotations | Effect |
|:------------ |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| null | Applies to a pointer and states the assumption that it may be NULL |
| notnull | Applies to a pointer and states the assumption that is cannot be NULL |
| relnull | Relaxes NULL checks for the pointer it refers to. |
| nullwhentrue | This annotation is used for functions that check whether or not a pointer is NULL. This annotation indicates that when the return value of the function is true, then its first argument was a NULL pointer. |
| in | This annotation applies to a pointer and indicates that the storage reachable from it must be defined. |
| out | This annotation applies to pointer and indicates that the storage reachable from it need not be defined. |
| partial | This annotation indicates the storage reachable from the pointer it applies to, typically a struct, may be partially defined, that is, it may have undefined fields. |
---
## 16.3 Memory Management
Memory Management is a major source of bugs in C programs.
| Flag | Effect |
| -------------- | ------------------------------------------------------------------------------ |
| stackref | Checks about returning the address of variables allocated on the stack |
| compdef | Checks if a function returns a pointer to data which is not completely defined |
| immediatetrans | Checks for inconsistent immediate object address(```&``` operator) usage |
| mustfree | Checks for memory leaks (allocate without free) |
| usereleased | Checks if data been use after free |
### stackref
Local static variables are stored in a call stack, when the function's life cycle ends, the call frame is deallocated and all local data of that function are destroyed. ```stackerf``` checks if any pointer points to any of this destroyed data.
For example:
```cpp=
int *glob;
/*@dependent@*/ int *f (int **x){
int sa[2] = { 0, 1 };
int loc = 3;
glob = &loc;
*x = &sa[0];
return &loc;
}
```
```glob``` on line 5 pointed to local address ```&loc```, which will become a invalid address after ```*f``` ends.
```*x``` pointed to local array ```sa```, which is also invalid after ```*f``` ends.
```/*@dependent@*/``` is needed because there is a implicit ```/*@only@*/``` for ```*f```.
### compdef
Gives warning if function returns a pointer to data which is not completely defined.
For example:
```cpp=
int *f(/*@out@*/ int *x){
return x;
}
```
```/*@out@*/``` annotation tells that ```*x``` might not defined. Clearly ```*f``` returned a value which might not defined.
### immediatetrans
Gives warning if inconsistent immediate object address(```&``` operator) exist.
```cpp=
static int tem;
int *f(int *x){
x = &tem;
return x;
}
```
Since there is no annotation for ```*f```, the return value is assumed to be ```/*@ only @*/```. which means system lost the only pointer points to tem after ```*f``` return.
### mustfree
Provide memory leaks information.
```cpp=
void leak(){
int *ptr = malloc(sizeof(int));
if(ptr != NULL){
*ptr = 1;
}
//free(ptr);
return;
}
```
Allocate memory without free before return.
### usereleased
Check if system try to use memory which is freed already.
```cpp=
void leak(){
int *ptr = malloc(sizeof(int));
free(ptr);
if(ptr != NULL){
*ptr = 1;
}
return;
}
```
Use ```*ptr``` after free.
---
## test
```cpp
#include <stdlib.h>
#define ALLOC(n) (int *) malloc(n)
int main(){
int *p = ALLOC(4);
free(p);
int *t = malloc(3);
free(t);
return 0;
}
```
return
```
Splint 3.1.2 --- 03 May 2009
macroMalloc.c:5:17: Parse Error. (For help on parse errors, see splint -help
parseerrors.)
*** Cannot continue.
```
---
## 16.4 Buffer Overflows
TODO: Why is this unreliable?
| Flag | Effect |
| ----------------- | ----------------------------------------------------------------- |
| bounds | Set both boundsread and boundswrite |
| boundsread | Warning if attempt to read out of boundary, this is not reliable |
| boundswrite | Warning if attempt to wrtie out of boundary, this is not reliable |
| likelybounds | Set both likelyboundsread and boundswrite |
| likelyboundsread | Less powerful than boundsread, but less false warnings |
| likelyboundswrite | Less powerful than boundswrite, but less false warnings |
### boundswrite
#### False negative
```cpp=
void f(){
int buf[10];
buf[-1] = 0;
}
```
Cannot detect ```buf[-1]``` is out of range.
Probably because splint have ```maxset()``` and ```maxread()``` only, without ```minset()``` and ```minread()```.
#### False positive
```cpp=
void f(){
int *buf;
buf = malloc(sizeof(int)*5);
if(buf == NULL){
return;
}
memset(buf,0,sizeof(int)*4);
free(buf);
return;
}
```
False positive on memset.
```bounds.c:10:2: Possible out-of-bounds store: memset(buf, 0, sizeof(int) * 5)```
#### True positive
```cpp=
void f(){
int buf[10];
buf[10] = 0;
}
```
Catch ```buf[10]``` is out of range.
---
## 16.5 Function Interface Annotations
---
## 16.6 Summary
---
## Reference list
[1] Testing Static Analysis Tools UsingExploitable Buffer Overflows From Open Source Code [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.87.3364&rep=rep1&type=pdf]
[2] Splint the C code static checker(ppt) [https://www.slideshare.net/UlissesCosta/splint-the-c-code-static-checker]
[3] Splint github [https://github.com/splintchecker/splint]
[4] Static program analysis wikipedia [https://en.wikipedia.org/wiki/Static_program_analysis]
[5] Evans, D., & Larochelle, D. (2002). Improving security using extensible lightweight static analysis. IEEE Software, 19(1), 42–51. doi: 10.1109/52.976940
[6] Splint Publications [https://splint.org/pubs.html]
[7] Splint Bugs [https://splint.org/bugs.html]
[8] Evans, D. (1996). Static detection of dynamic memory errors. Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language Design and Implementation - PLDI 96. doi: 10.1145/231379.231389