Semmle 1.21
Skip to end of metadata
Go to start of metadata

Name: File created without restricting permissions

Description: Creating a file that is world-writable can allow an attacker to write to the file.

ID: cpp/world-writable-file-creation

Kind: problem

Severity: warning

Precision: medium

Query: DoNotCreateWorldWritable.ql
/**
 * @name File created without restricting permissions
 * @description Creating a file that is world-writable can allow an attacker to write to the file.
 * @kind problem
 * @problem.severity warning
 * @precision medium
 * @id cpp/world-writable-file-creation
 * @tags security
 *       external/cwe/cwe-732
 */

import cpp
import FilePermissions
import semmle.code.cpp.commons.unix.Constants

predicate worldWritableCreation(FileCreationExpr fc, int mode) {
  mode = localUmask(fc).mask(fc.getMode())
  and
  sets(mode, s_iwoth())
}

predicate setWorldWritable(FunctionCall fc, int mode) {
  exists(string name | fc.getTarget().getName() = name |
    name = "chmod" or
    name = "fchmod" or
    name = "_chmod" or
    name = "_wchmod"
  )
  and
  mode = fc.getArgument(1).getValue().toInt()
  and
  sets(mode, s_iwoth())
}

from Expr fc, int mode, string message
where
  worldWritableCreation(fc, mode) and message = "A file may be created here with mode "+octalFileMode(mode)+", which would make it world-writable."
  or
  setWorldWritable(fc, mode) and message = "This sets a file's permissions to "+octalFileMode(mode)+", which would make it world-writable."
select fc, message

When you create a file, take care to give it the most restrictive permissions possible. A typical mistake is to create the file with world-writable permissions. This can allow an attacker to write to the file, which can give them unexpected control over the program.

Recommendation

Files should usually be created with write permissions only for the current user. If broader permissions are needed, including the users' group should be sufficient. It is very rare that a file needs to be world-writable, and care should be taken not to make assumptions about the contents of any such file.

On Unix systems, it is possible for the user who runs the program to restrict file creation permissions using umask. However, a program should not assume that the user will set an umask, and should still set restrictive permissions by default.

Example

This example shows two ways of writing a default configuration file. Software often does this to provide the user with a convenient starting point for defining their own configuration. However, configuration files can also control important aspects of the software's behavior, so it is important that they cannot be controlled by an attacker.

The first example creates the default configuration file with the usual "default" Unix permissions, 0666. This makes the file world-writable, so that an attacker could write in their own configuration that would be read by the program. The second example uses more restrictive permissions: a combination of the standard Unix constants S_IWUSR and S_IRUSR which means that only the current user will have read and write access to the file.

int write_default_config_bad() {
	// BAD - this is world-writable so any user can overwrite the config
	FILE* out = creat(OUTFILE, 0666);
	fprintf(out, DEFAULT_CONFIG);
}

int write_default_config_good() {
	// GOOD - this allows only the current user to modify the file
	FILE* out = creat(OUTFILE, S_IWUSR | S_IRUSR);
	fprintf(out, DEFAULT_CONFIG);
}

References