• 主页
  • 相册
  • 随笔
  • 目录
  • 存档
Total 244
Search AboutMe

  • 主页
  • 相册
  • 随笔
  • 目录
  • 存档

软件安全备忘录:CERT C Coding Standard笔记

2022-04-08

1. Expressions (EXP)

1.1. EXP30-C. Do not depend on the order of evaluation for side effects

At specific points during execution, known as sequence points, all side effects of previous evaluations are complete, and no side effects of subsequent evaluations have yet taken place. Do not depend on the order of evaluation for side effects unless there is an intervening sequence point

1
2
3
4
/* i is modified twice between sequence points */ 
i = ++i + 1;
/* i is read other than to determine the value to be stored */
a[i++] = i;
  • Attempting to modify an object multiple times between sequence points may cause that object to take on an unexpected value, which can lead to unexpected program behavior

1.1.1. 副作用

在产生一个值的过程中,表达式可能会对环境做出其他改变,这样的改变被称为副作用(side effect),诸如变量的值被修改,或者输入输出流的数据有所变化

  • 表达式x + 1;就产生了一个值,但是它没有产生一个副作用
  • 表达式x = x+ 3;产生了一个值,同时也会产生一个副作用

1.2. EXP32-C. Do not access a volatile object through a nonvolatile reference

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h> 
void func(void) {
static volatile int **ipp;
static int *ip;
static volatile int i = 0;
printf("i = %d.\n", i);
ipp = &ip; /* May produce a warning diagnostic */
ipp = (int**) &ip; /* Constraint violation; may produce a warning diagnostic */
*ipp = &i; /* Valid */
if (*ip != 0) { /* Valid */
/* ... */
}
}

The assignment ipp = &ip is not safe because it allows the valid code that follows to reference the value of the volatile object i through the non-volatile-qualified reference ip

  • Accessing an object with a volatile-qualified type through a reference with a non-volatile-qualified type is undefined behavior

1.3. EXP33-C. Do not read uninitialized memory

Although compilers and static analysis tools often detect uses of uninitialized variables when they have access to the source code, diagnosing the problem is difficult or impossible when either the initialization or the use takes place in object code for which the source code is inaccessible.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int is_negative(int number) {
int sign;
set_flag(number, &sign);
return sign < 0;
}



int *array = (int *)malloc(OLD_SIZE * sizeof(int));
if (0 == array) {
/* Handle error */
}
for (size_t i = 0; i < OLD_SIZE; ++i) {
array[i] = i;
}
  • The programmer neglected to account for the case where number is equal to 0. Because the local variable sign is uninitialized when calling set_flag() and is never written to by set_flag(), the comparison operation exhibits undefined behavior when reading sign.
  • Reading uninitialized variables is undefined behavior and can result in unexpected program behavior. In some cases, these security flaws may allow the execution of arbitrary code.

1.4. EXP34-C. Do not dereference null pointers

Dereferencing a null pointer is undefined behavior

  • Dereferencing a null pointer is undefined behavior, typically abnormal program termination. In some situations, however, dereferencing a null pointer can lead to the execution of arbitrary code

1.5. EXP35-C. Do not modify objects with temporary lifetime

The C11 Standard introduced a new term: temporary lifetime. Modifying an object with temporary lifetime is undefined behavior

  • the structure or union contains a member with array type (including, recursively, members of all contained structures and unions) refers to an object with automatic storage duration and temporary lifetime.

This noncompliant code example conforms to the C11 Standard; however, it fails to conform to C99. If compiled with a C99-conforming implementation, this code has undefined behavior because the sequence point preceding the call to printf() comes between the call and the access by printf() of the string in the returned object

  • 也就是说C99下先后顺序不确定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct X { char a[8]; };
struct X salutation(void) { struct X result = { "Hello" }; return result;
}
struct X addressee(void) { struct X result = { "world" }; return result;
}

/*Noncompliant*/
int main(void) {
printf("%s, %s!\n", salutation().a, addressee().a);
}

/*Compliant*/
int main(void) {
struct X my_salutation = salutation();
struct X my_addressee = addressee();
printf("%s, %s!\n", my_salutation.a, my_addressee.a);
}
  • Attempting to modify an array or access it after its lifetime expires may result in erroneous program behavior

1.6. EXP36-C. Do not cast pointers into more strictly aligned pointer types

