简体   繁体   中英

Find the vulnerability in the C program

Studying for an exam in software security and came across this but can't find the vulnerability. If you input the name "John Doe" and the salary 4000 then the program will write the string "John Doe: $4000". From what I can tell the program accounts for \0, there is no format string bug, no buffer overflow. Don't know what I missed.

Edit: Forgot to add that the "name" parameter can be assumed to a valid null-terminated string.

/* Calculates the number of letters (i.e. digits) that are needed to represent a decimal number as an ASCII string */
size_t count_digits(unsigned int number)
{
    unsigned int left = number;
    size_t n= 0;
    while(left != 0) {
        left = left / 10;
        n++;
    }
    return n;
}

void add_record(const char* name, unsigned int salary)
{
    char buffer[256];

    size_t len = strlen(name);
    size_t num_digits = count_digits(salary);

    /* 5 extra bytes required for colon and space after name + dollar sign, endline and NULL-terminator */
    if(len > SIZE_MAX - 5 || len + 5 > SIZE_MAX - num_digits) {
        printf("integer overflow");
        exit(1);
    }

    len = len + num_digits + 5;

    if (len > sizeof(buffer)) {
        printf("Too long string");
        exit(1);
    }

    /* Output formatted string to buffer (in the format string, %s denotes a string, and %u denotes an unsigned int that is printed as a decimal number) */
    sprintf(buffer, "%s: $%u\n", name, salary);

    // Write buffer to file
    fputs(buffer, global_file_handle);
}

count_digits incorrectly returns zero for zero. The correct result is one. A name of 251 characters with a salary of zero will require 257 characters (251 for name, 1 for salary, 5 for color, space, dollar sign, new-line, and null), but len will be incorrectly computed as 256, and len > sizeof(buffer) will not be triggered, so the code will overflow buffer .

(Another problem is strlen has undefined behavior when name is not null-terminated, but the context of name is not clear from the problem statement.)

This is not an answer, but an example of what the code potentially should have been to avoid the buffer overflow described by Erik Postpischil.

The count_digits function is wrong (in case of 0 ), but also unnecessary. It is possible to limit the output to buffer using snprintf :

void add_record(const char* name, unsigned int salary)
{
    char buffer[256];
    int len;

    len = snprintf(buffer, sizeof buffer, "%s: $%u\n", name, salary);
    if (len >= sizeof(buffer)) {
        printf("Too long string");
        exit(1);
    }

    fputs(buffer, global_file_handle);
}

Note that if len is exactly equal to sizeof buffer , this will mean that the resulting string was already truncated. In fact, len + 1 is the size that buffer should have been to prevent truncation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM