主要内容

CERT C: Rec. WIN03-C

Understand HANDLE inheritance

Since R2026a

Description

Understand HANDLE inheritance1

Polyspace Implementation

The rule checker checks for these issues:

  • Child process can inherit mutex handle

  • Handle not duplicated

  • File handle inheritable

Examples

expand all

Issue

This issue occurs when the functions OpenMutex() and CreateProcess() are called without explicitly setting the bInheritHandle parameter to FALSE. For example, this code opens the handle for the existing mutex myMutex, but the parameter bInheritHandle is set to TRUE, which allows any child process to inherit hMutex.

HANDLE hMutex = OpenMutex(myMutex, TRUE, TEXT("Global\\CommonMutex")); 
Polyspace® reports a violation.

Risk

Unless the child process closes all the inherited handles before it exits, the handles can leak. Allowing mutex handles to be inherited by any child process increases the possibility of a resource leak.

Fix

Set the bInheritHandle parameter of OpenMutex() and CreateProcess() to FALSE

Example

This code shows mutex handles can be inherited by child processes. Polyspace reports a violation.

#include <Windows.h>
#include <stdio.h>

int main() {
    HANDLE hMutex;
    BOOL createdNew = FALSE;

    // Create a named mutex
    hMutex = CreateMutex(NULL, TRUE, TEXT("Global\\CommonMutex")); 

    if (hMutex == NULL) {
        printf("CreateMutex error: %d\n", GetLastError());
        return 1;
    }

    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        printf("Mutex already exists. Opening existing mutex.\n");
        createdNew = FALSE;
    } else {
        printf("New mutex created.\n");
        createdNew = TRUE;
    }

    // Open the existing mutex
    HANDLE hMutexOpen = OpenMutex(MUTEX_ALL_ACCESS, TRUE, TEXT("Global\\CommonMutex")); //Noncompliant
    if (hMutexOpen == NULL) {
        printf("OpenMutex error: %d\n", GetLastError());
        CloseHandle(hMutex);
        return 1;
    }

    printf("Mutex opened successfully.\n");
/*
    // Simulate some work with the mutex
    WaitForSingleObject(hMutex, INFINITE);
    printf("Mutex acquired.\n");
    Sleep(2000); // Simulate work
    ReleaseMutex(hMutex);
    printf("Mutex released.\n");
*/
    // Clean up handles
    CloseHandle(hMutex);
    CloseHandle(hMutexOpen);

    return 0;
}

Correction

To fix the violations, set the inheritance parameter of OpenMutex() to False.

#include <Windows.h>
#include <stdio.h>

int main() {
    HANDLE hMutex;
    BOOL createdNew = FALSE;

    // Create a named mutex
    hMutex = CreateMutex(NULL, FALSE, TEXT("Global\\CommonMutex")); //Compliant

    if (hMutex == NULL) {
        printf("CreateMutex error: %d\n", GetLastError());
        return 1;
    }

    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        printf("Mutex already exists. Opening existing mutex.\n");
        createdNew = FALSE;
    } else {
        printf("New mutex created.\n");
        createdNew = TRUE;
    }

    // Open the existing mutex
    HANDLE hMutexOpen = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXT("Global\\CommonMutex")); //Compliant
    if (hMutexOpen == NULL) {
        printf("OpenMutex error: %d\n", GetLastError());
        CloseHandle(hMutex);
        return 1;
    }

    printf("Mutex opened successfully.\n");
/*
    // Simulate some work with the mutex
    WaitForSingleObject(hMutex, INFINITE);
    printf("Mutex acquired.\n");
    Sleep(2000); // Simulate work
    ReleaseMutex(hMutex);
    printf("Mutex released.\n");
*/
    // Clean up handles
    CloseHandle(hMutex);
    CloseHandle(hMutexOpen);

    return 0;
}

Issue

This issue occurs when a handle is initialized by a call to a string-to-number conversion function but the handle is not duplicated by calling the function DuplicateHandle. For example, this code initializes a handle using the command-line input but the function DuplicateHandle is not called. Polyspace reports a violation.

void foo(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR cmdLine, int show){
HANDLE hUntrusted = (HANDLE) strtoll (cmdLine, NULL, 16); // Violation
}
Examples of recognized string-to-number conversion functions include: strtoimax, strtoumax, strtol, strtoul, strtoll, strtoull, wcstoimax, wcstoumax, wcstol, wcstoul, wcstoll, and wcstoull.

Risk

Handles created using command-line inputs are not guaranteed to be valid. These handles are inheritable and child processes inherit these handles by default. The resource leaks if the child process fail to close the inherited handles

Fix

After creating a handle using the command-line input, duplicate the handle using DuplicateHandle(). This function checks if the created handle is valid and allows you to set the inheritance of the duplicated handle to FALSE. Use the duplicated handle in subsequent code.

Example

In this example, the handle hUntrusted is initialized using the string cmdline, which is a command-line input. The function uses this handle without any sanitization. Polyspace reports a violation.

#include <Windows.h>
#include <stdio.h>

int CALLBACK foo(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR cmdLine, int show)

{

	HANDLE hUntrusted = (HANDLE) strtoll(cmdLine, NULL, 16); //Noncompliant
	HANDLE hFile = NULL;
	//...
    printf("%X", hUntrusted);
	//...
}

Correction

To fix this issue, duplicate the handle hUntrusted by calling DuplicateHandle(). Set the inheritance parameter to FALSE.

#include <Windows.h>
#include <stdio.h>
int CALLBACK foo(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR cmdLine, int show)
{
	HANDLE hUntrusted = (HANDLE) strtoll(cmdLine, NULL, 16); 
	HANDLE hFile = NULL;
	if (!DuplicateHandle (GetCurrentProcess (), hUntrusted, GetCurrentProcess (), &hFile,  //Compliant
                       0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE)) { // Inheritance disabled

    // Handle invalid handle

  }

  //...
}

Issue

This issue occurs when files are opened without explicitly specifying that the file handle cannot be inherited by child processes. That is, the function fopen() or fopen_s() is called without appending N to the mode specifier.

Risk

Files that are opened without using the N specifier can be inherited by child processes. If the child process fails to close the inherited file handles, the files can leak.

Fix

When opening files using fopen() or fopen_s(), append N to the mode specifier argument.

Example

This code opens file without specifying them as non-inheritable. Polyspace reports violations.

#include <Windows.h>
#include <stdio.h>

void foo(void) {

	FILE *fp;

	fp = fopen("filename", "a+");  //Noncompliant                    
	fp = fopen("filename", "w");   //Noncompliant                   
	fp = fopen("filename", "w+");   //Noncompliant

}

Correction

To fix this violation, append N to the mode specifier.

#include <Windows.h>
#include <stdio.h>

void foo(void) {

	FILE *fp;

	fp = fopen("filename", "a+N");  //Compliant                    
	fp = fopen("filename", "wN");   //Compliant                   
	fp = fopen("filename", "wN+");   //Compliant

}

Check Information

Group: Rec. 51. Microsoft Windows (WIN)
PQL Name: std.cert.WIN03_C

Version History

Introduced in R2026a


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.