Browse Source

Update coding guide

pull/260/head
liuchongming 3 years ago
parent
commit
bc490feb1c
4 changed files with 350 additions and 193 deletions
  1. +71
    -0
      security/code_review_checklist_mechanism.md
  2. +116
    -98
      security/coding_guild_cpp_en.md
  3. +119
    -95
      security/coding_guild_cpp_zh_cn.md
  4. +44
    -0
      security/security_coding_violation_cases.md

+ 71
- 0
security/code_review_checklist_mechanism.md View File

@@ -0,0 +1,71 @@
# 代码检视Checklist运作机制(试运行)

## 目标

代码检视 Checklist 诣在辅助 Committer 进行高质量代码检视,同时为开发者提供代码自检的参考指南。

## Checklist 说明

代码检视 Checklist 分为 **必选** 与 **可选** 两节,其中:

### 必检项:

必选检查项位于**Code review checklist**下,为 Committer 代码Review的常规检查项,Committer 确认无问题后请在 CheckBox 勾选以表明完成对应检查(若当前 Pull request
不涉及某项,无须勾选);若当前 Pull request 涉及 **【性能分析】**中某子项、**【是否涉及模块/特性间交互】**,请开发者概述设计思想或实现方案。

- **Typical problems of security
coding [[historical security coding cases reference]](https://gitee.com/mindspore/community/blob/master/security/security_coding_violation_cases.md)**
- [ ] whether to verify the pointer is null/nullptr
- [ ] whether to verify the function's return value
- [ ] whether new/malloc memory is released correctly
- **Performance analysis (if a sub-item is involved, please outline the implementation idea or modification content)**
- [ ] whether to modify hotspot ***function / algorithm / operation***
- [ ] whether to consider concurrent scenarios
- [ ] whether to consider communication scenario

- - [ ] **Whether to comply with coding
specifications [[coding specification reference]](https://gitee.com/mindspore/community/blob/master/security/coding_guild_cpp_zh_cn.md)**
- - [ ] **Whether to comply with ***SOLID principle / Demeter's law*****
- - [ ] **Whether the ***interaction between modules / features*** is involved (if yes, please outline the
implementation ideas)**
- - [ ] **Whether there is UT test case && the test case is a valid (if there is no test case, please explain the
reason)**
- - [ ] **whether the secret key is loaded/released correctly**

- **Error handling and recording**
- [ ] whether the interface exception scenarios are fully considered
- [ ] whether the error is recorded appropriately

### 可选检查项:

若当前Pull request涉及 **【是否导致无法前向兼容】**、**【是否为对外接口变更】**、**【是否涉及依赖的三方库变更】**
中某项,请将对应可选项的注释去掉,并增加对应的评审结论,如:”已于YYYY/MM/dd在SEG通过评审“;若涉及对外文档变更,请将**【是否涉及文档(安装、教程、设计、参考、API、迁移指南、FAQ等)修改】**
的注释打开,并附上文档变更的Pull request。

- [ ] **Whether document (installation, tutorial, design, reference, API, migration guide, FAQ, etc.) modification
is involved**
- - [ ] **Whether it causes forward compatibility failure**
- - [ ] **Whether the API change is involved**
- - [ ] **Whether the dependent third-party library change is involved**

## 代码检视 Checklist 中英文参照表

| 检视项 | checklist |
| ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| 是否进行空指针校验 | whether to verify the pointer is null/nullptr |
| 是否进行返回值校验 | whether to verify the function's return value |
| 是否正确释放new/malloc内存 | whether new/malloc memory is released correctly |
| 是否修改热点函数/算法/算子 | whether to modify hotspot function / algorithm / operation |
| 是否考虑并发场景 | whether to consider concurrent scenarios |
| 是否考虑通信场景 | whether to consider communication scenario |
| 是否符合编码规范 【编码规范】 | Whether to comply with coding specifications [coding specification reference] |
| 是否遵守SOLID原则/迪米特法则 | Whether to comply with SOLID principle / Demeter's law |
| 是否涉及模块/特性间交互【若涉及请概述实现思路】 | Whether the interaction between modules / features is involved (if yes, please outline the implementation ideas) |
| 是否具备UT测试用例看护 && 测试用例为有效用例【若无测试用例请说明原因】 | Whether there is UT test case && the test case is a valid (if there is no test case, please explain the reason) |
| 秘钥是否被正确加载、释放 | whether the secret key is loaded/released correctly |
| 是否充分考虑接口的异常场景 | whether the interface exception scenarios are fully considered |
| 是否正确记录错误信息 | whether the error is recorded appropriately |
| 是否涉及文档(安装、教程、设计、参考、API、迁移指南、FAQ等)修改 | Whether document (installation, tutorial, design, reference, API, migration guide, FAQ, etc.) modification is involved |
| 是否导致无法前向兼容 | Whether it causes forward compatibility failure |
| 是否为对外接口变更 | Whether the API change is involved |
| 是否涉及依赖的三方库变更 | Whether the dependent third-party library change is involved |

+ 116
- 98
security/coding_guild_cpp_en.md View File

@@ -51,7 +51,7 @@ C++ files are named in the format of lowercase letters + underscores (_). The fi
> a_b_c.cc
> a_b_c_test.cc
##### Rule 1.1.2 Use lowercase letters and underscores (_) to name local variables and parameters.
##### Rule 1.1.2 Use lowercase letters and underscores (_) to name local variables and parameters
```cpp
void FooBar(int func_param) {
@@ -59,7 +59,7 @@ void FooBar(int func_param) {
}
```
##### Rule 1.1.3 Use lowercase letters and underscores (_) to name member variables, with an underscore (_) as the suffix.
##### Rule 1.1.3 Use lowercase letters and underscores (_) to name member variables, with an underscore (_) as the suffix
```cpp
class FooBar {
@@ -68,7 +68,7 @@ class FooBar {
};
```
##### Rule 1.1.4 Use uppercase letters and underscores (_) in macro names.
##### Rule 1.1.4 Use uppercase letters and underscores (_) in macro names
```cpp
#define MS_LOG(...)
@@ -86,22 +86,42 @@ enum UrlTableErrors {
};
```
##### Rule 1.1.6 Naming of function
1. Class member variable accessor:naming of accessor should comply with naming rule of variables and parameters, such as:
```c++
int count() {return this->count_;}
```
2. Class member variable modifier:naming of modifier should be started with `set_` and followed by variables or parameters name, such as:
```c++
void set_count(int count) {this->count_ = count;}
```
3. Other class member functions/common functions: named based on the large hump rules, such as:
```c++
void FindPattern(...);
```
#### <a name="fmt">1.2 Format</a>
##### Recommendation 1.2.1 Each line contains a maximum of 120 characters.
##### Recommendation 1.2.1 Each line contains a maximum of 120 characters
If a line contains more than 120 characters, start a new line properly.
##### Rule 1.2.2 Use spaces to indent, two at a time.
##### Rule 1.2.2 Use spaces to indent, two at a time
##### Rule 1.2.3 When declaring a pointer or referencing variables or parameters, follow variable names with `&` and `*` and place a space on the other side.
##### Rule 1.2.3 When declaring a pointer or referencing variables or parameters, follow variable names with `&` and `*` and place a space on the other side
```cpp
char *c;
const std::string &str;
```
##### Rule 1.2.4 Use braces to include an if statement.
##### Rule 1.2.4 Use braces to include an if statement
```cpp
// Even if the if branch code is within one line, braces are required.
@@ -110,9 +130,9 @@ if (cond) {
}
```
##### Rule 1.2.5 Use braces for loop statements such as for and while statements, even if the loop body is empty or there is only one loop statement.
##### Rule 1.2.5 Use braces for loop statements such as for and while statements, even if the loop body is empty or there is only one loop statement
##### Rule 1.2.6 Keep a consistent line break style for expressions and ensure that operators are placed at the end of a line.
##### Rule 1.2.6 Keep a consistent line break style for expressions and ensure that operators are placed at the end of a line
```cpp
int a = a_very_long_expression +
@@ -120,7 +140,7 @@ int a = a_very_long_expression +
a_very_very_very_long_expression;
```
##### Rule 1.2.7 Each variable definition or assignment statement occupies one line.
##### Rule 1.2.7 Each variable definition or assignment statement occupies one line
```cpp
a = 1;
@@ -130,11 +150,11 @@ c = 3;
#### <a name="nts">1.3 Comment</a>
##### Rule 1.3.1 File header comments contain copyright statements.
##### Rule 1.3.1 File header comments contain copyright statements
All .h and .cc files must contain the following copyright statements:
```cpp
```cpp
/**
* Copyright 2019 Huawei Technologies Co., Ltd
*
@@ -150,14 +170,13 @@ All .h and .cc files must contain the following copyright statements:
* See the License for the specific language governing permissions and
* limitations under the License.
*/
```
> Notes:
> Files created in 2020 should contain `Copyright 2020 Huawei Technologies Co., Ltd`.
> Files created in 2019 and modified in 2020 should contain `Copyright 2019-2020 Huawei Technologies Co., Ltd`.
##### Rule 1.3.2 A comment is placed above or to the right of the code. There must be a space between the comment character and the comment content, and at least one space between the code and its comment on the right. Use `//`, not `/**/`.
##### Rule 1.3.2 A comment is placed above or to the right of the code. There must be a space between the comment character and the comment content, and at least one space between the code and its comment on the right. Use `//`, not `/**/`
```cpp
// this is multi-
@@ -165,34 +184,33 @@ All .h and .cc files must contain the following copyright statements:
int foo; // this single-line comment
```
##### Rule 1.3.3 Do not use comments such as TODO, TBD, and FIXME in code. You are advised to submit an issue for tracking.
##### Rule 1.3.3 Do not use comments such as TODO, TBD, and FIXME in code. You are advised to submit an issue for tracking
##### Recommendation 1.3.4 Function header comments with no content are forbidden.
##### Recommendation 1.3.4 Function header comments with no content are forbidden
Not all functions require header comments. You are advised to use the name of the function as its comment and write header comments if there is the need. For the information that cannot be expressed by the function prototype but is expected to be known by readers, function header comments are required.
Do not write useless or redundant function headers. The function header comments are optional, including but not limited to function description, return values, performance constraints, usage, memory conventions, algorithm implementation, and reentrant requirements.
### <a name="cc">2. General Coding</a>
#### <a name="cdes">2.1 Code Design</a>
##### Rule 2.1.1 Check the validity of all external data, including but not limited to function input parameters, external input named lines, files, environment variables, and user data.
##### Rule 2.1.1 Check the validity of all external data, including but not limited to function input parameters, external input named lines, files, environment variables, and user data
##### Rule 2.1.2 When transferring function execution results, preferentially use return values and avoid output parameters.
##### Rule 2.1.2 When transferring function execution results, preferentially use return values and avoid output parameters
```cpp
FooBar *Func(const std::string &in);
```
##### Rule 2.1.3 Delete invalid, redundant, or never-executed code.
##### Rule 2.1.3 Delete invalid, redundant, or never-executed code
Although most modern compilers in many cases can alert you to invalid or never executed code, responding alarms should be identified and cleared.
Identify and delete invalid statements or expressions from the code.
##### Rule 2.1.4 Follow additional specifications to the C++ exception mechanism.
##### Rule 2.1.4 Follow additional specifications to the C++ exception mechanism
###### Rule 2.1.4.1 Specify the types of exceptions to be captured. Do not capture all exceptions.
###### Rule 2.1.4.1 Specify the types of exceptions to be captured. Do not capture all exceptions
```cpp
// Incorrect
@@ -211,7 +229,7 @@ try {
#### <a name="inc">2.2 Header File and Preprocessing</a>
##### Rule 2.2.1 Use the new standard C++ header file.
##### Rule 2.2.1 Use the new standard C++ header file
```cpp
// Correct
@@ -220,25 +238,24 @@ try {
#include <stdlib.h>
```
##### Rule 2.2.2 Header file cyclic dependency is forbidden.
##### Rule 2.2.2 Header file cyclic dependency is forbidden
An example of cyclic dependency (also known as circular dependency) is: a.h contains b.h, b.h contains c.h, and c.h contains a.h. If any of these header files is modified, all code containing a.h, b.h, and c.h needs to be recompiled.
The cyclic dependency of header files reflects an obviously unreasonable architecture design, which can be avoided through optimization.
##### Rule 2.2.3 Do not include unnecessary header files.
##### Rule 2.2.4 It is prohibited to reference external function interfaces and variables in extern declaration mode.
##### Rule 2.2.3 Do not include unnecessary header files
##### Rule 2.2.5 Do not include header files in extern "C".
##### Rule 2.2.4 It is prohibited to reference external function interfaces and variables in extern declaration mode
##### Rule 2.2.6 Do not use "using" to import namespace in a header file or before #include statements.
##### Rule 2.2.5 Do not include header files in extern "C"
##### Rule 2.2.6 Do not use "using" to import namespace in a header file or before #include statements
#### <a name="dtype">2.3 Data Type</a>
##### Recommendation 2.3.1 Do not abuse typedef or #define to alias basic types.
##### Recommendation 2.3.1 Do not abuse typedef or #define to alias basic types
##### Rule 2.3.2 Use “using” instead of typedef to define the alias of a type to avoid shot-bomb modification caused by type changes.
##### Rule 2.3.2 Use “using” instead of typedef to define the alias of a type to avoid shot-bomb modification caused by type changes
```cpp
// Correct
@@ -249,15 +266,15 @@ typedef std::shared_ptr<FooBar> FooBarPtr;
#### <a name="cons">2.4 Constant</a>
##### Rule 2.4.1 Do not use macros to replace constants.
##### Rule 2.4.1 Do not use macros to replace constants
##### Rule 2.4.2 Do not use magic numbers or character strings.
##### Rule 2.4.2 Do not use magic numbers or character strings
##### Recommendation 2.4.3 Ensure that a constant has only one responsibility.
##### Recommendation 2.4.3 Ensure that a constant has only one responsibility
#### <a name="var">2.5 Variable</a>
##### Recommendation 2.5.1 Use namespaces to manage global constants. If the global constants are closely tied to a class, you can use static member constants to manage them.
##### Recommendation 2.5.1 Use namespaces to manage global constants. If the global constants are closely tied to a class, you can use static member constants to manage them
```cpp
namespace foo {
@@ -270,17 +287,17 @@ namespace foo {
}
```
##### Rule 2.5.2 Do not use global variables. Use the singleton pattern cautiously to avoid abuse.
##### Rule 2.5.2 Do not use global variables. Use the singleton pattern cautiously to avoid abuse
##### Rule 2.5.3 A variable cannot be referenced again if it is contained in an increment or decrement operation in an expression.
##### Rule 2.5.3 A variable cannot be referenced again if it is contained in an increment or decrement operation in an expression
##### Rule 2.5.4 After the resource is released, immediately assign a new value to the pointer variable that points to a resource handle or descriptor, or set the value to NULL.
##### Rule 2.5.4 After the resource is released, immediately assign a new value to the pointer variable that points to a resource handle or descriptor, or set the value to NULL
##### Rule 2.5.5 Do not use uninitialized variables.
##### Rule 2.5.5 Do not use uninitialized variables
#### <a name="exp">2.6 Expression</a>
##### Recommendation 2.6.1 When comparing expressions, follow the principle that the left side tends to change and the right side tends to remain unchanged.
##### Recommendation 2.6.1 When comparing expressions, follow the principle that the left side tends to change and the right side tends to remain unchanged
```cpp
// Correct
@@ -294,7 +311,7 @@ if (SUCCESS != ret) {
}
```
##### Rule 2.6.2 Use parentheses to specify the operator precedence to avoid rookie errors.
##### Rule 2.6.2 Use parentheses to specify the operator precedence to avoid rookie errors
```cpp
// Correct
@@ -310,31 +327,28 @@ if (cond1 || cond2 && cond3) {
#### <a name="exc">2.7 Conversion</a>
##### Rule 2.7.1 Use the type casting provided by the C++ instead of the C style. Do not use const_cast and reinterpret_cast.
##### Rule 2.7.1 Use the type casting provided by the C++ instead of the C style. Do not use const_cast and reinterpret_cast
#### <a name="ctrl">2.8 Control Statement</a>
##### Rule 2.8.1 A switch statement must have a default branch.
##### Rule 2.8.1 A switch statement must have a default branch
#### <a name="init">2.9 Declaration and Initialization</a>
##### Rule 2.9.1 Do not use `memcpy_s` or `memset_s` to initialize non-POD objects.
##### Rule 2.9.1 Do not use `memcpy_s` or `memset_s` to initialize non-POD objects
#### <a name="ptr">2.10 Pointer and Array</a>
##### Rule 2.10.1 Do not use the pointer returned by c_str () of std::string.
##### Rule 2.10.1 Do not use the pointer returned by c_str () of std::string
```cpp
// Incorrect
const char * a = std::to_string(12345).c_str();
```
##### Rule 2.10.2 Prefer `unique_ptr` to `shared_ptr`.
##### Rule 2.10.2 Prefer `unique_ptr` to `shared_ptr`
##### Rule 2.10.3 Create `shared_ptr` by using `std::make_shared` instead of `new`.
##### Rule 2.10.3 Create `shared_ptr` by using `std::make_shared` instead of `new`
```cpp
// Correct
@@ -343,13 +357,13 @@ std::shared_ptr<FooBar> foo = std::make_shared<FooBar>();
std::shared_ptr<FooBar> foo(new FooBar());
```
##### Rule 2.10.4 Use a smart pointer to manage objects. Do not use new or delete.
##### Rule 2.10.4 Use a smart pointer to manage objects. Do not use new or delete
##### Rule 2.10.5 Do not use auto_ptr.
##### Rule 2.10.5 Do not use auto_ptr
##### Rule 2.10.6 For formal parameters of pointer and reference types, if the parameters do not need to be modified, use const.
##### Rule 2.10.6 For formal parameters of pointer and reference types, if the parameters do not need to be modified, use const
##### Rule 2.10.7 Use the array length as a function parameter when the array is a function parameter.
##### Rule 2.10.7 Use the array length as a function parameter when the array is a function parameter
```cpp
int ParseMsg(BYTE *msg, size_t msgLen) {
@@ -357,17 +371,17 @@ int ParseMsg(BYTE *msg, size_t msgLen) {
}
```
#### <a name="str">2.11 String</a>
#### <a name="str">2.11 String</a>
##### Rule 2.11.1 When saving a string, ensure that it has '\0' at the end.
##### Rule 2.11.1 When saving a string, ensure that it has '\0' at the end
#### <a name="ast">2.12 Assert</a>
##### Rule 2.12.1 Assert cannot be used to verify errors that may occur when the program is running. To handle possible running errors, use error processing code.
##### Rule 2.12.1 Assert cannot be used to verify errors that may occur when the program is running. To handle possible running errors, use error processing code
#### <a name="cls">2.13 Class and Object</a>
##### Rule 2.13.1 When a single object is released, delete is used. When an array object is released, delete [] is used.
##### Rule 2.13.1 When a single object is released, delete is used. When an array object is released, delete [] is used
```cpp
const int kSize = 5;
@@ -379,9 +393,10 @@ number_array = nullptr;
delete number;
number = nullptr;
```
##### Rule 2.13.2 Do not use std::move to operate the const object.
##### Rule 2.13.3 Strictly use virtual/override/final to modify virtual functions.
##### Rule 2.13.2 Do not use std::move to operate the const object
##### Rule 2.13.3 Strictly use virtual/override/final to modify virtual functions
```cpp
class Base {
@@ -402,7 +417,7 @@ class FinalDerived : public Derived {
#### <a name="fdes">2.14 Function Design</a>
##### Rule 2.14.1 Use the RAII feature to help track dynamic allocation.
##### Rule 2.14.1 Use the RAII feature to help track dynamic allocation
```cpp
// Correct
@@ -412,7 +427,7 @@ class FinalDerived : public Derived {
}
```
##### Rule 2.14.2 Avoid capturing by reference in lambdas that will not be used locally.
##### Rule 2.14.2 Avoid capturing by reference in lambdas that will not be used locally
```cpp
{
@@ -422,25 +437,25 @@ class FinalDerived : public Derived {
}
```
##### Rule 2.14.3 Do not use default parameter values for virtual functions.
##### Rule 2.14.3 Do not use default parameter values for virtual functions
##### Recommendation 2.14.4 Use strongly typed parameters or member variables. Do not use void*.
##### Recommendation 2.14.4 Use strongly typed parameters or member variables. Do not use void*
#### <a name="fuse">2.15 Function Usage</a>
##### Rule 2.15.1 The input parameter must be transferred before the output parameter.
##### Rule 2.15.1 The input parameter must be transferred before the output parameter
```cpp
bool Func(const std::string &in, FooBar *out1, FooBar *out2);
```
##### Rule 2.15.2 Use `const T &` as the input parameter and `T *` as the output parameter for function transfer.
##### Rule 2.15.2 Use `const T &` as the input parameter and `T *` as the output parameter for function transfer
```cpp
bool Func(const std::string &in, FooBar *out1, FooBar *out2);
```
##### Rule 2.15.3 In the scenario where ownership is not involved, use T * or const T & instead of the smart pointer as the transfer parameter.
##### Rule 2.15.3 In the scenario where ownership is not involved, use T * or const T & instead of the smart pointer as the transfer parameter
```cpp
// Correct
@@ -449,7 +464,7 @@ class FinalDerived : public Derived {
bool Func(std::shared_ptr<FooBar> in);
```
##### Rule 2.15.4 To transfer the ownership, you are advised to use shared_ptr + move to transfer parameters.
##### Rule 2.15.4 To transfer the ownership, you are advised to use shared_ptr + move to transfer parameters
```cpp
class Foo {
@@ -460,7 +475,7 @@ class Foo {
};
```
##### Rule 2.15.5 Use explicit to modify single-parameter constructors and do not use explicit to modify multi-parameter constructors.
##### Rule 2.15.5 Use explicit to modify single-parameter constructors and do not use explicit to modify multi-parameter constructors
```cpp
explicit Foo(int x); //good :white_check_mark:
@@ -469,7 +484,7 @@ class Foo {
explicit Foo(int x, int y); //bad :x:
```
##### Rule 2.15.6 Copy constructors and copy assignment operators should be implemented or hidden together.
##### Rule 2.15.6 Copy constructors and copy assignment operators should be implemented or hidden together
```cpp
class Foo {
@@ -481,11 +496,11 @@ class Foo {
};
```
##### Rule 2.15.7 [Question] Do not save or delete pointer parameters.
##### Rule 2.15.7 [Question] Do not save or delete pointer parameters
##### Rule 2.15.8 [Question] Do not use insecure functions as listed.
##### Rule 2.15.8 [Question] Do not use insecure functions as listed
##### Rule 2.15.9 [Question] Do not use insecure exit functions as listed.
##### Rule 2.15.9 [Question] Do not use insecure exit functions as listed
```cpp
{
@@ -499,16 +514,16 @@ class Foo {
}
```
##### Rule 2.15.10 Do not use the rand function to generate pseudo-random numbers for security purposes.
##### Rule 2.15.10 Do not use the rand function to generate pseudo-random numbers for security purposes
The rand() function in the C standard library generates pseudo-random numbers. To generate random numbers, use /dev/random.
##### Rule 2.15.11 Do not use the string class to store sensitive information.
##### Rule 2.15.11 Do not use the string class to store sensitive information
The string class is a character string management class defined in C++. If sensitive information such as passwords is operated through the string class, the sensitive information can be
scattered in various places of the memory and cannot be cleared.
In the following code, the Foo function obtains the password, saves it to the string variable password, and then transfers it to the VerifyPassword function. In this process,
In the following code, the Foo function obtains the password, saves it to the string variable password, and then transfers it to the VerifyPassword function. In this process,
two copies of the password exist in the memory.
```cpp
@@ -521,6 +536,7 @@ int Foo() {
...
}
```
Sensitive information must be stored using char or unsigned char. For example:
```cpp
@@ -535,31 +551,31 @@ int Foo() {
}
```
##### Rule 2.15.12 Clear sensitive information in the memory immediately after use.
##### Rule 2.15.12 Clear sensitive information in the memory immediately after use
Sensitive information, such as passwords and keys, must be cleared immediately after being used to prevent attackers from obtaining the information.
#### <a name="mem">2.16 Memory</a>
##### Rule 2.16.1 Check whether memory allocation is successful.
##### Rule 2.16.1 Check whether memory allocation is successful
If the memory allocation fails, the subsequent operations may have undefined behavior risks. For example, if malloc fails to be applied for and a null pointer is returned, dereference of the null pointer is an undefined behavior.
##### Rule 2.16.2 Do not reference uninitialized memory.
##### Rule 2.16.2 Do not reference uninitialized memory
The memory allocated by malloc and new is not initialized to 0. Ensure that the memory is initialized before being referenced.
##### Rule 2.16.3 Do not use the realloc() function.
##### Rule 2.16.3 Do not use the realloc() function
The behavior of the realloc function varies with parameters. This is not a well-designed function. Although it provides some convenience in coding, it can easily cause various bugs.
##### Rule 2.16.4 Do not use the alloca() function to apply for stack memory.
##### Rule 2.16.4 Do not use the alloca() function to apply for stack memory
Neither POSIX nor C99 defines the alloca() behavior. Some platforms do not support this function. Using alloca() reduces program compatibility and portability. This function requests memory in the stack frame. The requested size may exceed the stack boundary, affecting code execution.
#### <a name="file">2.17 File</a>
##### Rule 2.17.1 File paths must be canonicalized before use.
##### Rule 2.17.1 File paths must be canonicalized before use
A file path that comes from external data must be canonicalized first. If the file path is not canonicalized, attackers can construct a malicious file path to access the file without authorization.
For example, an attacker can construct “../../../etc/passwd” to access any file.
@@ -573,8 +589,10 @@ char *fileName = GetMsgFromRemote();
sprintf_s(untrustPath, sizeof(untrustPath), "/tmp/%s", fileName);
char *text = ReadFileContent(untrustPath); // Bad: Did not check whether the untrustPath can be accessed before the data is read.
```
[Compliant Code Example]
Canonicalize the file path and then check whether the path is valid in the program.
```cpp
char *fileName = GetMsgFromRemote();
...
@@ -590,11 +608,11 @@ if (!IsValidPath(path)) { // Good: Check whether the file location is correct
}
char *text = ReadFileContent(untrustPath);
```
Exceptions:
Command line programs that run on the console, or file paths that are manually entered on the console are exempted from this rule.
##### Rule 2.17.2 Do not create temporary files in the shared directory.
##### Rule 2.17.2 Do not create temporary files in the shared directory
Temporary files of a program must be exclusively used by itself. Otherwise, other users of the shared directory may obtain additional information about the program, resulting in information leakage. Therefore, do not create temporary files that should be used only by the program itself in any shared directory.
For example, the /tmp directory in Linux is a shared directory that all users can access. Do not create temporary files that should be used only by the program itself in this directory.
@@ -625,7 +643,7 @@ For example, the /tmp directory in Linux is a shared directory that all users ca
</tr>
</table>
##### Rule 2.15.18 Use secure functions provided by the community in the secure function library. Do not use dangerous functions related to memory operations.
##### Rule 2.15.18 Use secure functions provided by the community in the secure function library. Do not use dangerous functions related to memory operations
<table>
<thead>
@@ -772,12 +790,11 @@ For example, the /tmp directory in Linux is a shared directory that all users ca
</tr>
</table>
##### Rule 2.18.2 Correctly set the destMax parameter in secure functions
##### Rule 2.18.2 Correctly set the destMax parameter in secure functions.
##### Rule 2.18.3 Do not encapsulate secure functions
##### Rule 2.18.3 Do not encapsulate secure functions.
##### Rule 2.18.4 Do not rename secure functions using macros.
##### Rule 2.18.4 Do not rename secure functions using macros
```cpp
#define XXX_memcpy_s memcpy_s
@@ -785,10 +802,10 @@ For example, the /tmp directory in Linux is a shared directory that all users ca
#define XX_memset_s(dst, dstMax, val, n) memset_s((dst), (dstMax), (val), (n))
```
##### Rule 2.18.5 Do not customize secure functions.
##### Rule 2.18.5 Do not customize secure functions
Using macros to rename secure functions does not help static code scanning tools (non-compiled) customize rules for the misuse of secure functions. In addition, there are various naming styles.
In addition, it is not conducive to reminding the code developer of the real usage of functions, and may easily cause misunderstanding of the code and misuse of the renamed secure functions. Renaming secure functions will not
In addition, it is not conducive to reminding the code developer of the real usage of functions, and may easily cause misunderstanding of the code and misuse of the renamed secure functions. Renaming secure functions will not
affect the checking capability of the secure functions.
```cpp
@@ -797,9 +814,9 @@ void MemcpySafe(void *dest, unsigned int destMax, const void *src, unsigned int
}
```
##### Rule 2.18.6 Check the return values of secure functions and correctly process them.
##### Rule 2.18.6 Check the return values of secure functions and correctly process them
In principle, if a secure function is used, its return value must be checked. If the return value is ! = EOK, this function should be returned immediately,
In principle, if a secure function is used, its return value must be checked. If the return value is ! = EOK, this function should be returned immediately,
and cannot be continued.
A secure function may have multiple erroneous return values. If a secure function returns a failure, perform the following operations (one or more) based on specific product scenario before it is returned
:
@@ -819,14 +836,15 @@ A secure function may have multiple erroneous return values. If a secure functio
}
```
##### Rule 2.18.7 Do not use external controllable data as function parameters for starting processes, such as system, popen, WinExec, ShellExecute, execl, xeclp, execle, execv, execvp and CreateProcess.
##### Rule 2.18.7 Do not use external controllable data as function parameters for starting processes, such as system, popen, WinExec, ShellExecute, execl, xeclp, execle, execv, execvp and CreateProcess
##### Rule 2.18.8 Do not use external controllable data as parameters for module loading functions such as dlopen/LoadLibrary.
##### Rule 2.18.8 Do not use external controllable data as parameters for module loading functions such as dlopen/LoadLibrary
##### Rule 2.18.9 Do not call non-asynchronous secure functions in signal processing routines.
##### Rule 2.18.9 Do not call non-asynchronous secure functions in signal processing routines
Signal processing routines should be as simple as possible. If a non-asynchronous secure function is called in a signal processing routine, the execution of the function may not generate expected results.
The signal handler in the following code writes logs by calling fprintf(), but the function is not asynchronous secure function.
```cpp
void Handler(int sigNum) {
...
@@ -834,4 +852,4 @@ void Handler(int sigNum) {
}
```
------------------------------------------
------------------

+ 119
- 95
security/coding_guild_cpp_zh_cn.md View File

@@ -26,10 +26,8 @@
- [文件](#217-文件)
- [安全函数](#218-安全函数)


<!-- /TOC -->


## 说明

本规范以[Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html)为基础,参考华为通用编码规范、安全编程规范,并结合业界共识整理而成,参与MindSpore社区的开发者首先需要遵循本规范内容,其余遵循Google C++ Style Guide规范;
@@ -45,14 +43,15 @@ MindSpore开源社区

#### 1.1 命名

##### 规则 1.1.1 文件命名。
##### 规则 1.1.1 文件命名

C++文件使用小写+下划线的方式命名,以`.cc`作为后缀,头文件以`.h`作为后缀,单元测试文件以`_test.cc`结尾.

> a_b_c.h
> a_b_c.cc
> a_b_c_test.cc

##### 规则 1.1.2 局部变量、参数命名采用小写加下划线方式
##### 规则 1.1.2 局部变量、参数命名采用小写加下划线方式

```cpp
void FooBar(int func_param) {
@@ -60,7 +59,7 @@ void FooBar(int func_param) {
}
```

##### 规则 1.1.3 成员变量命名采用小写加下划线,并以下划线作为后缀
##### 规则 1.1.3 成员变量命名采用小写加下划线,并以下划线作为后缀

```cpp
class FooBar {
@@ -69,13 +68,13 @@ class FooBar {
};
```

##### 规则 1.1.4 宏命名采用大写加下划线
##### 规则 1.1.4 宏命名采用大写加下划线

```cpp
#define MS_LOG(...)
```

##### 规则 1.1.5 常量、枚举命名采用k驼峰
##### 规则 1.1.5 常量、枚举命名采用k驼峰

```cpp
const int kDaysInAWeek = 7;
@@ -87,22 +86,42 @@ enum UrlTableErrors {
};
```

##### 规则 1.1.6 函数命名规则

1. 类成员变量访问器:访问器命名应与变量命名规则保持一致,如:

```c++
int count() {return this->count_;}
```

2. 类成员变量修改器:访问器命名应以`set_`开头,后接变量名称,如:

```c++
void set_count(int count) {this->count_ = count;}
```

3. 其余类成员函数/普通函数:基于大驼峰规则命名,如:

```c++
void FindPattern(...);
```

#### 1.2 格式

##### 建议 1.2.1 每行字符数不要超过 120 个。
##### 建议 1.2.1 每行字符数不要超过 120 个

如果超过120个字符,请选择合理的方式进行换行。

##### 规则 1.2.2 使用空格进行缩进,每次缩进2格。
##### 规则 1.2.2 使用空格进行缩进,每次缩进2格

##### 规则 1.2.3 在声明指针、引用变量或参数时, `&`、`*`跟随变量名,另外一边留空格。
##### 规则 1.2.3 在声明指针、引用变量或参数时, `&`、`*`跟随变量名,另外一边留空格

```cpp
char *c;
const std::string &str;
```

##### 规则 1.2.4 if语句必须要使用大括号。
##### 规则 1.2.4 if语句必须要使用大括号

```cpp
// 即使if分支代码只有一行,也必须使用大括号
@@ -111,9 +130,9 @@ if (cond) {
}
```

##### 规则 1.2.5 for/while等循环语句必须使用大括号,即使循环体是空的,或者循环语句只有一条
##### 规则 1.2.5 for/while等循环语句必须使用大括号,即使循环体是空的,或者循环语句只有一条

##### 规则 1.2.6 表达式换行要保持换行的一致性,运算符放行末
##### 规则 1.2.6 表达式换行要保持换行的一致性,运算符放行末

```cpp
int a = a_very_long_expression +
@@ -121,7 +140,7 @@ int a = a_very_long_expression +
a_very_very_very_long_expression;
```

##### 规则 1.2.7 每个变量定义和赋值语句单独一行
##### 规则 1.2.7 每个变量定义和赋值语句单独一行

```cpp
a = 1;
@@ -129,14 +148,13 @@ b = 2;
c = 3;
```


#### 1.3 注释

##### 规则 1.3.1 文件头注释包含版权声明

所有h文件、cc文件,均需包含如下版权声明:
```cpp

```cpp
/**
* Copyright 2019 Huawei Technologies Co., Ltd
*
@@ -152,47 +170,48 @@ c = 3;
* See the License for the specific language governing permissions and
* limitations under the License.
*/

```

> 关于版权说明,应注意:
> 2020年新建的文件,应该是`Copyright 2020 Huawei Technologies Co., Ltd`
> 2019年创建年份,2020年修改年份,应该是`Copyright 2019-2020 Huawei Technologies Co., Ltd`

##### 规则 1.3.2 代码注释置于对应代码的上方或右边,注释符与注释内容之间要有1个空格,右置注释与前面代码至少1空格,使用`//`,而不是`/**/`

##### 规则 1.3.2 代码注释置于对应代码的上方或右边,注释符与注释内容之间要有1个空格,右置注释与前面代码至少1空格,使用`//`,而不是`/**/`。
```cpp
// this is multi-
// line comment
int foo; // this single-line comment
```
##### 规则 1.3.3 代码中禁止使用 TODO/TBD/FIXME 等注释,建议提issue跟踪。

##### 建议 1.3.4 不要写空有格式的函数头注释。
##### 规则 1.3.3 代码中禁止使用 TODO/TBD/FIXME 等注释,建议提issue跟踪

##### 建议 1.3.4 不要写空有格式的函数头注释

并不是所有的函数都需要函数头注释,函数尽量通过函数名自注释,按需写函数头注释;函数原型无法表达的,却又希望读者知道的信息,才需要加函数头注释辅助说明。
不要写无用、信息冗余的函数头,函数头注释内容可选,但不限于:功能说明、返回值,性能约束、用法、内存约定、算法实现、可重入的要求等。


### 2. 通用编码

#### 2.1 代码设计

##### 规则 2.1.1 对所有外部数据进行合法性检查,包括但不限于:函数入参、外部输入命名行、文件、环境变量、用户数据等
##### 规则 2.1.1 对所有外部数据进行合法性检查,包括但不限于:函数入参、外部输入命名行、文件、环境变量、用户数据等

##### 规则 2.1.2 函数执行结果传递,优先使用返回值,尽量避免使用出参
##### 规则 2.1.2 函数执行结果传递,优先使用返回值,尽量避免使用出参

```cpp
FooBar *Func(const std::string &in);
```

##### 规则 2.1.3 删除无效、冗余或永不执行的代码
##### 规则 2.1.3 删除无效、冗余或永不执行的代码

虽然大多数现代编译器在许多情况下可以对无效或从不执行的代码告警,响应告警应识别并清除告警;
应该主动识别无效的语句或表达式,并将其从代码中删除。

##### 规则 2.1.4 补充C++异常机制的规范
##### 规则 2.1.4 补充C++异常机制的规范

###### 规则 2.1.4.1 需要指定捕获异常种类,禁止捕获所有异常

```cpp
// 错误示范
try {
@@ -210,7 +229,7 @@ try {

#### 2.2 头文件和预处理

##### 规则 2.2.1 使用新的标准C++头文件
##### 规则 2.2.1 使用新的标准C++头文件

```cpp
// 正确示范
@@ -219,25 +238,24 @@ try {
#include <stdlib.h>
```

##### 规则 2.2.2 禁止头文件循环依赖
##### 规则 2.2.2 禁止头文件循环依赖

头文件循环依赖,指a.h包含b.h,b.h包含c.h,c.h包含a.h之类导致任何一个头文件修改,都导致所有包含了a.h/b.h/c.h的代码全部重新编译一遍。
头文件循环依赖直接体现了架构设计上的不合理,可通过优化架构去避免。

##### 规则 2.2.3 禁止包含用不到的头文件。

##### 规则 2.2.4 禁止通过 extern 声明的方式引用外部函数接口、变量。
##### 规则 2.2.3 禁止包含用不到的头文件

##### 规则 2.2.5 禁止在extern "C"中包含头文件。
##### 规则 2.2.4 禁止通过 extern 声明的方式引用外部函数接口、变量

##### 规则 2.2.6 禁止在头文件中或者#include之前使用using导入命名空间。
##### 规则 2.2.5 禁止在extern "C"中包含头文件

##### 规则 2.2.6 禁止在头文件中或者#include之前使用using导入命名空间

#### 2.3 数据类型

##### 建议 2.3.1 避免滥用 typedef或者#define 对基本类型起别名
##### 建议 2.3.1 避免滥用 typedef或者#define 对基本类型起别名

##### 规则 2.3.2 使用using 而非typedef定义类型的别名,避免类型变化带来的散弹式修改
##### 规则 2.3.2 使用using 而非typedef定义类型的别名,避免类型变化带来的散弹式修改

```cpp
// 正确示范
@@ -248,15 +266,15 @@ typedef std::shared_ptr<FooBar> FooBarPtr;

#### 2.4 常量

##### 规则 2.4.1 禁止使用宏表示常量
##### 规则 2.4.1 禁止使用宏表示常量

##### 规则 2.4.2 禁止使用魔鬼数字\字符串
##### 规则 2.4.2 禁止使用魔鬼数字\字符串

##### 建议 2.4.3 建议每个常量保证单一职责
##### 建议 2.4.3 建议每个常量保证单一职责

#### 2.5 变量

##### 规则 2.5.1 优先使用命名空间来管理全局常量,如果和某个class有直接关系的,可以使用静态成员常量
##### 规则 2.5.1 优先使用命名空间来管理全局常量,如果和某个class有直接关系的,可以使用静态成员常量

```cpp
namespace foo {
@@ -269,17 +287,17 @@ namespace foo {
}
```

##### 规则 2.5.2 尽量避免使用全局变量,谨慎使用单例模式,避免滥用
##### 规则 2.5.2 尽量避免使用全局变量,谨慎使用单例模式,避免滥用

##### 规则 2.5.3 禁止在变量自增或自减运算的表达式中再次引用该变量
##### 规则 2.5.3 禁止在变量自增或自减运算的表达式中再次引用该变量

##### 规则 2.5.4 指向资源句柄或描述符的指针变量在资源释放后立即赋予新值或置为NULL
##### 规则 2.5.4 指向资源句柄或描述符的指针变量在资源释放后立即赋予新值或置为NULL

##### 规则 2.5.5 禁止使用未经初始化的变量
##### 规则 2.5.5 禁止使用未经初始化的变量

#### 2.6 表达式

##### 建议 2.6.1 表达式的比较遵循左侧倾向于变化、右侧倾向于不变的原则
##### 建议 2.6.1 表达式的比较遵循左侧倾向于变化、右侧倾向于不变的原则

```cpp
// 正确示范
@@ -293,7 +311,7 @@ if (SUCCESS != ret) {
}
```

##### 规则 2.6.2 通过使用括号明确操作符的优先级,避免出现低级错误
##### 规则 2.6.2 通过使用括号明确操作符的优先级,避免出现低级错误

```cpp
// 正确示范
@@ -309,31 +327,28 @@ if (cond1 || cond2 && cond3) {

#### 2.7 转换

##### 规则 2.7.1 使用有C++提供的类型转换,而不是C风格的类型转换,避免使用const_cast和reinterpret_cast。

##### 规则 2.7.1 使用有C++提供的类型转换,而不是C风格的类型转换,避免使用const_cast和reinterpret_cast

#### 2.8 控制语句

##### 规则 2.8.1 switch语句要有default分支。

##### 规则 2.8.1 switch语句要有default分支

#### 2.9 声明与初始化

##### 规则 2.9.1 禁止用`memcpy_s`、`memset_s`初始化非POD对象。

##### 规则 2.9.1 禁止用`memcpy_s`、`memset_s`初始化非POD对象

#### 2.10 指针和数组

##### 规则 2.10.1 禁止持有std::string的c_str()返回的指针。
##### 规则 2.10.1 禁止持有std::string的c_str()返回的指

```cpp
// 错误示范
const char * a = std::to_string(12345).c_str();
```

##### 规则 2.10.2 优先使用unique_ptr 而不是shared_ptr
##### 规则 2.10.2 优先使用unique_ptr 而不是shared_ptr

##### 规则 2.10.3 使用std::make_shared 而不是new 创建shared_ptr
##### 规则 2.10.3 使用std::make_shared 而不是new 创建shared_ptr

```cpp
// 正确示范
@@ -342,13 +357,13 @@ std::shared_ptr<FooBar> foo = std::make_shared<FooBar>();
std::shared_ptr<FooBar> foo(new FooBar());
```

##### 规则 2.10.4 使用智能指针管理对象,避免使用new/delete
##### 规则 2.10.4 使用智能指针管理对象,避免使用new/delete

##### 规则 2.10.5 禁止使用auto_ptr
##### 规则 2.10.5 禁止使用auto_ptr

##### 规则 2.10.6 对于指针和引用类型的形参,如果是不需要修改的,要求使用const
##### 规则 2.10.6 对于指针和引用类型的形参,如果是不需要修改的,要求使用const

##### 规则 2.10.7 数组作为函数参数时,必须同时将其长度作为函数的参数
##### 规则 2.10.7 数组作为函数参数时,必须同时将其长度作为函数的参数

```cpp
int ParseMsg(BYTE *msg, size_t msgLen) {
@@ -358,15 +373,15 @@ int ParseMsg(BYTE *msg, size_t msgLen) {

#### 2.11 字符串

##### 规则 2.11.1 对字符串进行存储操作,确保字符串有’\0’结束符
##### 规则 2.11.1 对字符串进行存储操作,确保字符串有’\0’结束符

#### 2.12 断言

##### 规则 2.12.1 断言不能用于校验程序在运行期间可能导致的错误,可能发生的运行错误要用错误处理代码来处理
##### 规则 2.12.1 断言不能用于校验程序在运行期间可能导致的错误,可能发生的运行错误要用错误处理代码来处理

#### 2.13 类和对象

##### 规则 2.13.1 单个对象释放使用delete,数组对象释放使用delete []
##### 规则 2.13.1 单个对象释放使用delete,数组对象释放使用delete []

```cpp
const int kSize = 5;
@@ -378,9 +393,10 @@ number_array = nullptr;
delete number;
number = nullptr;
```
##### 规则 2.13.2 禁止使用std::move操作const对象。

##### 规则 2.13.3 严格使用virtual/override/final修饰虚函数。
##### 规则 2.13.2 禁止使用std::move操作const对象

##### 规则 2.13.3 严格使用virtual/override/final修饰虚函数

```cpp
class Base {
@@ -411,7 +427,7 @@ class FinalDerived : public Derived {
}
```

##### 规则 2.14.2 非局部范围使用lambdas时,避免按引用捕获
##### 规则 2.14.2 非局部范围使用lambdas时,避免按引用捕获

```cpp
{
@@ -421,25 +437,25 @@ class FinalDerived : public Derived {
}
```

##### 规则 2.14.3 禁止虚函数使用缺省参数值.
##### 规则 2.14.3 禁止虚函数使用缺省参数值

##### 建议 2.14.4 使用强类型参数\成员变量,避免使用void*.
##### 建议 2.14.4 使用强类型参数\成员变量,避免使用void*

#### 2.15 函数使用

##### 规则 2.15.1 函数传参传递,要求入参在前,出参在后
##### 规则 2.15.1 函数传参传递,要求入参在前,出参在后

```cpp
bool Func(const std::string &in, FooBar *out1, FooBar *out2);
```

##### 规则 2.15.2 函数传参传递,要求入参用`const T &`,出参用 `T *`
##### 规则 2.15.2 函数传参传递,要求入参用`const T &`,出参用 `T *`

```cpp
bool Func(const std::string &in, FooBar *out1, FooBar *out2);
```

##### 规则 2.15.3 函数传参传递,不涉及所有权的场景,使用T * 或const T & 作为参数,而不是智能指针
##### 规则 2.15.3 函数传参传递,不涉及所有权的场景,使用T * 或const T & 作为参数,而不是智能指针

```cpp
// 正确示范
@@ -448,7 +464,7 @@ class FinalDerived : public Derived {
bool Func(std::shared_ptr<FooBar> in);
```

##### 规则 2.15.4 函数传参传递,如需传递所有权,建议使用shared_ptr + move传参
##### 规则 2.15.4 函数传参传递,如需传递所有权,建议使用shared_ptr + move传参

```cpp
class Foo {
@@ -459,7 +475,7 @@ class Foo {
};
```

##### 规则 2.15.5 单参数构造函数必须用explicit修饰,多参数构造函数禁止使用explicit修饰.
##### 规则 2.15.5 单参数构造函数必须用explicit修饰,多参数构造函数禁止使用explicit修饰

```cpp
explicit Foo(int x); //good :white_check_mark:
@@ -468,7 +484,7 @@ class Foo {
explicit Foo(int x, int y); //bad :x:
```

##### 规则 2.15.6 拷贝构造和拷贝赋值操作符应该是成对出现或者禁止
##### 规则 2.15.6 拷贝构造和拷贝赋值操作符应该是成对出现或者禁止

```cpp
class Foo {
@@ -480,11 +496,11 @@ class Foo {
};
```

##### 规则 2.15.7 禁止保存、delete指针参数
##### 规则 2.15.7 禁止保存、delete指针参数

##### 规则 2.15.8 禁止使用非安全函数,需要给出清单
##### 规则 2.15.8 禁止使用非安全函数,需要给出清单

##### 规则 2.15.9 禁止使用非安全退出函数,需要给出清单
##### 规则 2.15.9 禁止使用非安全退出函数,需要给出清单

```cpp
{
@@ -498,11 +514,11 @@ class Foo {
}
```

##### 规则 2.15.10 禁用rand函数产生用于安全用途的伪随机数
##### 规则 2.15.10 禁用rand函数产生用于安全用途的伪随机数

C标准库rand()函数生成的是伪随机数,请使用/dev/random生成随机数。

##### 规则 2.15.11 严禁使用string类存储敏感信息
##### 规则 2.15.11 严禁使用string类存储敏感信息

string类是C++内部定义的字符串管理类,如果口令等敏感信息通过string进行操作,在程序运行过程中,敏感信息可
能会散落到内存的各个地方,并且无法清0。
@@ -520,7 +536,9 @@ int Foo() {
...
}
```

应该使用char或unsigned char保存敏感信息,如下代码:

```cpp
int VerifyPassword(const char *password) {
//...
@@ -533,34 +551,36 @@ int Foo() {
}
```

##### 规则 2.15.12 内存中的敏感信息使用完毕后立即清0
##### 规则 2.15.12 内存中的敏感信息使用完毕后立即清0

口令、密钥等敏感信息使用完毕后立即清0,避免被攻击者获取。


#### 2.16 内存
##### 规则 2.16.1 内存分配后必须判断是否成功。

##### 规则 2.16.1 内存分配后必须判断是否成功

内存分配失败后,那么后续的操作存在未定义的行为风险。比如malloc申请失败返回了空指针,对空指针的解引用是一种未定义行为。

##### 规则 2.16.2 禁止引用未初始化的内存
##### 规则 2.16.2 禁止引用未初始化的内存

malloc、new分配出来的内存没有被初始化为0,要确保内存被引用前是被初始化的。

##### 规则 2.16.3 避免使用realloc()函数
##### 规则 2.16.3 避免使用realloc()函数

随着参数的不同,realloc函数行为也不同,这不是一个设计良好的函数。虽然在编码中提供了一些便利性,但是却极易引发各种bug。

##### 规则 2.16.4 不要使用alloca()函数申请栈上内存
##### 规则 2.16.4 不要使用alloca()函数申请栈上内存

POSIX和C99均未定义alloca()的行为,在有些平台下不支持该函数,使用alloca会降低程序的兼容性和可移植性,该函数在栈帧里申请内存,申请的大小很可能超过栈的边界,影响后续的代码执行。

#### 2.17 文件

##### 规则 2.17.1 必须对文件路径进行规范化后再使用。
##### 规则 2.17.1 必须对文件路径进行规范化后再使用

当文件路径来自外部数据时,需要先将文件路径规范化,如果没有作规范化处理,攻击者就有机会通过恶意构造文件路径进行文件的越权访问:
例如,攻击者可以构造“../../../etc/passwd”的方式进行任意文件访问。
在linux下,使用realpath函数,在windows下,使用PathCanonicalize函数进行文件路径的规范化。

【错误代码示例】
以下代码从外部获取到文件名称,拼接成文件路径后,直接对文件内容进行读取,导致攻击者可以读取到任意文件的内容:

@@ -570,8 +590,10 @@ char *fileName = GetMsgFromRemote();
sprintf_s(untrustPath, sizeof(untrustPath), "/tmp/%s", fileName);
char *text = ReadFileContent(untrustPath); // Bad,读取前未检查untrustPath是否允许访问
```

【正确代码示例】
正确的做法是,对路径进行规范化后,再判断路径是否是本程序所认为的合法的路径:

```cpp
char *fileName = GetMsgFromRemote();
...
@@ -587,11 +609,12 @@ if (!IsValidPath(path)) { // Good,检查文件位置是否正确
}
char *text = ReadFileContent(untrustPath);
```

【例外】
运行于控制台的命令行程序,通过控制台手工输入文件路径,可以作为本建议例外。

##### 规则 2.17.2 不要在共享目录中创建临时文件

##### 规则 2.17.2 不要在共享目录中创建临时文件。
程序的临时文件应当是程序自身独享的,任何将自身临时文件置于共享目录的做法,将导致其他共享用户获得该程序的额外信息,产生信息泄露。因此,不要在任何共享目录创建仅由程序自身使用的临时文件。
如Linux下的/tmp目录是一个所有用户都可以访问的共享目录,不应在该目录下创建仅由程序自身使用的临时文件。

@@ -621,7 +644,7 @@ char *text = ReadFileContent(untrustPath);
</tr>
</table>

##### 规则 2.18.1 请使用社区提供的安全函数库的安全函数,禁止使用内存操作类危险函数
##### 规则 2.18.1 请使用社区提供的安全函数库的安全函数,禁止使用内存操作类危险函数

<table>
<thead>
@@ -768,12 +791,11 @@ char *text = ReadFileContent(untrustPath);
</tr>
</table>

##### 规则 2.18.2 正确设置安全函数中的destMax参数

##### 规则 2.18.2 正确设置安全函数中的destMax参数。
##### 规则 2.18.3 禁止封装安全函数

##### 规则 2.18.3 禁止封装安全函数。

##### 规则 2.18.4 禁止用宏重命名安全函数。
##### 规则 2.18.4 禁止用宏重命名安全函数

```cpp
#define XXX_memcpy_s memcpy_s
@@ -781,7 +803,7 @@ char *text = ReadFileContent(untrustPath);
#define XX_memset_s(dst, dstMax, val, n) memset_s((dst), (dstMax), (val), (n))
```

##### 规则 2.18.5 禁止自定义安全函数
##### 规则 2.18.5 禁止自定义安全函数

使用宏重命名安全函数不利于静态代码扫描工具(非编译型)定制针对安全函数误用的规则,同时,由于命名风格多
样,也不利于提示代码开发者函数的真实用途,容易造成对代码的误解及重命名安全函数的误用。重命名安全函数不
@@ -793,7 +815,7 @@ void MemcpySafe(void *dest, unsigned int destMax, const void *src, unsigned int
}
```

##### 规则 2.18.6 必须检查安全函数返回值,并进行正确的处理
##### 规则 2.18.6 必须检查安全函数返回值,并进行正确的处理

原则上,如果使用了安全函数,需要进行返回值检查。如果返回值!=EOK, 那么本函数一般情况下应该立即返回,不
能继续执行。
@@ -815,18 +837,20 @@ void MemcpySafe(void *dest, unsigned int destMax, const void *src, unsigned int
}
```

##### 规则 2.18.7 禁止外部可控数据作为system、popen、WinExec、ShellExecute、execl, xeclp, execle, execv, execvp、CreateProcess等进程启动函数的参数
##### 规则 2.18.7 禁止外部可控数据作为system、popen、WinExec、ShellExecute、execl, xeclp, execle, execv, execvp、CreateProcess等进程启动函数的参数

##### 规则 2.18.8 禁止外部可控数据作为dlopen/LoadLibrary等模块加载函数的参数
##### 规则 2.18.8 禁止外部可控数据作为dlopen/LoadLibrary等模块加载函数的参数

##### 规则 2.18.9 禁止在信号处理例程中调用非异步安全函数
##### 规则 2.18.9 禁止在信号处理例程中调用非异步安全函数

信号处理例程应尽可能简化。在信号处理例程中如果调用非异步安全函数,可能会导致函数的执行不符合预期的结
果。 下列代码中的信号处理程序通过调用fprintf()写日志,但该函数不是异步安全函数。

```cpp
void Handler(int sigNum) {
...
fprintf(stderr, "%s\n", info);
}
```
------------------------

------------------

+ 44
- 0
security/security_coding_violation_cases.md View File

@@ -0,0 +1,44 @@
# 典型违反安全编码案例

## 案例1:未对安全函数返回值进行校验

> 修改前:

进行内存拷贝过程中,未对拷贝函数返回值进行校验,导致拷贝失败时无法捕获失败信息。

```c
(void) memcpy_s(output_addr, output->size, input_addr, input->size);
```

> 修改后

```c
if (memcpy_s(output_addr, output->size, input_addr, input->size) != EOK) {
...
}
```

## 案例2:未对指针是否为空进行校验

> 修改前:

`primitive`由外部传入,使用指针`primitive`前,未对指针是否为空进行校验,若指针为空,则调用`name()`成员函数时会产生空指针引用导致程序挂死。

```c++
AbstractBasePtr InferImplPad(const AnalysisEnginePtr &, const PrimitivePtr &primitive,
const AbstractBasePtrList &args_spec_list) {
const std::string op_name = primitive->name(); // 未对meta_graph_指针进行校验
...
}
```

> 修改后:

```C++
AbstractBasePtr InferImplPad(const AnalysisEnginePtr &, const PrimitivePtr &primitive,
const AbstractBasePtrList &args_spec_list) {
MS_EXCEPTION_IF_NULL(primitive);
const std::string op_name = primitive->name(); // 校验指针是否为空后再使用该指针
...
}
```

Loading…
Cancel
Save