プログラミング言語Cセキュアコーディング抜粋

C プログラミング言語セキュアコーディング標準

1つのソース

「SEI CERT Cスタンダード、2016年版のコーディング」

2 プリプロセッサPRE

2.2 危険なマクロパラメータの副作用を避けます

危険な機能マクロは、展開中に複数回使用またはパラメータを使用しないので、副作用のパラメータを持つ代入、インクリメント、デクリメント、入力、出力、およびその他の危険なマクロが含まれて呼び出すことはありません。

 

#define ABS(x)は(((X)<0) - (X):( x))を

INT、M = ABS(++ N)  

 

2.2.6NDEBUG&アサート()

アサート()マクロは、診断コードとテストを統合するための便利な機構です。アサートマクロ挙動はクラスオブジェクトマクロ定義に依存NDEBUG マクロ場合、NDEBUGが定義されていない、()アサート結果がある場合、マクロパラメータの発現値を計算します0 、通話中断()関数。マクロ場合NDEBUGが定義されている、アサート式にマクロパラメータがアサーションでカウントされません。

(i>が0 ++)を主張

 

3 宣言および初期化DCL

3.4 予約の識別子や定義を宣言しないでください

#ifndefの_MY_HEADER_H_

#define _MY_HEADER_H

静的定数size_tの_max_limit = 1024;  

#endifの/ * _ MY_HEADER_H _ * /

上記 _MY_HEADER_H_ _max_limitは、他の競合を定義する最初のアンダースコアを削除することができます。

 

3.5.2 構造動的サイズの正しい使い方

構造体flexArrayStruct {

   size_tのnum個。

   int型のデータ[]。

}。

ボイドFUNC(size_tのARRAY_SIZE){

   構造体flexArrayStruct * structP =(構造体flexArrayStruct *)

       malloc(はsizeof(構造体flexArrayStruct)+はsizeof(int型)* ARRAY_SIZE)。

   IF(NULL == structP){/ *ハンドルのmalloc失敗* /

   }

   structP-> NUM = ARRAY_SIZE。

   用は(size_t i = 0; I <ARRAY_SIZE; ++ I){

      structP->データ[I] = 1。

   }

}

 

3.6 情報漏洩を回避したときに、信頼境界を越え構造

これは、それらの構造は、アライメント因子ので、実際の大きさを占めることを意味する 12 コピー、コピー情報は、他の場所で満たされるとき、バイト。

構造体のテスト{

int型;

char型のB;

int型のC;

}。

extern int型copy_to_user(ボイド* dstは、void *型SRC、size_tのサイズ);

空do_stuff(void *型usr_buf){

構造体の試験のarg = {A = 1、.B = 2、.C = 3}。

copy_to_user(usr_buf, &arg, sizeof(arg));

}

解决办法之一,用结构体1字节对齐。

 

3.7.9 超长标识符

C99外部标识符最长为31的限制

 

3.8不要在switch语句第一个case前声明变量

变量i被实例化为块内部自动存储值,但初始化语句不会被执行。

switch(expr){

int i = 4;

f(i);

case 0:

i = 18;

default:

printf(“%d\n”,i);

}

 

4 表达式EXP

4.1.1不要依赖序列点之间的求值顺序

void func(int i, int *b){

int a = i + b[++i];

}

 

4.10.1不要比较填充数据

如下代码,如果结构体因为对齐有填充,不能用memcmp比较两个结构体的内容。

struct s{

char c;

int i;

char buffer[13];

};

void compare(const struct s*left, const struct s *right){

if (0 == memcmp(left, righe, sizeof(struct s))){

/**/

}

}

 

5 整数INT

5.1.1.1保证无符号整数操作不会出现回绕

加法保护

void func(unsigned int ui_a, unsigned int ui_b){

unsigned int usum;

if (UINT_MAX - ui_a < ui_b){

   /*Handle error*/

}else{

   usum = ui_a + ui_b;

}

}

 

5.1.2.1减法操作保护

void func(unsigned int ui_a, unsigned int ui_b){

unsigned int udiff;

if (ui_a < ui_b){

   /*Handle error*/

}else{

   udiff = ui_a - ui_b;

}

}

 

5.1.3.1 乘法操作保护

测试乘法的操作数,以保证不会出现回绕.

num_vertices = M;

