Main Content

CWE Rule 99

Improper Control of Resource Identifiers ('Resource Injection')

Since R2024b

Description

Rule Description

The software receives input from an upstream component, but it does not restrict or incorrectly restricts the input before it is used as an identifier for a resource that may be outside the intended sphere of control.

Polyspace Implementation

The rule checker checks for Resource Injection.

Examples

expand all

Issue

This issue occurs when these conditions are met:

  • Information such as a port number, filename, or a URL is collected as user input.

  • The input is used in the code as an identifier for a resource without being sanitized or validated.

This can allow a malicious user to access sensitive or restricted data outside the intended resources.

This checker detects the input of data from an untrusted source. Untrusted sources include strings read from stdin using the fread() or fgets() function or from files opened with fopen(). This checker checks only the functions that are directly or indirectly called by the main() function (if there is a main() function).

Risk

If your code allows users to input an identifier used to access a system resource and uses the input without any validation or sanitization, your code is vulnerable to resource injection. A malicious user can inject resource identifiers to access restricted or out-of-scope system resources, which can compromise secure information.

For example, if your code prompts the user to enter a filename, a malicious user could use special characters or directory traversal sequences such as ../ to move to a different folder structure or to specify and access out-of-scope information or system files.

char userInput[256];
printf("Enter the filename: ");
fgets(userInput, sizeof(userInput), stdin);
std::ifstream file(std::string("user_data/") + userInput);
In this case, the user could use a relative path as input to the fgets() function:
../../etc/passwd
This particular user input attempts to access the /etc/passwd file on a Unix-based system by traversing from the location of user_data.

Fix

Validate or sanitize user input before you use it. For example, validating filename inputs can include denying the use of the / character or multiple uses of the . character. If you expect a certain string input, you can check properties such as length and input type.

Extend Checker

If you validate user inputs by using dedicated functions, you can make the resource injection checker aware of your validation and sanitization functions. Suppose that the function resource_validate_inputs() checks user inputs for malicious entries.

int resource_validate_inputs(
     char *,    /* String to check */
     int);      /* Length of string */
Suppose that the nth parameter of this function is the user input to validate. For instance, the first argument in the above signature could be the string to validate.

To make the resource injection checker aware of this function:

  1. Specify this code in a file with extension .dl:

    .include "models/interfaces/resource_injection.dl"
    
    Resource.Basic.validating("resource_validate_inputs", $OutParameterDeref(n-1)).
    
    If n is 1 (that is, the first parameter of the function is the parameter of interest), then the code to include becomes:
    .include "models/interfaces/resource_injection.dl"
    
    Resource.Basic.validating("resource_validate_inputs", $OutParameterDeref(0)).
    

  2. Specify this file using the option -code-behavior-specifications when running a Polyspace® Bug Finder™ analysis at the command line. For instance, if the file is named ResourceAdditionalFunctions.dl, use this analysis option:

    -code-behavior-specifications ResourceAdditionalFunctions.dl

Example — User Input Not Validated or Sanitized
#include <cstdio>
#include <cstring>

int main() {
    char userInputFilename[256];
    FILE *file;
    const size_t bufferSize = 1024;
    char buffer[bufferSize];

    printf("Enter the filename: ");
    fgets(userInputFilename, sizeof(userInputFilename), stdin);

    userInputFilename[strcspn(userInputFilename, "\n")] = 0;

    file = fopen(userInputFilename, "rb");     // Defect                   
    if (file == NULL) {
        perror("Error opening file");
        return 1;
    }

    size_t bytesRead = fread(buffer, 1, bufferSize - 1, file);
    buffer[bytesRead] = '\0'; // Null-terminate the string

    printf("Data read from the file:\n%s\n", buffer);
    fclose(file);
    return 0;
}

In this example, the code prompts the user to enter a filename and then uses it to navigate to a file. The code then opens, reads, and prints the data from the specified file. However, the code never sanitizes or validates the user input, allowing the potential for a malicious user to navigate to and read the contents of out-of-scope information.

Correction — Validate and sanitize user input before use

You can write your own functions to validate or sanitize the input before using the input to navigate to the resource. In this example, the validation function isValidFilename() validates the user input by preventing the use of characters that could lead to path traversal.

#include <cstdio>
#include <cstring>

bool isValidFilename(const char *filename) {
    //Check for invalid characters or patterns that could lead to path traversal
    for (const char *p = filename; *p; ++p) {
        if (*p == '/' || *p == '\\' || (*p == '.' && *(p + 1) == '.')) {
            return false;
        }
    }
    return true;
}



int main() {
    char userInputFilename[256];
    FILE *file;
    const size_t bufferSize = 1024;
    char buffer[bufferSize];

    // Ask user for the filename
    printf("Enter the filename: ");
    fgets(userInputFilename, sizeof(userInputFilename), stdin);

    // Remove the newline character if present
    userInputFilename[strcspn(userInputFilename, "\n")] = 0;

    // Validate the filename
    if (!isValidFilename(userInputFilename)) {
        printf("Invalid filename.\n");
        return 1;
    }

    
    // Open the file using the safe file path
    file = fopen(userInputFilename, "rb");    // No defect
    if (file == NULL) {
        perror("Error opening file");
        return 1;
    }

    return 0;
}

To make the Polyspace analysis aware of a validation or sanitation function such as isValidFilename() from the example:

  1. Specify this code in a file with extension .dl (for example, sanitizeFunctions.dl):

    .include "models/interfaces/resource_injection.dl"
    
    Resource.Basic.sanitizing("isValidFilename", $OutParameterDeref(0)).
    

  2. Specify this file using the option -code-behavior-specifications when running a Polyspace Bug Finder analysis at the command line.

    -code-behavior-specifications sanitizeFunctions.dl

    See also -code-behavior-specifications.

Check Information

Category: Others

Version History

Introduced in R2024b