Main Content

CWE Rule 922

Insecure Storage of Sensitive Information

Since R2023a

Description

Rule Description

The software stores sensitive information without properly limiting read or write access by unauthorized actors.

Polyspace Implementation

The rule checker checks for these issues:

  • File manipulation after chroot() without chdir("/")

  • Umask used with chmod-style arguments

  • Use of non-secure temporary file

  • Vulnerable permission assignments

Examples

expand all

Issue

This issue occurs when you have access to a file system outside of the jail created by chroot. By calling chroot, you create a file system jail that confines access to a specific file subsystem. However, this jail is ineffective if you do not call chdir("/").

Risk

If you do not call chdir("/") after creating a chroot jail, file manipulation functions that takes a path as an argument can access files outside of the jail. An attacker can still manipulate files outside the subsystem that you specified, making the chroot jail ineffective.

Fix

After calling chroot, call chdir("/") to make your chroot jail more secure.

Example — Open File in chroot-jail
#include <unistd.h>
#include <stdio.h>

const char root_path[] = "/var/ftproot";
const char log_path[] = "file.log";
FILE* chrootmisuse() {
    FILE* res;
    chroot(root_path);
    chdir("base");  //Noncompliant
    res = fopen(log_path, "r");  //Noncompliant
    return res;
}