Do not convert a pointer value to a pointer type that is more strictly aligned than the referenced type. Different alignments are possible for different types of objects. If the type-checking system is overridden by an explicit cast or the pointer is converted to a void pointer (void *) and then to a different type, the alignment of an object may be changed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <assert.h>
void func(void) {
char c = 'x';
int *ip = (int *)&c; /* This can lose information */
char *cp = (char *)ip;
/* Will fail on some conforming implementations */
assert(cp == &c);
}


// 正确的
{
int i = c;
int *ip = &i;
assert(ip == &i);
}

  • the char pointer &c is converted to the more strictly aligned int pointer ip. On some implementations, cp will not match &c.
  • Accessing a pointer or an object that is not properly aligned can cause a program to crash or give erroneous information, or it can cause slow pointer accesses (if the architecture allows misaligned accesses).

1.6.1. EXP36-C-EX2

If a pointer is known to be correctly aligned to the target type, then a cast to that type is permitted. There are several cases where a pointer is known to be correctly aligned to the target type. The pointer could point to an object declared with a suitable alignment specifier. It could point to an object returned by aligned_alloc(), calloc(), malloc(), or realloc()

1
2
3
4
5
6
7
8
9
10
#include <stdalign.h> 
#include <assert.h>
void func(void) {
/* Align c to the alignment of an int */
alignas(int) char c = 'x';
int *ip = (int *)&c;
char *cp = (char *)ip;
/* Both cp and &c point to equally aligned objects */
assert(cp == &c);
}

1.7. EXP37-C. Call functions with the correct number and type of arguments

  • Do not call a function with the wrong number or type of arguments.
1
2
3
4
5
6
7
8
9
/* In another source file */ 
long f(long x) { return x < 0 ? -x : x;}

/* In this source file, no f prototype in scope */
long f();
long g(int x) {
return f(x); // wrong
return f((long)x); //correct
}
  • Calling a function with incorrect arguments can result in unexpected or unintended program behavior

1.8. EXP39-C. Do not access a variable through a pointer of an incompatible type

  • Modifying a variable through a pointer of an incompatible type (other than unsigned char) can lead to unpredictable results
  • Accessing an object by means of any other lvalue expression (other than unsigned char) is undefined behavior
  • Optimizing for performance can lead to aliasing errors that can be quite difficult to detect. Furthermore, as in the preceding example, unexpected results can lead to buffer overflow attacks, bypassing security checks, or unexpected execution.

1.9. EXP40-C. Do not modify constant objects

1
2
3
4
5
6
7
8
const int **ipp; 
int *ip;
const int i = 42;
void func(void) {
ipp = &ip; /* Constraint violation */
*ipp = &i; /* Valid */
*ip = 0; /* Modifies constant i (was 42) */
}

1.10. EXP42-C. Do not compare padding data

  • There may be unnamed padding within a structure object, but not at its beginning. . . .
  • There may be unnamed padding at the end of a structure or union.
  • unnamed members of objects of structure and union type do not participate in initialization. Unnamed members of structure objects have indeterminate value even after initialization
    • 结构和联合类型的对象的未命名成员不参与初始化。结构体对象的未命名成员在初始化后也有不确定的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct s { 
char c;
int i;
char buffer[13];
};

//wrong
void compare(const struct s *left, const struct s *right) {
if (0 == memcmp(left, right, sizeof(struct s))) {
/* ... */
}
}

//correct
void compare(const struct s *left, const struct s *right) {
if ((left && right) && (left->c == right->c)
&& (left->i == right->i)
&& (0 == memcmp(left->buffer, right->buffer, 13))) {
/* ... */
}
}
  • memcmp() is used to compare the contents of two structures, including any padding bytes

1.10.1. EXP42-C-EX1

1.11. EXP43-C. Avoid undefined behavior when using restrict-qualified pointers

  • deleting all instances of the qualifier from a program does not change its meaning (that is, observable behavior).

  • undefined behavior:

    A restrict-qualified pointer is assigned a value based on another restricted pointer whose associated block neither began execution before the block associated with this pointer, nor ended before the assignment

  • restrict says that two pointers cannot point to overlapping重叠的 memory regions. The most common usage is for function arguments.

1
2
3
4
5
6
7
8
9
10
11
12
13
int *restrict a; 
int *restrict b;

extern int c[];

