|
|
Log in / Subscribe / Register

New AT_ flags for restricting pathname lookup

New AT_ flags for restricting pathname lookup

Posted Oct 5, 2018 4:13 UTC (Fri) by eru (subscriber, #2753)
Parent article: New AT_ flags for restricting pathname lookup

openat() is one of those Linux system calls whose rationale I don't quite understand. It allows opening files relative to a particular directory, but can't you do the same thing by manipulating the path name, or by using chdir() first?


to post comments

New AT_ flags for restricting pathname lookup

Posted Oct 5, 2018 4:33 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

You can't, not in a race-free way anyway.

New AT_ flags for restricting pathname lookup

Posted Oct 5, 2018 10:47 UTC (Fri) by pbonzini (subscriber, #60935) [Link]

For one, chdir affects the entire process rather than the current thread only.

New AT_ flags for restricting pathname lookup

Posted Oct 5, 2018 12:08 UTC (Fri) by nix (subscriber, #2304) [Link]

Others have commented on the problems with chdir(). The problem with using long absolute pathnames is twofold: firstly, you race with people modifying symlinks and/or renaming out from underneath you (*at() can at least reduce this by nailing the walk to specific directory inodes). Secondly, the length of pathnames is capped at pathconf(..., _SC_PATH_MAX): but you can make directory trees of arbitrary depth, with absolute paths much deeper than this and indeed deeper than the hardware page size. Nobody does this manually, but it can and does happen with machine-generated hierarchies, and the deep parts of such hierarchies are *only* traversable via chdir() or the *at() syscalls: while you can compose an absolute path that should reach those parts, the kernel will reject it with -ENAMETOOLONG.

So generic code has no choice but to use chdir() or *at() to traverse hierarchies or fail on such deep hierarchies, and generic multithreaded code or library code which might be run in multithreaded contexts has no choice but to use *at().

New AT_ flags for restricting pathname lookup

Posted Oct 7, 2018 17:22 UTC (Sun) by rweikusat2 (subscriber, #117920) [Link] (1 responses)

Manipulating pathnames means "doing string operations", something that's fairly cumbersome in C. For an example, consider the following toy-program:
#define _GNU_SOURCE

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>

static char *cwd[] = {
    ".",
    NULL
};

int main(int argc, char **argv)
{
    DIR *dir;
    struct dirent *d_ent;
    struct stat st;
    int dirfd, rc;
    
    ++argv;
    if (!*argv) argv = cwd;
    do {
        dirfd = open(*argv, O_RDONLY, 0);
        if (dirfd == -1) {
            perror("open");
            continue;
        }
        
        dir = fdopendir(dirfd);
        if (!dir) {
            perror("fdopendir");
            continue;
        }

        printf("-----\nfiles in %s\n-----\n", *argv);
        while ((d_ent = readdir(dir))) {
            rc = fstatat(dirfd, d_ent->d_name, &, 0);
            if (rc == -1) {
                if (errno != ENOENT) perror("fstatat");
                continue;
            }

            if (S_ISREG(st.st_mode))
                printf("%s\t\t%zu bytes\n", d_ent->d_name, (size_t)st.st_size);
        }

        closedir(dir);
    } while (*++argv);

    return 0;
}
This takes a list of directory pathnames as arguments and prints the names and sizes of all files in any of the directories. It uses fstatat because the names returned by readdir are filenames relative to the directory being read. Thanks to the *at-call, they can be accessed without doing dynamic string manipulation and buffer management and also without changing the cwd of the process forward and backward for each directory.

Also, chdir is basically unusable in multi-threaded processes as it changes the working directory of the process, ie, it affects all threads, not just the one executing it and, as seen by another thread, the cwd change is an unpredictable, asynchronously occuring event. Eg, a thread desiring to create two files in the same directory might end up creating them in different directories.

Lastly, the directory a process was started in might have been picked intentionally, eg, as location where core dumps should go to, and the process shouldn't change it except if there's a very good reason for that (and this should be documented).

New AT_ flags for restricting pathname lookup

Posted Oct 7, 2018 19:27 UTC (Sun) by rweikusat2 (subscriber, #117920) [Link]

rc = fstatat(dirfd, d_ent->d_name, &, 0);

This should have been

rc = fstatat(dirfd, d_ent->d_name, &st, 0);

and was but got deleted when "htmlifying" the source ... :-(

New AT_ flags for restricting pathname lookup

Posted Oct 8, 2018 4:18 UTC (Mon) by eru (subscriber, #2753) [Link]

Thanks to all for explaining the need and use of the somethingat() calls.


Copyright © 2026, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds