<commit_before>---
layout: post
title: Opening files (and Linux drivers)
---

We should be careful (if not downright paranoid) when opening files. Some of
the recommended checks to perform and best practices include:

 * Using [realpath(3)](http://man7.org/linux/man-pages/man3/realpath.3.html) to product a canonicalized absolute path for us when the path comes from outside.
 * Setting O\_CLOEXEC to make sure that the file descriptor is not leaked to any child processes we spawn
 * Sanity-checking the file with [fstat(2)](http://man7.org/linux/man-pages/man2/stat.2.html) to make sure it looks like the kind of file we are expecting

When appropriate, we can also use the fstat(2) output to check for:

 * Expected file ownership (at least with the `st_uid` and `st_gid`), for example if we expect a specific user and/or group to own the file, regardless of our ability to access it.
 * An expected physical location (`st_dev` field), for example if we expect it to reside on a specific disk or device regardless of what the path says.
 * Expected permissions (`st_mode` field), for example we may want to refuse to open an executable file or a file with too lax of permissions no matter what

# The path

A program taking a path from the outside world, for example through a command
line argument, should sanitize the path (per CERT [FIOO2-C](https://securecoding.cert.org/confluence/display/c/FIO02-C.+Canonicalize+path+names+originating+from+tainted+sources).  Typically this looks like:

    int main(int argc, char **argv)
    {
        if (argc < 2) {
            printf("Usage: %s <path>\n", argv[0]);
            exit(EXIT_SUCCESS);
        }

        char *path = realpath(argv[1], NULL);
        if (!path) {
            fprintf(stderr, "Invalid argument: %m");

The resolved path will need to be freed.

# Example: Talking to a SPI (spidev) device<commit_msg>missing )<commit_after>---
layout: post
title: Opening files (and Linux drivers)
---

We should be careful (if not downright paranoid) when opening files. Some of
the recommended checks to perform and best practices include:

 * Using [realpath(3)](http://man7.org/linux/man-pages/man3/realpath.3.html) to product a canonicalized absolute path for us when the path comes from outside.
 * Setting O\_CLOEXEC to make sure that the file descriptor is not leaked to any child processes we spawn
 * Sanity-checking the file with [fstat(2)](http://man7.org/linux/man-pages/man2/stat.2.html) to make sure it looks like the kind of file we are expecting

When appropriate, we can also use the fstat(2) output to check for:

 * Expected file ownership (at least with the `st_uid` and `st_gid`), for example if we expect a specific user and/or group to own the file, regardless of our ability to access it.
 * An expected physical location (`st_dev` field), for example if we expect it to reside on a specific disk or device regardless of what the path says.
 * Expected permissions (`st_mode` field), for example we may want to refuse to open an executable file or a file with too lax of permissions no matter what

# The path

A program taking a path from the outside world, for example through a command
line argument, should sanitize the path (per CERT [FIOO2-C](https://securecoding.cert.org/confluence/display/c/FIO02-C.+Canonicalize+path+names+originating+from+tainted+sources)).  Typically this looks like:

    int main(int argc, char **argv)
    {
        if (argc < 2) {
            printf("Usage: %s <path>\n", argv[0]);
            exit(EXIT_SUCCESS);
        }

        char *path = realpath(argv[1], NULL);
        if (!path) {
            fprintf(stderr, "Invalid argument: %m");

The resolved path will need to be freed.

# Example: Talking to a SPI (spidev) device
{'fraction_non_alphanumeric': 0.08913797704830531, 'fraction_numerical': 0.008006405124099279, 'mean_word_length': 3.6733167082294265, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3381261', 'n_tokens_mistral': 1078, 'n_tokens_neox': 1041, 'n_words': 492}