/var/log/andrey     About     Archive     Feed

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:

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

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). 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

We can now try to open the file given the resolved path, however we should sanity-check that the file looks like something that we expect to open. For example, a SPI device interfaced via the Linux spidev driver should at least:

We specifically want to use fstat(2) rather than stat(2) because we want to be sure that we are checking the file we opened rather than checking a path twice (and allowing whatever the path resolves to to change out from under us).

First, we open the file:

int fd = open(path, O_CLOEXEC);
if (fd == -1) {
    fprintf(stderr, "Unable to open \"%s\"\n", path);
    goto out_fd;
}

Then we perform some basic sanity checks. The st_mode field tells us what kind of file we have and there are convenient macros to simplify our checks: ST_IS_CHR checks that this is a character device, which is what we expect. In order cases we may want a regular file (S_ISREG matches that).

For character devices and other special files we also have the st_rdev field on which we can use macros major and minor to check for specific IDs.

struct stat st;
if (fstat(fd, &st) || !S_IS_CHR(st.st_mode) || major(st.st_rdev) != 153) {
    fprintf(stderr, "\"%s\" does not look like a SPI device\n", path);
    goto out_st;
}

We have now opened the file and reasonably believe that it is a SPI device. Our cleanup would be in reverse order:

out_st:
    close(fd);
out_fd:
    free(path);

or the GCC cleanup attribute can be used to clean up resources.

comments powered by Disqus