From 4ca36afcb7956c66e42abd0c1f81e93e491a9c5b Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 5 Aug 2022 23:35:21 +0200 Subject: [PATCH 1/9] Package IO4 --- rule_packages/c/IO1.json | 4 +- rule_packages/c/IO4.json | 50 +++++++++++++++++++ rules.csv | 8 +-- .../generate_package_description.py | 5 +- 4 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 rule_packages/c/IO4.json diff --git a/rule_packages/c/IO1.json b/rule_packages/c/IO1.json index 481843d7ff..e6576be906 100644 --- a/rule_packages/c/IO1.json +++ b/rule_packages/c/IO1.json @@ -65,7 +65,7 @@ }, "queries": [ { - "description": "", + "description": "Do not alternate input and output operations on a file without an intervening flush or positioning call.", "kind": "problem", "name": "Do not alternately input and output from a stream without an intervening flush or positioning call", "precision": "very-high", @@ -88,7 +88,7 @@ }, "queries": [ { - "description": "", + "description": "Close files when they are no longer needed", "kind": "problem", "name": "Close files when they are no longer needed", "precision": "very-high", diff --git a/rule_packages/c/IO4.json b/rule_packages/c/IO4.json new file mode 100644 index 0000000000..ac1f49cd3a --- /dev/null +++ b/rule_packages/c/IO4.json @@ -0,0 +1,50 @@ +{ + "CERT-C": { + "FIO45-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Avoid TOCTOU race conditions accessing files", + "kind": "problem", + "name": "Avoid TOCTOU race conditions while accessing files", + "precision": "very-high", + "severity": "error", + "short_name": "ToctouRaceConditionsWhileAccessingFiles", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Avoid TOCTOU race conditions while accessing files", + "implementation_scope": { + "description": "None" + } + }, + "FIO47-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Use valid format strings", + "kind": "problem", + "name": "Use valid format strings", + "precision": "high", + "severity": "error", + "short_name": "UseValidFormatStrings", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "Use valid format strings", + "implementation_scope": { + "description": "None" + } + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 44d2dcf85a..a4b7d16efa 100755 --- a/rules.csv +++ b/rules.csv @@ -540,9 +540,9 @@ c,CERT-C,FIO40-C,Yes,Rule,,,Reset strings on fgets() or fgetws() failure,,IO2,Me c,CERT-C,FIO41-C,Yes,Rule,,,"Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects",,IO2,Medium, c,CERT-C,FIO42-C,Yes,Rule,,,Close files when they are no longer needed,FIO51-CPP,IO1,Medium, c,CERT-C,FIO44-C,Yes,Rule,,,Only use values for fsetpos() that are returned from fgetpos(),,IO2,Medium, -c,CERT-C,FIO45-C,Yes,Rule,,,Avoid TOCTOU race conditions while accessing files,,IO,Medium, +c,CERT-C,FIO45-C,Yes,Rule,,,Avoid TOCTOU race conditions while accessing files,,IO4,Medium, c,CERT-C,FIO46-C,Yes,Rule,,,Do not access a closed file,FIO51-CPP,IO1,Hard, -c,CERT-C,FIO47-C,Yes,Rule,,,Use valid format strings,,IO,Hard, +c,CERT-C,FIO47-C,Yes,Rule,,,Use valid format strings,,IO4,Hard, c,CERT-C,FLP30-C,Yes,Rule,,,Do not use floating-point variables as loop counters,,Statements,Easy, c,CERT-C,FLP32-C,Yes,Rule,,,Prevent or detect domain and range errors in math functions,A0-4-4,Types,Medium, c,CERT-C,FLP34-C,Yes,Rule,,,Ensure that floating-point conversions are within range of the new type,,Types,Medium, @@ -761,8 +761,8 @@ c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type",,Types,Medium, c,MISRA-C-2012,RULE-21-17,Yes,Mandatory,,,Use of the string handling functions from shall not result in accesses beyond the bounds of the objects referenced by their pointer parameters,,Memory,Hard, c,MISRA-C-2012,RULE-21-18,Yes,Mandatory,,,The size_t argument passed to any function in shall have an appropriate value,,Expressions,Medium, -c,MISRA-C-2012,RULE-21-19,Yes,Mandatory,,,"The pointers returned by the Standard Library functions localeconv, getenv, setlocale or, strerror shall only be used as if they have pointer to const-qualified type",ENV30-C,Contracts,Easy, -c,MISRA-C-2012,RULE-21-20,Yes,Mandatory,,,"The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror shall not be used following a subsequent call to the same function","ENV31-C, ENV34-C",Contracts,Easy, +c,MISRA-C-2012,RULE-21-19,Yes,Mandatory,,,"The pointers returned by the Standard Library functions localeconv, getenv, setlocale or, strerror shall only be used as if they have pointer to const-qualified type",ENV30-C,Contracts1,Easy, +c,MISRA-C-2012,RULE-21-20,Yes,Mandatory,,,"The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror shall not be used following a subsequent call to the same function","ENV31-C, ENV34-C",Contracts1,Easy, c,MISRA-C-2012,RULE-21-21,Yes,Required,,,The Standard Library function system of shall not be used,ENV33-C,Banned,Import, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory,Hard, diff --git a/scripts/generate_rules/generate_package_description.py b/scripts/generate_rules/generate_package_description.py index d3890e230f..51fb63a97d 100644 --- a/scripts/generate_rules/generate_package_description.py +++ b/scripts/generate_rules/generate_package_description.py @@ -166,7 +166,10 @@ def generate_short_name(title): "kind" : "problem", "tags" : [] } - ] + ], + "implementation_scope": { + "description": "None." + } } if not package_description: From 0ff4879756fd45a23696873532d57daeb0983ad4 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Sat, 6 Aug 2022 00:21:40 +0200 Subject: [PATCH 2/9] Package IO4 --- ...ernatelyIOFromAStreamWithoutPositioning.ql | 3 +- .../CloseFilesWhenTheyAreNoLongerNeeded.ql | 2 +- c/cert/src/rules/FIO47-C/check.svg | 1 + c/cert/src/rules/FIO47-C/error.svg | 1 + ...touRaceConditionsWhileAccessingFiles.qlref | 1 + .../rules/FIO47-C/UseValidFormatStrings.qlref | 1 + .../codingstandards/cpp/exclusions/c/IO4.qll | 42 +++++++++++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 ++ 8 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 c/cert/src/rules/FIO47-C/check.svg create mode 100644 c/cert/src/rules/FIO47-C/error.svg create mode 100644 c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.qlref create mode 100644 c/cert/test/rules/FIO47-C/UseValidFormatStrings.qlref create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/IO4.qll diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql index bb1cef3259..04f15a4857 100644 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql +++ b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql @@ -1,7 +1,8 @@ /** * @id c/cert/do-not-alternately-io-from-a-stream-without-positioning * @name FIO39-C: Do not alternately input and output from a stream without an intervening flush or positioning call - * @description + * @description Do not alternate input and output operations on a file without an intervening flush + * or positioning call. * @kind problem * @precision very-high * @problem.severity error diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql index 28f7d6eb58..2acd27d08b 100644 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql +++ b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql @@ -1,7 +1,7 @@ /** * @id c/cert/close-files-when-they-are-no-longer-needed * @name FIO42-C: Close files when they are no longer needed - * @description + * @description Close files when they are no longer needed * @kind problem * @precision very-high * @problem.severity error diff --git a/c/cert/src/rules/FIO47-C/check.svg b/c/cert/src/rules/FIO47-C/check.svg new file mode 100644 index 0000000000..e9573db5e7 --- /dev/null +++ b/c/cert/src/rules/FIO47-C/check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/c/cert/src/rules/FIO47-C/error.svg b/c/cert/src/rules/FIO47-C/error.svg new file mode 100644 index 0000000000..b897217cb9 --- /dev/null +++ b/c/cert/src/rules/FIO47-C/error.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.qlref b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.qlref new file mode 100644 index 0000000000..cd31c49372 --- /dev/null +++ b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.qlref @@ -0,0 +1 @@ +rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql \ No newline at end of file diff --git a/c/cert/test/rules/FIO47-C/UseValidFormatStrings.qlref b/c/cert/test/rules/FIO47-C/UseValidFormatStrings.qlref new file mode 100644 index 0000000000..7e6481309d --- /dev/null +++ b/c/cert/test/rules/FIO47-C/UseValidFormatStrings.qlref @@ -0,0 +1 @@ +rules/FIO47-C/UseValidFormatStrings.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/IO4.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/IO4.qll new file mode 100644 index 0000000000..cbc27bec99 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/IO4.qll @@ -0,0 +1,42 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype IO4Query = + TToctouRaceConditionsWhileAccessingFilesQuery() or + TUseValidFormatStringsQuery() + +predicate isIO4QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `toctouRaceConditionsWhileAccessingFiles` query + IO4Package::toctouRaceConditionsWhileAccessingFilesQuery() and + queryId = + // `@id` for the `toctouRaceConditionsWhileAccessingFiles` query + "c/cert/toctou-race-conditions-while-accessing-files" and + ruleId = "FIO45-C" + or + query = + // `Query` instance for the `useValidFormatStrings` query + IO4Package::useValidFormatStringsQuery() and + queryId = + // `@id` for the `useValidFormatStrings` query + "c/cert/use-valid-format-strings" and + ruleId = "FIO47-C" +} + +module IO4Package { + Query toctouRaceConditionsWhileAccessingFilesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `toctouRaceConditionsWhileAccessingFiles` query + TQueryC(TIO4PackageQuery(TToctouRaceConditionsWhileAccessingFilesQuery())) + } + + Query useValidFormatStringsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useValidFormatStrings` query + TQueryC(TIO4PackageQuery(TUseValidFormatStringsQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index d4813a7e58..e2c0f9e0e6 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -8,6 +8,7 @@ import Concurrency2 import IO1 import IO2 import IO3 +import IO4 import Misc import Pointers1 import Preprocessor1 @@ -30,6 +31,7 @@ newtype TCQuery = TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or TIO3PackageQuery(IO3Query q) or + TIO4PackageQuery(IO4Query q) or TMiscPackageQuery(MiscQuery q) or TPointers1PackageQuery(Pointers1Query q) or TPreprocessor1PackageQuery(Preprocessor1Query q) or @@ -52,6 +54,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId) { isIO1QueryMetadata(query, queryId, ruleId) or isIO2QueryMetadata(query, queryId, ruleId) or isIO3QueryMetadata(query, queryId, ruleId) or + isIO4QueryMetadata(query, queryId, ruleId) or isMiscQueryMetadata(query, queryId, ruleId) or isPointers1QueryMetadata(query, queryId, ruleId) or isPreprocessor1QueryMetadata(query, queryId, ruleId) or From 6fb1f08e2aa947e207e5ae9f6729b2f7bb9537a9 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 12 Aug 2022 19:45:20 +0200 Subject: [PATCH 3/9] Package Contracts1 --- .vscode/tasks.json | 1 + ...tModifyTheReturnValueOfCertainFunctions.md | 225 ++++++++++++++++++ ...tModifyTheReturnValueOfCertainFunctions.ql | 69 ++++++ ...vPointerIsInvalidAfterCertainOperations.md | 225 ++++++++++++++++++ ...vPointerIsInvalidAfterCertainOperations.ql | 39 +++ c/cert/src/rules/FIO47-C/check.svg | 1 - c/cert/src/rules/FIO47-C/error.svg | 1 - ...yTheReturnValueOfCertainFunctions.expected | 20 ++ ...difyTheReturnValueOfCertainFunctions.qlref | 1 + c/cert/test/rules/ENV30-C/test.c | 93 ++++++++ ...erIsInvalidAfterCertainOperations.expected | 6 + ...interIsInvalidAfterCertainOperations.qlref | 1 + c/cert/test/rules/ENV31-C/test.c | 45 ++++ ...touRaceConditionsWhileAccessingFiles.qlref | 1 - .../rules/FIO47-C/UseValidFormatStrings.qlref | 1 - .../cpp/exclusions/c/Contracts1.qll | 42 ++++ .../codingstandards/cpp/exclusions/c/IO4.qll | 42 ---- .../cpp/exclusions/c/RuleMetadata.qll | 6 +- rule_packages/c/Contracts1.json | 48 ++++ rule_packages/c/IO4.json | 50 ---- rules.csv | 4 +- 21 files changed, 820 insertions(+), 101 deletions(-) create mode 100644 c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.md create mode 100644 c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql create mode 100644 c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.md create mode 100644 c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql delete mode 100644 c/cert/src/rules/FIO47-C/check.svg delete mode 100644 c/cert/src/rules/FIO47-C/error.svg create mode 100644 c/cert/test/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.expected create mode 100644 c/cert/test/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.qlref create mode 100644 c/cert/test/rules/ENV30-C/test.c create mode 100644 c/cert/test/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.expected create mode 100644 c/cert/test/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.qlref create mode 100644 c/cert/test/rules/ENV31-C/test.c delete mode 100644 c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.qlref delete mode 100644 c/cert/test/rules/FIO47-C/UseValidFormatStrings.qlref create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Contracts1.qll delete mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/IO4.qll create mode 100644 rule_packages/c/Contracts1.json delete mode 100644 rule_packages/c/IO4.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 84d63e64d7..9f4a58d9fb 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -193,6 +193,7 @@ "Classes", "Classes", "Comments", + "Contracts1", "Concurrency", "Concurrency", "Concurrency1", diff --git a/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.md b/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.md new file mode 100644 index 0000000000..a68e904281 --- /dev/null +++ b/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.md @@ -0,0 +1,225 @@ +# ENV30-C: Do not modify the return value of certain functions + +This query implements the CERT-C rule ENV30-C: + +> Do not modify the object referenced by the return value of certain functions + + +## Description + +Some functions return a pointer to an object that cannot be modified without causing [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). These functions include `getenv()`, `setlocale()`, `localeconv()`, `asctime()`, and `strerror()`. In such cases, the function call results must be treated as being `const`-qualified. + +The C Standard, 7.22.4.6, paragraph 4 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], defines `getenv()` as follows: + +> The `getenv` function returns a pointer to a string associated with the matched list member. The string pointed to shall not be modified by the program, but may be overwritten by a subsequent call to the `getenv` function. If the specified name cannot be found, a null pointer is returned. + + +If the string returned by `getenv()` must be altered, a local copy should be created. Altering the string returned by `getenv()` is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behavior 184](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_184).) + +Similarly, subclause 7.11.1.1, paragraph 8 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], defines `setlocale()` as follows: + +> The pointer to string returned by the `setlocale` function is such that a subsequent call with that string value and its associated category will restore that part of the program'€™s locale. The string pointed to shall not be modified by the program, but may be overwritten by a subsequent call to the `setlocale` function. + + +And subclause 7.11.2.1, paragraph 8 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], defines `localeconv()` as follows: + +> The `localeconv` function returns a pointer to the filled-in object. The structure pointed to by the return value shall not be modified by the program, but may be overwritten by a subsequent call to the `localeconv` function. In addition, calls to the `setlocale` function with categories `LC_ALL`, `LC_MONETARY`, or `LC_NUMERIC` may overwrite the contents of the structure. + + +Altering the string returned by `setlocale()` or the structure returned by `localeconv()` are [undefined behaviors](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behaviors 120](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_120) and [121](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_121).) Furthermore, the C Standard imposes no requirements on the contents of the string by `setlocale()`. Consequently, no assumptions can be made as to the string's internal contents or structure. + +Finally, subclause 7.24.6.2, paragraph 4 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], states + +> The `strerror` function returns a pointer to the string, the contents of which are locale-specific. The array pointed to shall not be modified by the program, but may be overwritten by a subsequent call to the `strerror` function. + + +Altering the string returned by `strerror()` is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behavior 184](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_184).) + +## Noncompliant Code Example (getenv()) + +This noncompliant code example modifies the string returned by `getenv()` by replacing all double quotation marks (`"`) with underscores (`_`): + +```cpp +#include + +void trstr(char *c_str, char orig, char rep) { + while (*c_str != '\0') { + if (*c_str == orig) { + *c_str = rep; + } + ++c_str; + } +} + +void func(void) { + char *env = getenv("TEST_ENV"); + if (env == NULL) { + /* Handle error */ + } + trstr(env,'"', '_'); +} + +``` + +## Compliant Solution (getenv()) (Environment Not Modified) + +If the programmer does not intend to modify the environment, this compliant solution demonstrates how to modify a copy of the return value: + +```cpp +#include +#include + +void trstr(char *c_str, char orig, char rep) { + while (*c_str != '\0') { + if (*c_str == orig) { + *c_str = rep; + } + ++c_str; + } +} + +void func(void) { + const char *env; + char *copy_of_env; + + env = getenv("TEST_ENV"); + if (env == NULL) { + /* Handle error */ + } + + copy_of_env = (char *)malloc(strlen(env) + 1); + if (copy_of_env == NULL) { + /* Handle error */ + } + + strcpy(copy_of_env, env); + trstr(copy_of_env,'"', '_'); + /* ... */ + free(copy_of_env); +} +``` + +## Compliant Solution (getenv()) (Modifying the Environment in POSIX) + +If the programmer's intent is to modify the environment, this compliant solution, which saves the altered string back into the environment by using the POSIX `setenv()` and `strdup()` functions, can be used: + +```cpp +#include +#include + +void trstr(char *c_str, char orig, char rep) { + while (*c_str != '\0') { + if (*c_str == orig) { + *c_str = rep; + } + ++c_str; + } +} + +void func(void) { + const char *env; + char *copy_of_env; + + env = getenv("TEST_ENV"); + if (env == NULL) { + /* Handle error */ + } + + copy_of_env = strdup(env); + if (copy_of_env == NULL) { + /* Handle error */ + } + + trstr(copy_of_env,'"', '_'); + + if (setenv("TEST_ENV", copy_of_env, 1) != 0) { + /* Handle error */ + } + /* ... */ + free(copy_of_env); +} +``` + +## Noncompliant Code Example (localeconv()) + +In this noncompliant example, the object returned by `localeconv()` is directly modified: + +```cpp +#include + +void f2(void) { + struct lconv *conv = localeconv(); + + if ('\0' == conv->decimal_point[0]) { + conv->decimal_point = "."; + } +} + +``` + +## Compliant Solution (localeconv()) (Copy) + +This compliant solution modifies a copy of the object returned by `localeconv()`: + +```cpp +#include +#include +#include + +void f2(void) { + const struct lconv *conv = localeconv(); + if (conv == NULL) { + /* Handle error */ + } + + struct lconv *copy_of_conv = (struct lconv *)malloc( + sizeof(struct lconv)); + if (copy_of_conv == NULL) { + /* Handle error */ + } + + memcpy(copy_of_conv, conv, sizeof(struct lconv)); + + if ('\0' == copy_of_conv->decimal_point[0]) { + copy_of_conv->decimal_point = "."; + } + /* ... */ + free(copy_of_conv); +} +``` + +## Risk Assessment + +Modifying the object pointed to by the return value of `getenv()`, `setlocale()`, `localeconv()`, `asctime()`, or `strerror()` is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). Even if the modification succeeds, the modified object can be overwritten by a subsequent call to the same function. + +
Rule Severity Likelihood Remediation Cost Priority Level
ENV30-C Low Probable Medium P4 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 stdlib-const-pointer-assign Partially checked
Axivion Bauhaus Suite 7.2.0 CertC-ENV30
CodeSonar 7.0p0 BADFUNC.GETENV Use of getenv
Compass/ROSE Can detect violations of this rule. In particular, it ensures that the result of getenv() is stored in a const variable
Helix QAC 2022.2 C1492, C1493, C1494, C4751, C4752, C4753 C++4751, C++4752, C++4753
Klocwork 2022.2 MISRA.STDLIB.CTYPE.RANGE.2012_AMD1 MISRA.STDLIB.ILLEGAL_REUSE.2012_AMD1 MISRA.STDLIB.ILLEGAL_WRITE.2012_AMD1
LDRA tool suite 9.7.1 107 D Partially Implemented
Parasoft C/C++test 2022.1 CERT_C-ENV30-a The pointers returned by the Standard Library functions 'localeconv', 'getenv', 'setlocale' or, 'strerror' shall only be used as if they have pointer to const-qualified type
Polyspace Bug Finder R2022a CERT C: Rule ENV30-C Checks for modification of internal buffer returned from nonreentrant standard function (rule fully covered)
PRQA QA-C 9.7 1492, 1493, 1494
PVS-Studio 7.20 V675
RuleChecker 22.04 stdlib-const-pointer-assign Partially checked
+ + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+ENV30-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
Taxonomy Taxonomy item Relationship
ISO/IEC TS 17961:2013 Modifying the string returned by getenv , localeconv , setlocale , and strerror \[libmod\] Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ IEEE Std 1003.1:2013 \] XSH, System Interfaces, getenv XSH, System Interfaces, setlocale XSH, System Interfaces, localeconv
\[ ISO/IEC 9899:2011 \] 7.11.1.1, "The setlocale Function" 7.11.2.1, "The localeconv Function" 7.22.4.6, "The getenv Function" 7.24.6.2, "The strerror Function"
+ + +## Implementation notes + +None + +## References + +* CERT-C: [ENV30-C: Do not modify the object referenced by the return value of certain functions](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql b/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql new file mode 100644 index 0000000000..5d04188238 --- /dev/null +++ b/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql @@ -0,0 +1,69 @@ +/** + * @id c/cert/do-not-modify-the-return-value-of-certain-functions + * @name ENV30-C: Do not modify the return value of certain functions + * @description Modification of return values of getenv and similar functions results in undefined + * behaviour. + * @kind path-problem + * @precision very-high + * @problem.severity warning + * @tags external/cert/id/env30-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import semmle.code.cpp.dataflow.DataFlow +import DataFlow::PathGraph + +/* + * Call to functions that return pointers to environment objects that should not be modified. + */ + +class NotModifiableCall extends FunctionCall { + NotModifiableCall() { + this.getTarget() + .hasGlobalName(["getenv", "setlocale", "localeconv", "asctime", "strerror"]) + } +} + +/* + * An expression that modifies an object. + */ + +class ObjectWrite extends Expr { + ObjectWrite() { + // the pointed object is reassigned + exists(Expr e | + e = [any(AssignExpr ae).getLValue(), any(CrementOperation co).getOperand()] and + ( + this = e.(PointerDereferenceExpr).getOperand() + or + this = e.(PointerFieldAccess).getQualifier() + ) + ) + } +} + +/** + * DF configuration for flows from a `NotModifiableCall` to a object modifications. + */ +class DFConf extends DataFlow::Configuration { + DFConf() { this = "DFConf" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof NotModifiableCall + } + + override predicate isSink(DataFlow::Node sink) { sink.asExpr() instanceof ObjectWrite } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink +where + not isExcluded(sink.getNode().asExpr(), + Contracts1Package::doNotModifyTheReturnValueOfCertainFunctionsQuery()) and + // the modified object comes from a call to one of the ENV functions + any(DFConf d).hasFlowPath(source, sink) +select sink.getNode(), source, sink, + "The object returned by the function " + + source.getNode().asExpr().(FunctionCall).getTarget().getName() + " should no be modified." diff --git a/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.md b/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.md new file mode 100644 index 0000000000..bb222bfbce --- /dev/null +++ b/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.md @@ -0,0 +1,225 @@ +# ENV31-C: Do not rely on an env pointer following an operation that may invalidate it + +This query implements the CERT-C rule ENV31-C: + +> Do not rely on an environment pointer following an operation that may invalidate it + + +## Description + +Some implementations provide a nonportable environment pointer that is valid when `main()` is called but may be invalidated by operations that modify the environment. + +The C Standard, J.5.1 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\], states + +> In a hosted environment, the main function receives a third argument, `char *envp[]`, that points to a null-terminated array of pointers to `char`, each of which points to a string that provides information about the environment for this execution of the program. + + +Consequently, under a [hosted environment](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions) supporting this common extension, it is possible to access the environment through a modified form of `main()`: + +```cpp +main(int argc, char *argv[], char *envp[]){ /* ... */ } + +``` +However, modifying the environment by any means may cause the environment memory to be reallocated, with the result that `envp` now references an incorrect location. For example, when compiled with GCC 4.8.1 and run on a 32-bit Intel GNU/Linux machine, the following code, + +```cpp +#include +#include + +extern char **environ; + +int main(int argc, const char *argv[], const char *envp[]) { + printf("environ: %p\n", environ); + printf("envp: %p\n", envp); + setenv("MY_NEW_VAR", "new_value", 1); + puts("--Added MY_NEW_VAR--"); + printf("environ: %p\n", environ); + printf("envp: %p\n", envp); + return 0; +} + +``` +yields + +```cpp +% ./envp-environ +environ: 0xbf8656ec +envp: 0xbf8656ec +--Added MY_NEW_VAR-- +environ: 0x804a008 +envp: 0xbf8656ec + +``` +It is evident from these results that the environment has been relocated as a result of the call to `setenv()`. The external variable `environ` is updated to refer to the current environment; the `envp` parameter is not. + +An environment pointer may also become invalidated by subsequent calls to `getenv().` (See [ENV34-C. Do not store pointers returned by certain functions](https://wiki.sei.cmu.edu/confluence/display/c/ENV34-C.+Do+not+store+pointers+returned+by+certain+functions) for more information.) + +## Noncompliant Code Example (POSIX) + +After a call to the POSIX `setenv()` function or to another function that modifies the environment, the `envp` pointer may no longer reference the current environment. The *Portable Operating System Interface (POSIX®), Base Specifications, Issue 7* \[[IEEE Std 1003.1:2013](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-IEEEStd1003.1-2013)\], states + +> Unanticipated results may occur if `setenv()` changes the external variable `environ`. In particular, if the optional `envp` argument to `main()` is present, it is not changed, and thus may point to an obsolete copy of the environment (as may any other copy of `environ`). + + +This noncompliant code example accesses the `envp` pointer after calling `setenv()`: + +```cpp +#include +#include + +int main(int argc, const char *argv[], const char *envp[]) { + if (setenv("MY_NEW_VAR", "new_value", 1) != 0) { + /* Handle error */ + } + if (envp != NULL) { + for (size_t i = 0; envp[i] != NULL; ++i) { + puts(envp[i]); + } + } + return 0; +} + +``` +Because `envp` may no longer point to the current environment, this program has unanticipated behavior. + +## Compliant Solution (POSIX) + +Use `environ` in place of `envp` when defined: + +```cpp +#include +#include + +extern char **environ; + +int main(void) { + if (setenv("MY_NEW_VAR", "new_value", 1) != 0) { + /* Handle error */ + } + if (environ != NULL) { + for (size_t i = 0; environ[i] != NULL; ++i) { + puts(environ[i]); + } + } + return 0; +} + +``` + +## Noncompliant Code Example (Windows) + +After a call to the Windows [_putenv_s()](http://msdn.microsoft.com/en-us/library/eyw7eyfw.aspx) function or to another function that modifies the environment, the `envp` pointer may no longer reference the environment. + +According to the Visual C++ reference \[[MSDN](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-MSDN)\] + +> The environment block passed to `main` and `wmain` is a "frozen" copy of the current environment. If you subsequently change the environment via a call to `_putenv` or `_wputenv`, the current environment (as returned by `getenv` / `_wgetenv` and the `_environ` / `_wenviron` variable) will change, but the block pointed to by `envp` will not change. + + +This noncompliant code example accesses the `envp` pointer after calling `_putenv_s()`: + +```cpp +#include +#include + +int main(int argc, const char *argv[], const char *envp[]) { + if (_putenv_s("MY_NEW_VAR", "new_value") != 0) { + /* Handle error */ + } + if (envp != NULL) { + for (size_t i = 0; envp[i] != NULL; ++i) { + puts(envp[i]); + } + } + return 0; +} + +``` +Because `envp` no longer points to the current environment, this program has unanticipated behavior. + +## Compliant Solution (Windows) + +This compliant solution uses the [_environ](http://msdn.microsoft.com/en-us/library/stxk41x1.aspx) variable in place of `envp`: + +```cpp +#include +#include + +_CRTIMP extern char **_environ; + +int main(int argc, const char *argv[]) { + if (_putenv_s("MY_NEW_VAR", "new_value") != 0) { + /* Handle error */ + } + if (_environ != NULL) { + for (size_t i = 0; _environ[i] != NULL; ++i) { + puts(_environ[i]); + } + } +return 0; +} + +``` + +## Compliant Solution + +This compliant solution can reduce remediation time when a large amount of noncompliant `envp` code exists. It replaces + +```cpp +int main(int argc, char *argv[], char *envp[]) { + /* ... */ +} + +``` +with + +```cpp +#if defined (_POSIX_) || defined (__USE_POSIX) + extern char **environ; + #define envp environ +#elif defined(_WIN32) + _CRTIMP extern char **_environ; + #define envp _environ +#endif + +int main(int argc, char *argv[]) { + /* ... */ +} + +``` +This compliant solution may need to be extended to support other implementations that support forms of the external variable `environ`. + +## Risk Assessment + +Using the `envp` environment pointer after the environment has been modified can result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +
Rule Severity Likelihood Remediation Cost Priority Level
ENV31-C Low Probable Medium P4 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 Supported
Compass/ROSE
Helix QAC 2022.2 C4991, C4992, C4993 C++4991, C++4992, C++4993
LDRA tool suite 9.7.1 118 S Fully Implemented
Parasoft C/C++test 2022.1 CERT_C-ENV31-a Do not rely on an environment pointer following an operation that may invalidate it
Polyspace Bug Finder R2022a CERT C: Rule ENV31-C Checks for environment pointer invalidated by previous operation (rule fully covered)
PRQA QA-C 9.7 4991, 4992, 4993
PRQA QA-C++ 4.4 4991, 4992, 4993
+ + +## Related Vulnerabilities + +Search for vulnerabilities resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MEM00-CPP). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
Taxonomy Taxonomy item Relationship
CERT C VOID ENV31-CPP. Do not rely on an environment pointer following an operation that may invalidate it Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ IEEE Std 1003.1:2013 \] XSH, System Interfaces, setenv
\[ ISO/IEC 9899:2011 \] J.5.1, "Environment Arguments"
\[ MSDN \] _environ , _wenviron , getenv , _wgetenv , _putenv_s , _wputenv_s
+ + +## Implementation notes + +None + +## References + +* CERT-C: [ENV31-C: Do not rely on an environment pointer following an operation that may invalidate it](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql b/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql new file mode 100644 index 0000000000..a925b80e74 --- /dev/null +++ b/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql @@ -0,0 +1,39 @@ +/** + * @id c/cert/env-pointer-is-invalid-after-certain-operations + * @name ENV31-C: Do not rely on an env pointer following an operation that may invalidate it + * @description Using the envp pointer after environment modifications can result in undefined + * behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/cert/id/env31-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.EncapsulatingFunctions + +/* + * Call to functions that modify the environment. + */ + +class EnvModifyingCall extends FunctionCall { + EnvModifyingCall() { + this.getTarget().hasGlobalName(["setenv", "unsetenv", "putenv", "_putenv_s", "_wputenv_s"]) + } +} + +from VariableAccess va, MainFunction main, EnvModifyingCall call, Parameter envp +where + not isExcluded(va, Contracts1Package::envPointerIsInvalidAfterCertainOperationsQuery()) and + // param envp exists + main.getNumberOfParameters() >= 3 and + envp = main.getParameter(2) and + va.getTarget() = envp and + va = call.getASuccessor+() +select va, + "Accessing " + va + + " following a $@ is invalid because the optional $@ argument is present in main.", call, + call.toString(), envp, envp.getName() diff --git a/c/cert/src/rules/FIO47-C/check.svg b/c/cert/src/rules/FIO47-C/check.svg deleted file mode 100644 index e9573db5e7..0000000000 --- a/c/cert/src/rules/FIO47-C/check.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/c/cert/src/rules/FIO47-C/error.svg b/c/cert/src/rules/FIO47-C/error.svg deleted file mode 100644 index b897217cb9..0000000000 --- a/c/cert/src/rules/FIO47-C/error.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/c/cert/test/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.expected b/c/cert/test/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.expected new file mode 100644 index 0000000000..91d6d9a1b4 --- /dev/null +++ b/c/cert/test/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.expected @@ -0,0 +1,20 @@ +edges +| test.c:5:18:5:22 | c_str | test.c:8:8:8:12 | c_str | +| test.c:15:16:15:21 | call to getenv | test.c:21:9:21:12 | env1 | +| test.c:21:9:21:12 | env1 | test.c:5:18:5:22 | c_str | +| test.c:61:11:61:20 | call to localeconv | test.c:64:5:64:9 | conv4 | +| test.c:69:25:69:34 | call to localeconv | test.c:73:5:73:8 | conv | +nodes +| test.c:5:18:5:22 | c_str | semmle.label | c_str | +| test.c:8:8:8:12 | c_str | semmle.label | c_str | +| test.c:15:16:15:21 | call to getenv | semmle.label | call to getenv | +| test.c:21:9:21:12 | env1 | semmle.label | env1 | +| test.c:61:11:61:20 | call to localeconv | semmle.label | call to localeconv | +| test.c:64:5:64:9 | conv4 | semmle.label | conv4 | +| test.c:69:25:69:34 | call to localeconv | semmle.label | call to localeconv | +| test.c:73:5:73:8 | conv | semmle.label | conv | +subpaths +#select +| test.c:8:8:8:12 | c_str | test.c:15:16:15:21 | call to getenv | test.c:8:8:8:12 | c_str | The object returned by the function getenv should no be modified. | +| test.c:64:5:64:9 | conv4 | test.c:61:11:61:20 | call to localeconv | test.c:64:5:64:9 | conv4 | The object returned by the function localeconv should no be modified. | +| test.c:73:5:73:8 | conv | test.c:69:25:69:34 | call to localeconv | test.c:73:5:73:8 | conv | The object returned by the function localeconv should no be modified. | diff --git a/c/cert/test/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.qlref b/c/cert/test/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.qlref new file mode 100644 index 0000000000..9c9c06e9de --- /dev/null +++ b/c/cert/test/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.qlref @@ -0,0 +1 @@ +rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql \ No newline at end of file diff --git a/c/cert/test/rules/ENV30-C/test.c b/c/cert/test/rules/ENV30-C/test.c new file mode 100644 index 0000000000..cd7c101898 --- /dev/null +++ b/c/cert/test/rules/ENV30-C/test.c @@ -0,0 +1,93 @@ +#include +#include +#include + +void trstr(char *c_str, char orig, char rep) { + while (*c_str != '\0') { + if (*c_str == orig) { + *c_str = rep; // NON_COMPLIANT + } + ++c_str; + } +} + +void f1(void) { + char *env1 = getenv("TEST_ENV"); + char *copy_of_env; + copy_of_env = env1; // COMPLIANT + + if (env1 == NULL) { + } + trstr(env1, '"', '_'); +} + +void f2(void) { + const char *env2; + char *copy_of_env; + + env2 = getenv("TEST_ENV"); + if (env2 == NULL) { + } + + copy_of_env = (char *)malloc(strlen(env2) + 1); + if (copy_of_env == NULL) { + } + + strcpy(copy_of_env, env2); + trstr(copy_of_env, '"', '_'); // COMPLIANT +} + +void f3(void) { + const char *env3; + char *copy_of_env; + + env3 = getenv("TEST_ENV"); + if (env3 == NULL) { + } + + copy_of_env = strdup(env3); + if (copy_of_env == NULL) { + } + + trstr(copy_of_env, '"', '_'); // COMPLIANT + if (setenv("TEST_ENV", copy_of_env, 1) != 0) { + } +} + +void f4(void) { + struct lconv *conv4 = localeconv(); + + setlocale(LC_ALL, "C"); // COMPLIANT + conv4 = localeconv(); // COMPLIANT + + if ('\0' == conv4->decimal_point[0]) { + conv4->decimal_point = "."; // NON_COMPLIANT + } +} + +void f4alias(void) { + struct lconv *conv4 = localeconv(); + struct lconv *conv = conv4; + + if ('\0' == conv4->decimal_point[0]) { + conv->decimal_point = "."; // NON_COMPLIANT + } +} + +void f5(void) { + const struct lconv *conv5 = localeconv(); + if (conv5 == NULL) { + } + + struct lconv *copy_of_conv = (struct lconv *)malloc(sizeof(struct lconv)); + if (copy_of_conv == NULL) { + } + + memcpy(copy_of_conv, conv5, sizeof(struct lconv)); + + if ('\0' == copy_of_conv->decimal_point[0]) { + copy_of_conv->decimal_point = "."; // COMPLIANT + } + + free(copy_of_conv); +} \ No newline at end of file diff --git a/c/cert/test/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.expected b/c/cert/test/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.expected new file mode 100644 index 0000000000..7c42b5c817 --- /dev/null +++ b/c/cert/test/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.expected @@ -0,0 +1,6 @@ +| test.c:23:9:23:12 | envp | Accessing envp following a $@ is invalid because the optional $@ argument is present in main. | test.c:15:9:15:14 | call to setenv | call to setenv | test.c:11:52:11:55 | envp | envp | +| test.c:24:26:24:29 | envp | Accessing envp following a $@ is invalid because the optional $@ argument is present in main. | test.c:15:9:15:14 | call to setenv | call to setenv | test.c:11:52:11:55 | envp | envp | +| test.c:25:14:25:17 | envp | Accessing envp following a $@ is invalid because the optional $@ argument is present in main. | test.c:15:9:15:14 | call to setenv | call to setenv | test.c:11:52:11:55 | envp | envp | +| test.c:38:9:38:12 | envp | Accessing envp following a $@ is invalid because the optional $@ argument is present in main. | test.c:30:9:30:17 | call to _putenv_s | call to _putenv_s | test.c:11:52:11:55 | envp | envp | +| test.c:39:26:39:29 | envp | Accessing envp following a $@ is invalid because the optional $@ argument is present in main. | test.c:30:9:30:17 | call to _putenv_s | call to _putenv_s | test.c:11:52:11:55 | envp | envp | +| test.c:40:14:40:17 | envp | Accessing envp following a $@ is invalid because the optional $@ argument is present in main. | test.c:30:9:30:17 | call to _putenv_s | call to _putenv_s | test.c:11:52:11:55 | envp | envp | diff --git a/c/cert/test/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.qlref b/c/cert/test/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.qlref new file mode 100644 index 0000000000..1f9a564c8e --- /dev/null +++ b/c/cert/test/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.qlref @@ -0,0 +1 @@ +rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql \ No newline at end of file diff --git a/c/cert/test/rules/ENV31-C/test.c b/c/cert/test/rules/ENV31-C/test.c new file mode 100644 index 0000000000..63fe9d7451 --- /dev/null +++ b/c/cert/test/rules/ENV31-C/test.c @@ -0,0 +1,45 @@ +#include +#include + +// UNIX +extern char **environ; + +// WINDOWS +extern char **_environ; +int _putenv_s(const char *varname, const char *value_string); + +int main(int argc, const char *argv[], const char *envp[]) { + + if (argc) { + // UNIX + if (setenv("MY_NEW_VAR", "new_value", 1) != 0) { + /* Handle error */ + } + if (environ != NULL) { // COMPLIANT + for (size_t i = 0; environ[i] != NULL; ++i) { + puts(environ[i]); + } + } + if (envp != NULL) { // NON_COMPLIANT + for (size_t i = 0; envp[i] != NULL; ++i) { // NON_COMPLIANT + puts(envp[i]); // NON_COMPLIANT + } + } + } else { + // WINDOWS + if (_putenv_s("MY_NEW_VAR", "new_value") != 0) { + /* Handle error */ + } + if (_environ != NULL) { // COMPLIANT + for (size_t i = 0; _environ[i] != NULL; ++i) { + puts(_environ[i]); + } + } + if (envp != NULL) { // NON_COMPLIANT + for (size_t i = 0; envp[i] != NULL; ++i) { // NON_COMPLIANT + puts(envp[i]); // NON_COMPLIANT + } + } + } + return 0; +} diff --git a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.qlref b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.qlref deleted file mode 100644 index cd31c49372..0000000000 --- a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql \ No newline at end of file diff --git a/c/cert/test/rules/FIO47-C/UseValidFormatStrings.qlref b/c/cert/test/rules/FIO47-C/UseValidFormatStrings.qlref deleted file mode 100644 index 7e6481309d..0000000000 --- a/c/cert/test/rules/FIO47-C/UseValidFormatStrings.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/FIO47-C/UseValidFormatStrings.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts1.qll new file mode 100644 index 0000000000..b7a10673b7 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts1.qll @@ -0,0 +1,42 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Contracts1Query = + TDoNotModifyTheReturnValueOfCertainFunctionsQuery() or + TEnvPointerIsInvalidAfterCertainOperationsQuery() + +predicate isContracts1QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `doNotModifyTheReturnValueOfCertainFunctions` query + Contracts1Package::doNotModifyTheReturnValueOfCertainFunctionsQuery() and + queryId = + // `@id` for the `doNotModifyTheReturnValueOfCertainFunctions` query + "c/cert/do-not-modify-the-return-value-of-certain-functions" and + ruleId = "ENV30-C" + or + query = + // `Query` instance for the `envPointerIsInvalidAfterCertainOperations` query + Contracts1Package::envPointerIsInvalidAfterCertainOperationsQuery() and + queryId = + // `@id` for the `envPointerIsInvalidAfterCertainOperations` query + "c/cert/env-pointer-is-invalid-after-certain-operations" and + ruleId = "ENV31-C" +} + +module Contracts1Package { + Query doNotModifyTheReturnValueOfCertainFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotModifyTheReturnValueOfCertainFunctions` query + TQueryC(TContracts1PackageQuery(TDoNotModifyTheReturnValueOfCertainFunctionsQuery())) + } + + Query envPointerIsInvalidAfterCertainOperationsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `envPointerIsInvalidAfterCertainOperations` query + TQueryC(TContracts1PackageQuery(TEnvPointerIsInvalidAfterCertainOperationsQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/IO4.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/IO4.qll deleted file mode 100644 index cbc27bec99..0000000000 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/IO4.qll +++ /dev/null @@ -1,42 +0,0 @@ -//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ -import cpp -import RuleMetadata -import codingstandards.cpp.exclusions.RuleMetadata - -newtype IO4Query = - TToctouRaceConditionsWhileAccessingFilesQuery() or - TUseValidFormatStringsQuery() - -predicate isIO4QueryMetadata(Query query, string queryId, string ruleId) { - query = - // `Query` instance for the `toctouRaceConditionsWhileAccessingFiles` query - IO4Package::toctouRaceConditionsWhileAccessingFilesQuery() and - queryId = - // `@id` for the `toctouRaceConditionsWhileAccessingFiles` query - "c/cert/toctou-race-conditions-while-accessing-files" and - ruleId = "FIO45-C" - or - query = - // `Query` instance for the `useValidFormatStrings` query - IO4Package::useValidFormatStringsQuery() and - queryId = - // `@id` for the `useValidFormatStrings` query - "c/cert/use-valid-format-strings" and - ruleId = "FIO47-C" -} - -module IO4Package { - Query toctouRaceConditionsWhileAccessingFilesQuery() { - //autogenerate `Query` type - result = - // `Query` type for `toctouRaceConditionsWhileAccessingFiles` query - TQueryC(TIO4PackageQuery(TToctouRaceConditionsWhileAccessingFilesQuery())) - } - - Query useValidFormatStringsQuery() { - //autogenerate `Query` type - result = - // `Query` type for `useValidFormatStrings` query - TQueryC(TIO4PackageQuery(TUseValidFormatStringsQuery())) - } -} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index e2c0f9e0e6..880c95958a 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -5,10 +5,10 @@ import codingstandards.cpp.exclusions.RuleMetadata import Banned import Concurrency1 import Concurrency2 +import Contracts1 import IO1 import IO2 import IO3 -import IO4 import Misc import Pointers1 import Preprocessor1 @@ -28,10 +28,10 @@ newtype TCQuery = TBannedPackageQuery(BannedQuery q) or TConcurrency1PackageQuery(Concurrency1Query q) or TConcurrency2PackageQuery(Concurrency2Query q) or + TContracts1PackageQuery(Contracts1Query q) or TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or TIO3PackageQuery(IO3Query q) or - TIO4PackageQuery(IO4Query q) or TMiscPackageQuery(MiscQuery q) or TPointers1PackageQuery(Pointers1Query q) or TPreprocessor1PackageQuery(Preprocessor1Query q) or @@ -51,10 +51,10 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId) { isBannedQueryMetadata(query, queryId, ruleId) or isConcurrency1QueryMetadata(query, queryId, ruleId) or isConcurrency2QueryMetadata(query, queryId, ruleId) or + isContracts1QueryMetadata(query, queryId, ruleId) or isIO1QueryMetadata(query, queryId, ruleId) or isIO2QueryMetadata(query, queryId, ruleId) or isIO3QueryMetadata(query, queryId, ruleId) or - isIO4QueryMetadata(query, queryId, ruleId) or isMiscQueryMetadata(query, queryId, ruleId) or isPointers1QueryMetadata(query, queryId, ruleId) or isPreprocessor1QueryMetadata(query, queryId, ruleId) or diff --git a/rule_packages/c/Contracts1.json b/rule_packages/c/Contracts1.json new file mode 100644 index 0000000000..c9be4424dd --- /dev/null +++ b/rule_packages/c/Contracts1.json @@ -0,0 +1,48 @@ +{ + "CERT-C": { + "ENV30-C": { + "implementation_scope": { + "description": "None." + }, + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Modification of return values of getenv and similar functions results in undefined behaviour.", + "kind": "path-problem", + "name": "Do not modify the return value of certain functions", + "precision": "very-high", + "severity": "warning", + "short_name": "DoNotModifyTheReturnValueOfCertainFunctions", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not modify the object referenced by the return value of certain functions" + }, + "ENV31-C": { + "implementation_scope": { + "description": "The rule is enforced in the context of a single function." + }, + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Using the envp pointer after environment modifications can result in undefined behavior.", + "kind": "problem", + "name": "Do not rely on an env pointer following an operation that may invalidate it", + "precision": "high", + "severity": "error", + "short_name": "EnvPointerIsInvalidAfterCertainOperations", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not rely on an environment pointer following an operation that may invalidate it" + } + } +} \ No newline at end of file diff --git a/rule_packages/c/IO4.json b/rule_packages/c/IO4.json deleted file mode 100644 index ac1f49cd3a..0000000000 --- a/rule_packages/c/IO4.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "CERT-C": { - "FIO45-C": { - "properties": { - "obligation": "rule" - }, - "queries": [ - { - "description": "Avoid TOCTOU race conditions accessing files", - "kind": "problem", - "name": "Avoid TOCTOU race conditions while accessing files", - "precision": "very-high", - "severity": "error", - "short_name": "ToctouRaceConditionsWhileAccessingFiles", - "tags": [ - "correctness", - "security" - ] - } - ], - "title": "Avoid TOCTOU race conditions while accessing files", - "implementation_scope": { - "description": "None" - } - }, - "FIO47-C": { - "properties": { - "obligation": "rule" - }, - "queries": [ - { - "description": "Use valid format strings", - "kind": "problem", - "name": "Use valid format strings", - "precision": "high", - "severity": "error", - "short_name": "UseValidFormatStrings", - "tags": [ - "correctness", - "security" - ] - } - ], - "title": "Use valid format strings", - "implementation_scope": { - "description": "None" - } - } - } -} \ No newline at end of file diff --git a/rules.csv b/rules.csv index a4b7d16efa..d2f4249b8f 100755 --- a/rules.csv +++ b/rules.csv @@ -540,9 +540,9 @@ c,CERT-C,FIO40-C,Yes,Rule,,,Reset strings on fgets() or fgetws() failure,,IO2,Me c,CERT-C,FIO41-C,Yes,Rule,,,"Do not call getc(), putc(), getwc(), or putwc() with a stream argument that has side effects",,IO2,Medium, c,CERT-C,FIO42-C,Yes,Rule,,,Close files when they are no longer needed,FIO51-CPP,IO1,Medium, c,CERT-C,FIO44-C,Yes,Rule,,,Only use values for fsetpos() that are returned from fgetpos(),,IO2,Medium, -c,CERT-C,FIO45-C,Yes,Rule,,,Avoid TOCTOU race conditions while accessing files,,IO4,Medium, +c,CERT-C,FIO45-C,Yes,Rule,,,Avoid TOCTOU race conditions while accessing files,,IO,Medium, c,CERT-C,FIO46-C,Yes,Rule,,,Do not access a closed file,FIO51-CPP,IO1,Hard, -c,CERT-C,FIO47-C,Yes,Rule,,,Use valid format strings,,IO4,Hard, +c,CERT-C,FIO47-C,Yes,Rule,,,Use valid format strings,,IO,Hard, c,CERT-C,FLP30-C,Yes,Rule,,,Do not use floating-point variables as loop counters,,Statements,Easy, c,CERT-C,FLP32-C,Yes,Rule,,,Prevent or detect domain and range errors in math functions,A0-4-4,Types,Medium, c,CERT-C,FLP34-C,Yes,Rule,,,Ensure that floating-point conversions are within range of the new type,,Types,Medium, From 158c048a7ffd377c1ee097c731b64b602cc0817e Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 12 Aug 2022 19:52:51 +0200 Subject: [PATCH 4/9] Contracts1 --- .../FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql | 3 +-- .../src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql index 04f15a4857..312f525dbc 100644 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql +++ b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql @@ -1,8 +1,7 @@ /** * @id c/cert/do-not-alternately-io-from-a-stream-without-positioning * @name FIO39-C: Do not alternately input and output from a stream without an intervening flush or positioning call - * @description Do not alternate input and output operations on a file without an intervening flush - * or positioning call. + * @description * @kind problem * @precision very-high * @problem.severity error diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql index 2acd27d08b..1828b70ac1 100644 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql +++ b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql @@ -1,7 +1,7 @@ /** * @id c/cert/close-files-when-they-are-no-longer-needed * @name FIO42-C: Close files when they are no longer needed - * @description Close files when they are no longer needed + * @description * @kind problem * @precision very-high * @problem.severity error From 5aa018af7d745204bb31ff57046200564db1d836 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 12 Aug 2022 19:53:55 +0200 Subject: [PATCH 5/9] Contracts1 --- .../FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql | 2 +- c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql index 312f525dbc..bb1cef3259 100644 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql +++ b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql @@ -1,7 +1,7 @@ /** * @id c/cert/do-not-alternately-io-from-a-stream-without-positioning * @name FIO39-C: Do not alternately input and output from a stream without an intervening flush or positioning call - * @description + * @description * @kind problem * @precision very-high * @problem.severity error diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql index 1828b70ac1..28f7d6eb58 100644 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql +++ b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql @@ -1,7 +1,7 @@ /** * @id c/cert/close-files-when-they-are-no-longer-needed * @name FIO42-C: Close files when they are no longer needed - * @description + * @description * @kind problem * @precision very-high * @problem.severity error From 41eeb04be4bdeea161a96ba183b839abbc241b8e Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 12 Aug 2022 19:56:07 +0200 Subject: [PATCH 6/9] Contracts1 --- rule_packages/c/IO1.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rule_packages/c/IO1.json b/rule_packages/c/IO1.json index e6576be906..81167fd296 100644 --- a/rule_packages/c/IO1.json +++ b/rule_packages/c/IO1.json @@ -65,7 +65,7 @@ }, "queries": [ { - "description": "Do not alternate input and output operations on a file without an intervening flush or positioning call.", + "description": "", "kind": "problem", "name": "Do not alternately input and output from a stream without an intervening flush or positioning call", "precision": "very-high", @@ -88,7 +88,7 @@ }, "queries": [ { - "description": "Close files when they are no longer needed", + "description": "", "kind": "problem", "name": "Close files when they are no longer needed", "precision": "very-high", @@ -111,7 +111,7 @@ }, "queries": [ { - "description": "Do not access a closed file", + "description": "Do not access a closed file.", "kind": "problem", "name": "Do not access a closed file", "precision": "high", @@ -136,7 +136,7 @@ }, "queries": [ { - "description": "A closed FILE is accessed", + "description": "A closed FILE is accessed.", "kind": "problem", "name": "The value of a pointer to a FILE shall not be used after the associated stream has been closed", "precision": "very-high", From 3233d1d18f2045d1f344b346cea5f017315704bd Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 12 Aug 2022 20:03:58 +0200 Subject: [PATCH 7/9] Contracts1 --- scripts/generate_rules/generate_package_description.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/scripts/generate_rules/generate_package_description.py b/scripts/generate_rules/generate_package_description.py index 51fb63a97d..d3890e230f 100644 --- a/scripts/generate_rules/generate_package_description.py +++ b/scripts/generate_rules/generate_package_description.py @@ -166,10 +166,7 @@ def generate_short_name(title): "kind" : "problem", "tags" : [] } - ], - "implementation_scope": { - "description": "None." - } + ] } if not package_description: From 4530ed81f3643dab93efaa53a0e2a50068ade261 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 12 Aug 2022 20:06:38 +0200 Subject: [PATCH 8/9] Contracts1 --- rule_packages/c/IO1.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rule_packages/c/IO1.json b/rule_packages/c/IO1.json index 81167fd296..481843d7ff 100644 --- a/rule_packages/c/IO1.json +++ b/rule_packages/c/IO1.json @@ -111,7 +111,7 @@ }, "queries": [ { - "description": "Do not access a closed file.", + "description": "Do not access a closed file", "kind": "problem", "name": "Do not access a closed file", "precision": "high", @@ -136,7 +136,7 @@ }, "queries": [ { - "description": "A closed FILE is accessed.", + "description": "A closed FILE is accessed", "kind": "problem", "name": "The value of a pointer to a FILE shall not be used after the associated stream has been closed", "precision": "very-high", From 625baceeb82b9ea1c1b2c234a70456552d6328f1 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 12 Aug 2022 20:12:04 +0200 Subject: [PATCH 9/9] Contracts1 --- rules.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rules.csv b/rules.csv index d2f4249b8f..158fbb53cb 100755 --- a/rules.csv +++ b/rules.csv @@ -506,8 +506,8 @@ c,CERT-C,DCL38-C,Yes,Rule,,,Use the correct syntax when declaring a flexible arr c,CERT-C,DCL39-C,Yes,Rule,,,Avoid information leakage when passing a structure across a trust boundary,,Declarations,Hard, c,CERT-C,DCL40-C,Yes,Rule,,,Do not create incompatible declarations of the same function or object,,Declarations,Hard, c,CERT-C,DCL41-C,Yes,Rule,,,Do not declare variables inside a switch statement before the first case label,,Declarations,Medium, -c,CERT-C,ENV30-C,Yes,Rule,,,Do not modify the object referenced by the return value of certain functions,RULE-21-19,Contracts,Medium, -c,CERT-C,ENV31-C,Yes,Rule,,,Do not rely on an environment pointer following an operation that may invalidate it,RULE-21-20,Contracts,Hard, +c,CERT-C,ENV30-C,Yes,Rule,,,Do not modify the object referenced by the return value of certain functions,RULE-21-19,Contracts1,Medium, +c,CERT-C,ENV31-C,Yes,Rule,,,Do not rely on an environment pointer following an operation that may invalidate it,RULE-21-20,Contracts1,Hard, c,CERT-C,ENV32-C,Yes,Rule,,,All exit handlers must return normally,,Contracts,Medium, c,CERT-C,ENV33-C,Yes,Rule,,,Do not call system(),"RULE-21-21, M18-0-3",Banned,Easy, c,CERT-C,ENV34-C,Yes,Rule,,,Do not store pointers returned by certain functions,RULE-21-20,Contracts,Medium, @@ -761,8 +761,8 @@ c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type",,Types,Medium, c,MISRA-C-2012,RULE-21-17,Yes,Mandatory,,,Use of the string handling functions from shall not result in accesses beyond the bounds of the objects referenced by their pointer parameters,,Memory,Hard, c,MISRA-C-2012,RULE-21-18,Yes,Mandatory,,,The size_t argument passed to any function in shall have an appropriate value,,Expressions,Medium, -c,MISRA-C-2012,RULE-21-19,Yes,Mandatory,,,"The pointers returned by the Standard Library functions localeconv, getenv, setlocale or, strerror shall only be used as if they have pointer to const-qualified type",ENV30-C,Contracts1,Easy, -c,MISRA-C-2012,RULE-21-20,Yes,Mandatory,,,"The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror shall not be used following a subsequent call to the same function","ENV31-C, ENV34-C",Contracts1,Easy, +c,MISRA-C-2012,RULE-21-19,Yes,Mandatory,,,"The pointers returned by the Standard Library functions localeconv, getenv, setlocale or, strerror shall only be used as if they have pointer to const-qualified type",ENV30-C,Contracts,Easy, +c,MISRA-C-2012,RULE-21-20,Yes,Mandatory,,,"The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror shall not be used following a subsequent call to the same function","ENV31-C, ENV34-C",Contracts,Easy, c,MISRA-C-2012,RULE-21-21,Yes,Required,,,The Standard Library function system of shall not be used,ENV33-C,Banned,Import, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory,Hard,