Skip to content

Commit 0be6b45

Browse files
committed
Fix CI issues
1 parent d10812f commit 0be6b45

File tree

8 files changed

+764
-9
lines changed

8 files changed

+764
-9
lines changed

c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.md

Lines changed: 362 additions & 2 deletions
Large diffs are not rendered by default.

c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.md

Lines changed: 168 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,175 @@ This query implements the CERT-C rule SIG31-C:
55
> Do not access shared objects in signal handlers
66
77

8-
## CERT
98

10-
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
## Description
10+
11+
Accessing or modifying shared objects in signal handlers can result in race conditions that can leave data in an inconsistent state. The two exceptions (C Standard, 5.1.2.3, paragraph 5) to this rule are the ability to read from and write to lock-free atomic objects and variables of type `volatile sig_atomic_t`. Accessing any other type of object from a signal handler is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). (See [undefined behavior 131](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_131).)
12+
13+
The need for the `volatile` keyword is described in [DCL22-C. Use volatile for data that cannot be cached](https://wiki.sei.cmu.edu/confluence/display/c/DCL22-C.+Use+volatile+for+data+that+cannot+be+cached).
14+
15+
The type `sig_atomic_t` is the integer type of an object that can be accessed as an atomic entity even in the presence of asynchronous interrupts. The type of `sig_atomic_t` is [implementation-defined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation-definedbehavior), though it provides some guarantees. Integer values ranging from `SIG_ATOMIC_MIN` through `SIG_ATOMIC_MAX`, inclusive, may be safely stored to a variable of the type. In addition, when `sig_atomic_t` is a signed integer type, `SIG_ATOMIC_MIN` must be no greater than `−127` and `SIG_ATOMIC_MAX` no less than `127`. Otherwise, `SIG_ATOMIC_MIN` must be `0` and `SIG_ATOMIC_MAX` must be no less than `255`. The macros `SIG_ATOMIC_MIN` and `SIG_ATOMIC_MAX` are defined in the header `<stdint.h>`.
16+
17+
According to the C99 Rationale \[[C99 Rationale 2003](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-C992003)\], other than calling a limited, prescribed set of library functions,
18+
19+
> the C89 Committee concluded that about the only thing a [strictly conforming](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-strictlyconforming) program can do in a signal handler is to assign a value to a `volatile static` variable which can be written uninterruptedly and promptly return.
20+
21+
22+
However, this issue was discussed at the April 2008 meeting of ISO/IEC WG14, and it was agreed that there are no known [implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) in which it would be an error to read a value from a `volatile sig_atomic_t` variable, and the original intent of the committee was that both reading and writing variables of `volatile sig_atomic_t` would be strictly conforming.
23+
24+
The signal handler may also call a handful of functions, including `abort().` (See [SIG30-C. Call only asynchronous-safe functions within signal handlers](https://wiki.sei.cmu.edu/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers) for more information.)
25+
26+
## Noncompliant Code Example
27+
28+
In this noncompliant code example, `err_msg` is updated to indicate that the `SIGINT` signal was delivered. The `err_msg` variable is a character pointer and not a variable of type `volatile sig_atomic_t`.
29+
30+
```cpp
31+
#include <signal.h>
32+
#include <stdlib.h>
33+
#include <string.h>
34+
35+
enum { MAX_MSG_SIZE = 24 };
36+
char *err_msg;
37+
38+
void handler(int signum) {
39+
strcpy(err_msg, "SIGINT encountered.");
40+
}
41+
42+
int main(void) {
43+
signal(SIGINT, handler);
44+
45+
err_msg = (char *)malloc(MAX_MSG_SIZE);
46+
if (err_msg == NULL) {
47+
/* Handle error */
48+
}
49+
strcpy(err_msg, "No errors yet.");
50+
/* Main code loop */
51+
return 0;
52+
}
53+
54+
```
55+
56+
## Compliant Solution (Writing volatile sig_atomic_t)
57+
58+
For maximum portability, signal handlers should only unconditionally set a variable of type `volatile sig_atomic_t` and return, as in this compliant solution:
59+
60+
```cpp
61+
#include <signal.h>
62+
#include <stdlib.h>
63+
#include <string.h>
64+
65+
enum { MAX_MSG_SIZE = 24 };
66+
volatile sig_atomic_t e_flag = 0;
67+
68+
void handler(int signum) {
69+
e_flag = 1;
70+
}
71+
72+
int main(void) {
73+
char *err_msg = (char *)malloc(MAX_MSG_SIZE);
74+
if (err_msg == NULL) {
75+
/* Handle error */
76+
}
77+
78+
signal(SIGINT, handler);
79+
strcpy(err_msg, "No errors yet.");
80+
/* Main code loop */
81+
if (e_flag) {
82+
strcpy(err_msg, "SIGINT received.");
83+
}
84+
return 0;
85+
}
86+
87+
```
88+
89+
## Compliant Solution (Lock-Free Atomic Access)
90+
91+
Signal handlers can refer to objects with static or thread storage durations that are lock-free atomic objects, as in this compliant solution:
92+
93+
```cpp
94+
#include <signal.h>
95+
#include <stdlib.h>
96+
#include <string.h>
97+
#include <stdatomic.h>
98+
99+
#ifdef __STDC_NO_ATOMICS__
100+
#error "Atomics are not supported"
101+
#elif ATOMIC_INT_LOCK_FREE == 0
102+
#error "int is never lock-free"
103+
#endif
104+
105+
atomic_int e_flag = ATOMIC_VAR_INIT(0);
106+
107+
void handler(int signum) {
108+
e_flag = 1;
109+
}
110+
111+
int main(void) {
112+
enum { MAX_MSG_SIZE = 24 };
113+
char err_msg[MAX_MSG_SIZE];
114+
#if ATOMIC_INT_LOCK_FREE == 1
115+
if (!atomic_is_lock_free(&e_flag)) {
116+
return EXIT_FAILURE;
117+
}
118+
#endif
119+
if (signal(SIGINT, handler) == SIG_ERR) {
120+
return EXIT_FAILURE;
121+
}
122+
strcpy(err_msg, "No errors yet.");
123+
/* Main code loop */
124+
if (e_flag) {
125+
strcpy(err_msg, "SIGINT received.");
126+
}
127+
return EXIT_SUCCESS;
128+
}
129+
130+
```
131+
132+
## Exceptions
133+
134+
**SIG31-C-EX1:** The C Standard, 7.14.1.1 paragraph 5 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\], makes a special exception for `errno` when a valid call to the `signal()` function results in a `SIG_ERR` return, allowing `errno` to take an indeterminate value. (See [ERR32-C. Do not rely on indeterminate values of errno](https://wiki.sei.cmu.edu/confluence/display/c/SIG31-C.+Do+not+access+shared+objects+in+signal+handlers#).)
135+
136+
## Risk Assessment
137+
138+
Accessing or modifying shared objects in signal handlers can result in accessing data in an inconsistent state. Michal Zalewski's paper "Delivering Signals for Fun and Profit" \[[Zalewski 2001](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Zalewski01)\] provides some examples of [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) that can result from violating this and other signal-handling rules.
139+
140+
<table> <tbody> <tr> <th> Rule </th> <th> Severity </th> <th> Likelihood </th> <th> Remediation Cost </th> <th> Priority </th> <th> Level </th> </tr> <tr> <td> SIG31-C </td> <td> High </td> <td> Likely </td> <td> High </td> <td> <strong>P9</strong> </td> <td> <strong>L2</strong> </td> </tr> </tbody> </table>
141+
142+
143+
## Automated Detection
144+
145+
<table> <tbody> <tr> <th> Tool </th> <th> Version </th> <th> Checker </th> <th> Description </th> </tr> <tr> <td> <a> Astrée </a> </td> <td> 22.04 </td> <td> <strong>signal-handler-shared-access</strong> </td> <td> Partially checked </td> </tr> <tr> <td> <a> Axivion Bauhaus Suite </a> </td> <td> 7.2.0 </td> <td> <strong>CertC-SIG31</strong> </td> <td> </td> </tr> <tr> <td> <a> CodeSonar </a> </td> <td> 7.2p0 </td> <td> <strong>CONCURRENCY.DATARACE</strong> </td> <td> Data race </td> </tr> <tr> <td> <a> Compass/ROSE </a> </td> <td> </td> <td> </td> <td> Can detect violations of this rule for single-file programs </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.4 </td> <td> <strong>C2029, C2030</strong> <strong>C++3854, C++3855</strong> </td> <td> </td> </tr> <tr> <td> <a> LDRA tool suite </a> </td> <td> 9.7.1 </td> <td> <strong>87 D</strong> </td> <td> Fully implemented </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.2 </td> <td> <strong>CERT_C-SIG31-a</strong> </td> <td> Properly define signal handlers </td> </tr> <tr> <td> <a> PC-lint Plus </a> </td> <td> 1.4 </td> <td> <strong>2765</strong> </td> <td> Fully supported </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022b </td> <td> <a> CERT C: Rule SIG31-C </a> </td> <td> Checks for shared data access within signal handler (rule partially covered) </td> </tr> <tr> <td> <a> PRQA QA-C </a> </td> <td> 9.7 </td> <td> <strong>2029, 2030</strong> </td> <td> </td> </tr> <tr> <td> <a> RuleChecker </a> </td> <td> 22.04 </td> <td> <strong>signal-handler-shared-access</strong> </td> <td> Partially checked </td> </tr> </tbody> </table>
146+
147+
148+
## Related Vulnerabilities
149+
150+
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+SIG31-C).
151+
152+
## Related Guidelines
153+
154+
[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions)
155+
156+
<table> <tbody> <tr> <th> Taxonomy </th> <th> Taxonomy item </th> <th> Relationship </th> </tr> <tr> <td> <a> ISO/IEC TS 17961:2013 </a> </td> <td> Accessing shared objects in signal handlers \[accsig\] </td> <td> Prior to 2018-01-12: CERT: Unspecified Relationship </td> </tr> <tr> <td> <a> CWE 2.11 </a> </td> <td> <a> CWE-662 </a> , Improper Synchronization </td> <td> 2017-07-10: CERT: Rule subset of CWE </td> </tr> <tr> <td> <a> CWE 2.11 </a> </td> <td> <a> CWE-828 </a> , Signal Handler with Functionality that is not Asynchronous-Safe </td> <td> 2017-10-30:MITRE:Unspecified Relationship 2018-10-19:CERT: Rule subset of CWE </td> </tr> </tbody> </table>
157+
158+
159+
## CERT-CWE Mapping Notes
160+
161+
[Key here](https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152408#HowthisCodingStandardisOrganized-CERT-CWEMappingNotes) for mapping notes
162+
163+
**CWE-662 and SIG31-C**
164+
165+
CWE-662 = Union( SIG31-C, list) where list =
166+
167+
* Improper synchronization of shared objects between threads
168+
* Improper synchronization of files between programs (enabling TOCTOU race conditions
169+
**CWE-828 and SIG31-C**
170+
171+
CWE-828 = SIG31-C + non-async-safe things besides shared objects.
172+
173+
## Bibliography
174+
175+
<table> <tbody> <tr> <td> \[ <a> C99 Rationale 2003 </a> \] </td> <td> 5.2.3, "Signals and Interrupts" </td> </tr> <tr> <td> \[ <a> ISO/IEC 9899:2011 </a> \] </td> <td> Subclause 7.14.1.1, "The <code>signal</code> Function" </td> </tr> <tr> <td> \[ <a> Zalewski 2001 </a> \] </td> <td> </td> </tr> </tbody> </table>
176+
11177
12178
## Implementation notes
13179

c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.md

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,135 @@ This query implements the CERT-C rule SIG34-C:
55
> Do not call signal() from within interruptible signal handlers
66
77

8-
## CERT
98

10-
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
## Description
10+
11+
A signal handler should not reassert its desire to handle its own signal. This is often done on *nonpersistent* platforms—that is, platforms that, upon receiving a signal, reset the handler for the signal to SIG_DFL before calling the bound signal handler. Calling` signal()` under these conditions presents a race condition. (See [SIG01-C. Understand implementation-specific details regarding signal handler persistence](https://wiki.sei.cmu.edu/confluence/display/c/SIG01-C.+Understand+implementation-specific+details+regarding+signal+handler+persistence).)
12+
13+
A signal handler may call `signal()` only if it does not need to be [asynchronous-safe](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-asynchronous-safefunction) (that is, if all relevant signals are masked so that the handler cannot be interrupted).
14+
15+
## Noncompliant Code Example (POSIX)
16+
17+
On nonpersistent platforms, this noncompliant code example contains a race window, starting when the host environment resets the signal and ending when the handler calls `signal()`. During that time, a second signal sent to the program will trigger the default signal behavior, consequently defeating the persistent behavior implied by the call to `signal()` from within the handler to reassert the binding.
18+
19+
If the environment is persistent (that is, it does not reset the handler when the signal is received), the `signal()` call from within the `handler()` function is redundant.
20+
21+
```cpp
22+
#include <signal.h>
23+
24+
void handler(int signum) {
25+
if (signal(signum, handler) == SIG_ERR) {
26+
/* Handle error */
27+
}
28+
/* Handle signal */
29+
}
30+
31+
void func(void) {
32+
if (signal(SIGUSR1, handler) == SIG_ERR) {
33+
/* Handle error */
34+
}
35+
}
36+
```
37+
38+
## Compliant Solution (POSIX)
39+
40+
Calling the `signal()` function from within the signal handler to reassert the binding is unnecessary for persistent platforms, as in this compliant solution:
41+
42+
```cpp
43+
#include <signal.h>
44+
45+
void handler(int signum) {
46+
/* Handle signal */
47+
}
48+
49+
void func(void) {
50+
if (signal(SIGUSR1, handler) == SIG_ERR) {
51+
/* Handle error */
52+
}
53+
}
54+
```
55+
56+
## Compliant Solution (POSIX)
57+
58+
POSIX defines the `sigaction()` function, which assigns handlers to signals in a similar manner to `signal()` but allows the caller to explicitly set persistence. Consequently, the `sigaction()` function can be used to eliminate the race window on nonpersistent platforms, as in this compliant solution:
59+
60+
```cpp
61+
#include <signal.h>
62+
#include <stddef.h>
63+
64+
void handler(int signum) {
65+
/* Handle signal */
66+
}
67+
68+
void func(void) {
69+
struct sigaction act;
70+
act.sa_handler = handler;
71+
act.sa_flags = 0;
72+
if (sigemptyset(&act.sa_mask) != 0) {
73+
/* Handle error */
74+
}
75+
if (sigaction(SIGUSR1, &act, NULL) != 0) {
76+
/* Handle error */
77+
}
78+
}
79+
```
80+
Although the handler in this example does not call `signal()`, it could do so safely because the signal is masked and the handler cannot be interrupted. If the same handler is installed for more than one signal, the signals must be masked explicitly in `act.sa_mask` to ensure that the handler cannot be interrupted because the system masks only the signal being delivered.
81+
82+
POSIX recommends that new applications should use `sigaction()` rather than `signal()`. The `sigaction()` function is not defined by the C Standard and is not supported on some platforms, including Windows.
83+
84+
## Compliant Solution (Windows)
85+
86+
There is no safe way to implement persistent signal-handler behavior on Windows platforms, and it should not be attempted. If a design depends on this behavior, and the design cannot be altered, it may be necessary to claim a deviation from this rule after completing an appropriate risk analysis.
87+
88+
The reason for this is that Windows is a nonpersistent platform as discussed above. Just before calling the current handler function, Windows resets the handler for the next occurrence of the same signal to `SIG_DFL`. If the handler calls `signal()` to reinstall itself, there is still a race window. A signal might occur between the start of the handler and the call to `signal()`, which would invoke the default behavior instead of the desired handler.
89+
90+
## Exceptions
91+
92+
**SIG34-C-EX1:** For implementations with persistent signal handlers, it is safe for a handler to modify the behavior of its own signal. Behavior modifications include ignoring the signal, resetting to the default behavior, and having the signal handled by a different handler. A handler reasserting its binding is also safe but unnecessary.
93+
94+
The following code example resets a signal handler to the system's default behavior:
95+
96+
```cpp
97+
#include <signal.h>
98+
99+
void handler(int signum) {
100+
#if !defined(_WIN32)
101+
if (signal(signum, SIG_DFL) == SIG_ERR) {
102+
/* Handle error */
103+
}
104+
#endif
105+
/* Handle signal */
106+
}
107+
108+
void func(void) {
109+
if (signal(SIGUSR1, handler) == SIG_ERR) {
110+
/* Handle error */
111+
}
112+
}
113+
```
114+
115+
## Risk Assessment
116+
117+
Two signals in quick succession can trigger a race condition on nonpersistent platforms, causing the signal's default behavior despite a handler's attempt to override it.
118+
119+
<table> <tbody> <tr> <th> Rule </th> <th> Severity </th> <th> Likelihood </th> <th> Remediation Cost </th> <th> Priority </th> <th> Level </th> </tr> <tr> <td> SIG34-C </td> <td> Low </td> <td> Unlikely </td> <td> Low </td> <td> <strong>P3</strong> </td> <td> <strong>L3</strong> </td> </tr> </tbody> </table>
120+
121+
122+
## Automated Detection
123+
124+
<table> <tbody> <tr> <th> Tool </th> <th> Version </th> <th> Checker </th> <th> Description </th> </tr> <tr> <td> <a> Astrée </a> </td> <td> 22.04 </td> <td> <strong>signal-handler-signal-call</strong> </td> <td> Partially checked </td> </tr> <tr> <td> <a> Axivion Bauhaus Suite </a> </td> <td> 7.2.0 </td> <td> <strong>CertC-SIG34</strong> </td> <td> </td> </tr> <tr> <td> <a> CodeSonar </a> </td> <td> 7.2p0 </td> <td> <strong>BADFUNC.SIGNAL</strong> </td> <td> Use of signal </td> </tr> <tr> <td> <a> Compass/ROSE </a> </td> <td> </td> <td> </td> <td> Can detect violations of this rule. However, false positives may occur on systems with persistent handlers </td> </tr> <tr> <td> <a> Helix QAC </a> </td> <td> 2022.4 </td> <td> <strong>C5021</strong> <strong>C++5022</strong> </td> <td> </td> </tr> <tr> <td> <a> Klocwork </a> </td> <td> 2022.4 </td> <td> <strong>MISRA.STDLIB.SIGNAL</strong> </td> <td> </td> </tr> <tr> <td> <a> LDRA tool suite </a> </td> <td> 9.7.1 </td> <td> <strong>97 D</strong> </td> <td> Fully implemented </td> </tr> <tr> <td> <a> Parasoft C/C++test </a> </td> <td> 2022.2 </td> <td> <strong>CERT_C-SIG34-a</strong> </td> <td> Properly define signal handlers </td> </tr> <tr> <td> <a> PC-lint Plus </a> </td> <td> 1.4 </td> <td> <strong>2762, 2763</strong> </td> <td> Fully supported </td> </tr> <tr> <td> <a> Polyspace Bug Finder </a> </td> <td> R2022b </td> <td> <a> CERT C: Rule SIG34-C </a> </td> <td> Checks for signal call from within signal handler (rule partially covered) </td> </tr> <tr> <td> <a> PRQA QA-C </a> </td> <td> 9.7 </td> <td> <strong>5021</strong> </td> <td> Partially implemented </td> </tr> <tr> <td> <a> PRQA QA-C++ </a> </td> <td> 4.4 </td> <td> <strong>5022</strong> </td> <td> </td> </tr> <tr> <td> <a> RuleChecker </a> </td> <td> 22.04 </td> <td> <strong>signal-handler-signal-call</strong> </td> <td> Partially checked </td> </tr> </tbody> </table>
125+
126+
127+
## Related Vulnerabilities
128+
129+
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+SIG34-C).
130+
131+
## Related Guidelines
132+
133+
[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions)
134+
135+
<table> <tbody> <tr> <th> Taxonomy </th> <th> Taxonomy item </th> <th> Relationship </th> </tr> <tr> <td> <a> CERT C Secure Coding Standard </a> </td> <td> <a> SIG01-C. Understand implementation-specific details regarding signal handler persistence </a> </td> <td> Prior to 2018-01-12: CERT: Unspecified Relationship </td> </tr> <tr> <td> <a> ISO/IEC TS 17961:2013 </a> </td> <td> Calling signal from interruptible signal handlers \[sigcall\] </td> <td> Prior to 2018-01-12: CERT: Unspecified Relationship </td> </tr> </tbody> </table>
136+
11137

12138
## Implementation notes
13139

0 commit comments

Comments
 (0)