This example uses chroot to create a chroot-jail. However, to use the chroot jail securely, you must call chdir("\") afterward. This example calls chdir("base"), which is not equivalent. Bug Finder also flags fopen because fopen opens a file in the vulnerable chroot-jail.

Correction — Call chdir("/")

Before opening files, call chdir("/").

#include <unistd.h>
#include <stdio.h>

const char root_path[] = "/var/ftproot";
const char log_path[] = "file.log";
FILE* chrootmisuse() {
    FILE* res;
    chroot(root_path);
    chdir("/");    
    res = fopen(log_path, "r");
    return res;
}
Issue

This issue occurs when umask commands have arguments specified in the style of arguments to chmod and provide possibly unintended permissions. For instance:

  • The umask command provides more permissions to the group than the current user.

  • The umask command provides more permissions to other users than the group.

For new files, the umask argument or the mask value specifies which permissions not to set, in other words, which permissions to remove. The mask is bitwise-negated and then applied to new file permissions. In contrast, chmod sets the permissions as you specify them.

Risk

If you use chmod-style arguments, you specify opposite permissions of what you want. This mistake can give external users unintended read/write access to new files and folders.

Fix

To fix this defect, perform both of these tasks:

  • Enable read permission for the user.

  • Set the mask value so that the user (u) has equal or fewer permissions turned off than the group (g) and the group has equal or fewer permissions turned off than other users (o), or u <= g <= o.

You can see the umask value by calling,

umask
or the symbolic value by calling,
umask -S

Example — Setting the Default Mask
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>

typedef mode_t (*umask_func)(mode_t);

const mode_t default_mode = (
    S_IRUSR    /* 00400 */ 
    | S_IWUSR  /* 00200 */ 
    | S_IRGRP  /* 00040 */ 
    | S_IWGRP  /* 00020 */
    | S_IROTH  /* 00004 */
    | S_IWOTH  /* 00002 */
    );         /* 00666 (i.e. -rw-rw-rw-) */

static void my_umask(mode_t mode)
{
    umask(mode);  //Noncompliant
}

int umask_use(mode_t m)
{
    my_umask(default_mode);
    return 0;
}

This example uses a function called my_umask to set the default mask mode. However, the default_mode variable gives the permissions 666 or -rw-rw-rw. umask negates this value. However, this negation means the default mask mode turns off read/write permissions for the user, group users, and other outside users.

Correction — Negate Preferred Permissions

One possible correction is to negate the default_mode argument to my_umask. This correction nullifies the negation umask for new files.

#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>

typedef mode_t (*umask_func)(mode_t);

const mode_t default_mode = (
    S_IRUSR    /* 00400 */ 
    | S_IWUSR  /* 00200 */ 
    | S_IRGRP  /* 00040 */ 
    | S_IWGRP  /* 00020 */
    | S_IROTH  /* 00004 */
    | S_IWOTH  /* 00002 */
    );         /* 00666 (i.e. -rw-rw-rw-) */

static void my_umask(mode_t mode)
{
    umask(mode);
}

int umask_use(mode_t m)
{
    my_umask(~default_mode);
    return 0;
}
Issue

This issue occurs when you use temporary file routines that are not secure.

Risk

If an attacker guesses the file name generated by a standard temporary file routine, the attacker can:

  • Cause a race condition when you generate the file name.

  • Precreate a file of the same name, filled with malicious content. If your program reads the file, the attacker’s file can inject the malicious code.

  • Create a symbolic link to a file storing sensitive data. When your program writes to the temporary file, the sensitive data is deleted.

Fix

To create temporary files, use a more secure standard temporary file routine, such as mkstemp from POSIX.1-2001.

Also, when creating temporary files with routines that allow flags, such as mkostemp, use the exclusion flag O_EXCL to avoid race conditions.

Example — Temp File Created With tempnam
#define _BSD_SOURCE
#define _XOPEN_SOURCE 
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int test_temp()
{
    char tpl[] = "abcXXXXXX";
    char suff_tpl[] = "abcXXXXXXsuff";
    char *filename = NULL;
    int fd;
    
    filename = tempnam("/var/tmp", "foo_");
    
    if (filename != NULL)
    {
        printf("generated tmp name (%s) in (%s:%s:%s)\n", 
               filename, getenv("TMPDIR") ? getenv("TMPDIR") : "$TMPDIR",
               "/var/tmp", P_tmpdir);
        
        fd = open(filename, O_CREAT, S_IRWXU|S_IRUSR);  //Noncompliant
        if (fd != -1)
        {
            close(fd);
            unlink(filename);
            return 1;
        }
    }
    return 0;
}

In this example, Bug Finder flags open because it tries to use an unsecure temporary file. The file is opened without exclusive privileges. An attacker can access the file causing various risks.

Correction — Add O_EXCL Flag

One possible correction is to add the O_EXCL flag when you open the temporary file.

#define _BSD_SOURCE
#define _XOPEN_SOURCE 
#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int test_temp()
{
    char tpl[] = "abcXXXXXX";
    char suff_tpl[] = "abcXXXXXXsuff";
    char *filename = NULL;
    int fd;
    
    filename = tempnam("/var/tmp", "foo_");
    
    if (filename != NULL)
    {
        printf("generated tmp name (%s) in (%s:%s:%s)\n", 
               filename, getenv("TMPDIR") ? getenv("TMPDIR") : "$TMPDIR",
               "/var/tmp", P_tmpdir);
        
        fd = open(filename, O_CREAT|O_EXCL, S_IRWXU|S_IRUSR);
        if (fd != -1)
        {
            close(fd);
            unlink(filename);
            return 1;
        }
    }
    return 0;
}
Issue

This issue occurs when functions that can change resource permissions, such as chmod, umask, creat, or open, specify permissions that allow unintended actors to modify or read the resource.

Risk

If you give outside users or outside groups a wider range or permissions than required, you potentially expose your sensitive information and your modifications. This defect is especially dangerous for permissions related to:

  • Program configurations

  • Program executions

  • Sensitive user data

Fix

Set your permissions so that the user (u) has more permissions than the group (g), and so the group has more permissions than other users (o), or u >= g >= o.

Example — Create File with Other Permissions
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void bug_dangerouspermissions(const char * log_path) {
    mode_t mode = S_IROTH | S_IXOTH | S_IWOTH;
    int fd = creat(log_path, mode); //Noncompliant

    if (fd) {
        write(fd, "Hello\n", 6);
    }
    close(fd);
    unlink(log_path);
}

In this example, the log_path file is created with more rights for the other outside users, than the current user. The permissions are ---------rwx.

Correction — Modify User Permissions

One possible correction is to modify the user permissions for the file. In this correction, the user has read/write/execute permissions, but other users do not.

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void corrected_dangerouspermissions(const char * log_path) {
    mode_t mode = S_IRUSR | S_IXUSR | S_IWUSR;
    int fd = creat(log_path, mode);

    if (fd) {
        write(fd, "Hello\n", 6);
    }
    close(fd);
    unlink(log_path);
}

Check Information

Category: Others

Version History

Introduced in R2023a