if (num_vertices > SIZE_MAX / sizeof(vertex_t){

/*Handle error*/

}

vetices = malloc(num_vertices * sizeof(vertex_t));

 

5.2.9保证整型转换不会丢失或错误解释数据

time函数在表示当前日历时间无效时,会将-1转换为time_t类型后的值。如果time_t的精度小于signed int的无符号整数类型,那么下面转换有误。

void func(void){

time_t now = time(NULL);

if (now != -1){    /*应改为now != (time_t)-1*/

    /*....*/

}

}

 

5.3.3.1有符号整数加法保护

两端都要做溢出保护

void func(signed int si_a, signed int si_b){

signed int sum;

if(((si_b > 0)&& (si_a > (INT_MAX -si_b))) ||

  ((si_b < 0)&&(si_a < (INT_MIN-si_b)))){

/*Handle error*/

    }else{

      sum = si_a + si_b;

}

}

 

5.4.1有符号除法保护

void func(signed long s_a, signed long s_b){

   signed long result;

   if ((s_b ==0) || ((s_a == LONG_MIN)&&(s_b == -1))){

   }else{

       result = s_a / s_b;

   }

}

 

5.5.2不要将表达式移动负数位或者移动大于等于操作数中存在的位数

无符号类型左位移保护

#include <limits.h>

#include <stddef.h>

#include <inttypes.h>

extern size_t popcount(uintmax_t);

#define PRECISION(x) popcount(x)

 

void func(unsigned int ui_a, unsigned int ui_b){

   unsigned int uresult = 0;

   if (ui_b >= PRECISION(UINT_MAX)){

      /*Handle error*/

   }else{

      uresult = ui_a << ui_b;

   }

}

 

5.6.1使用正确的整数精度

C中整数类型包含大小和精度两部分,大小表示一个对象使用的字节数,可以通过sizeof得到。一个整数类型的精度是它用来表示值的位数,不包括任何符号位和填充位。

例如,在一个平台上用64位来存储无符号整数,但仅用48位表示值,左移56位将导致未定义的行为。

6 浮点数FLP

6.1.1不要用浮点数作为循环计数器

void func(void){

for(float x = 0.1f; x <= 1.0f; x+= 0.1f){

/*Loop may iterate 9 or 10times*/

}

}

 

6.1.3 浮点数精度导致死循环

for(float x = 100000001.0f; x <= 100000010.0f; x += 1.0f){

/*Loop may not terminate*/

}

 

6.3.2floatint要确保float值的范围适合int

extern size_t popcount(uintmax_t);

#define PRECISION(umax_value) popcount(umax_value)

void func(float f_a){

int i_a;

if (PRECISION(INT_MAX) < log2f(fabsf(f_a)) ||

   (f_a != 0.0F && fabs(f_a) < FLT_MIN)){

/*Handle error */

}else{

  i_a = f_a;

}

}

 

6.5.1不要使用对象表示来比较浮点值

-0.0 0.0是等价的,但是对象表示中使用的位模式是不相同的。

struct S{

  int i;

  float f;

};

bool are_equal(const struct S *s1, const struct S *s2){

  if (!s1 && !s2)return true;

  else if (!s1 || !s2) return false;

  return 0 == memcmp(s1, s2, sizeof(struct S));

}

 

7 数组ARR

7.1.8索引超出范围的访问

多维数组访问时,数组下标不要搞混了。

 

7.2.4确保变长数组的大小参数在有效范围内

enum {N1 = 4096};

void *func(size_t n2){

if (n2 > SIZE_MAX/(N1*sizeof(int))){

    return NULL;

}

typedef int A[n2][N1];

A *array = malloc(sizeof(A));

if (!array){

    return NULL;

}

/*init*/

return array;

}

 

8 字符和字符串STR

8.1.1不要试图修改字符串常量

char *p = “string literals”;

p[0] = ‘S’; //未定义行为

 

8.2保证字符串的存储具有足够的空间容纳字符数据和null结尾符

void copy(size_t n, char src[n], char dest[n]){

   size_t i;

   for (i = 0; src[i] && (i < n-1); ++i){  //合规解决方法

      dest[i] = src[i];

   }

   dest[i] = ‘\0’;

}

 

8.2.9 fscanf()合规方法,防止缓冲区溢出

void get_data(void){

char buf[1024];

if (1 != fscanf(stdin, “%1023s”, buf)){

   /*Handle error*/

}

}

 

8.3不要将非null结尾的字符序列当做字符串传递给库函数

void func(void){

char c_str[3] = “abc”;

printf(“%s\n”,c_str); /*没有null结尾的字符序列,传给了printf*/

}

 

9 内存管理MEM

9.3.5含有灵活数据成员的结构拷贝

struct flex_array_struct{

size_t num;

int data[];

};

void print_array(struct flex_array_struct struct_p){

for (size_t i = 0; i < struct_p.num; ++i){

    printf(“%d”, struct_p.data[i]);  /*error当以传值方式传递入参时,灵活数组成员的大小不会被考虑,因此,只有num被拷贝*/

}

}

 

9.4.3只释放动态分配的内存

下面的不合规代码中,realloc的参数,buf不是指向动态分配的内存。

char buf[1024];

char *p = (char *)realloc(buf, 2048);  /*error*/

 

9.5.4为对象分配足够的内存

struct tm *tmb;

tmb = (struct tm *)malloc(sizeof(tmb)); /*错误,只申请了指针所占的大小*/

 

9.6不要使用realloc()修改对齐的内存

おすすめ

転載: www.cnblogs.com/sunnypoem/p/11368473.html