int main(void) {
c[0] = 17;
c[1] = 18;
a = &c[0];
b = &c[1];
a = b; /* Undefined behavior */
/* ... */
}
  • The incorrect use of restrict-qualified pointers can result in undefined behavior that might be exploited to cause data integrity violations.

1.12. EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic

  • Some operators do not evaluate their operands beyond the type information the operands provide. When using one of these operators, do not pass an operand that would otherwise yield a side effect since the side effect will not be generated.
  • The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. In most cases, the operand is not evaluated.
    • A possible exception is when the type of the operand is a variable length array type(VLA)
    • 然而in the case of a VLA used in sizeof, have unspecified results
    • 所以结论还是不要在sizeof里副作用VLA
1
2
int a = 14;
int b = sizeof(a++);
  • expression a++ is not evaluated计算

1.13. EXP45-C. Do not perform assignments in selection statements

1
2
3
4
5
if (a = b) { 
/* ... */
}

do { /* ... */ } while (foo(), x = y);

1.13.1. EXP45-C-EX2

1
if ((x = y)) { /* ... */ }

1.14. EXP46-C. Do not use a bitwise operator with a Boolean-like operand

  • 混淆了&和&&
    • The expression x & y will perform a bitwise operation on each individual bit in x and y. So if x is 1010 in binary and y is 1100 then x & y will evaluate to 1000.
1
2
3
4
5
if (!(getuid() & geteuid() == 0)) { /* ... */
}

if (!(getuid() && geteuid() == 0)) { /* ... */
}

1.15. Risk Assessment

RuleSeverityLikelihoodRemediation CostPriorityLevel
EXP30-CMediumProbableMediumP8L2
EXP32-CLowLikelyMediumP6L2
EXP33-CHighProbableMediumP12L1
EXP34-CHighLikelyMediumP18L1
EXP35-CLowProbableMediumP4L3
EXP36-CLowProbableMediumP4L3
EXP37-CMediumProbableHighP4L3
EXP39-CMediumUnlikelyHighP2L3
EXP40-CLowUnlikelyMediumP2L3
EXP42-CMediumProbableMediumP8L2
EXP43-CMediumProbableHighP4L3
EXP44-CLowUnlikelyLowP3L3
EXP45-CLowLikelyMediumP6L2
EXP46-CLowLikelyLowP9L2

2. Memory (Mem)

.

3. Array (ARR)

.

  • sec
  • Security
  • Software Security
ESBMC-An Efficient SMT-based Software Model Checker
软件安全备忘录:Mem Management
  1. 1. 1. Expressions (EXP)
    1. 1.1. 1.1. EXP30-C. Do not depend on the order of evaluation for side effects
      1. 1.1.1. 1.1.1. 副作用
    2. 1.2. 1.2. EXP32-C. Do not access a volatile object through a nonvolatile reference
    3. 1.3. 1.3. EXP33-C. Do not read uninitialized memory
    4. 1.4. 1.4. EXP34-C. Do not dereference null pointers
    5. 1.5. 1.5. EXP35-C. Do not modify objects with temporary lifetime
    6. 1.6. 1.6. EXP36-C. Do not cast pointers into more strictly aligned pointer types
      1. 1.6.1. 1.6.1. EXP36-C-EX2
    7. 1.7. 1.7. EXP37-C. Call functions with the correct number and type of arguments
    8. 1.8. 1.8. EXP39-C. Do not access a variable through a pointer of an incompatible type
    9. 1.9. 1.9. EXP40-C. Do not modify constant objects
    10. 1.10. 1.10. EXP42-C. Do not compare padding data
      1. 1.10.1. 1.10.1. EXP42-C-EX1
    11. 1.11. 1.11. EXP43-C. Avoid undefined behavior when using restrict-qualified pointers
    12. 1.12. 1.12. EXP44-C. Do not rely on side effects in operands to sizeof, _Alignof, or _Generic
    13. 1.13. 1.13. EXP45-C. Do not perform assignments in selection statements
      1. 1.13.1. 1.13.1. EXP45-C-EX2
    14. 1.14. 1.14. EXP46-C. Do not use a bitwise operator with a Boolean-like operand
    15. 1.15. 1.15. Risk Assessment
  2. 2. 2. Memory (Mem)
  3. 3. 3. Array (ARR)
© 2024 何决云 载入天数...