1

In my application, I am trying to check if a path is inside of a specific directory. E.g., I want the files in the path /x/y/z not to be accessible by parts of my application. I cannot use traditional file permissions, as other parts of the application should be able to access these files.

Several Internet resources suggest the use of realpath to first canonicalize paths, i.e., resolving all symlinks and instances of .. (e.g. 1, 2). However, it seems not to be possible to perform path resolution followed by an open without an race condition (TOCTOU).

char *resolved = realpath("/my/potentially/dangerous/path.txt", NULL);
// someone changes any part of the path to a symlink to something else   <--- race condition
if (check_path(resolved)) {
    //                                                                   <--- race condition
    int fd = open(resolved, O_RDONLY);
}

Am I overlooking something or does POSIX (and Linux) not provide any way to do something like this without a race condition?

user2737037
  • 1,119
  • 1
  • 16
  • 29
  • 2
    Should these isolated parts of your application really be able to access anything _except_ everything under a certain directory? Can you not split your application into two processes, chroot one of them to e.g. a temporary directory and then mount everything it should be able to access under that directory? – Peter Nov 24 '20 at 12:24
  • What are you trying to protect against? This seems like a [classic XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). You have some unknown problem that you've already decided how it needs to be solved, and you're asking about the solution instead of your actual problem. – Andrew Henle Nov 24 '20 at 12:31
  • It's a kind of in-process isolation (similar to https://vahldiek.github.io/project/erim/), where some parts of the application are trusted, others not. So the premise is to only have one process. – user2737037 Nov 24 '20 at 12:42

1 Answers1

1

What about 'openat2' (Linux only)?

And once you have a file descriptor, see man open

Description:

A file descriptor is a reference to an open file description; this reference is unaffected if pathname is subsequently removed or modified to refer to a different file.

Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11
  • `openat2()` is not POSIX. – Andrew Henle Nov 24 '20 at 12:27
  • @Andrew Henle True, but it wasn't specifically asked for Posix. – Erdal Küçük Nov 24 '20 at 12:31
  • The POSIX tag has been on the question from the moment it was posted. – Andrew Henle Nov 24 '20 at 12:31
  • You mean resolving it and then opening it with RESOLVE_NO_SYMLINKS? And trying it again if it fails? I'm actually fine for it not being POSIX, however, it was introduced just in Linux 5.6. Is there no solution for pure POSIX or older Linux? – user2737037 Nov 24 '20 at 12:35
  • @user2737037 Are the resolve flags not enough? Ok, realpath gives you an absolute pathname, but you still have to check the permissions to that file. Can't you describe with the resolve flags what you are trying to achive? Basically one step instead of two. – Erdal Küçük Nov 24 '20 at 12:53
  • @Andrew Henle I cannot disagree with you, but the user asked for 'and Linux' too. I added the 'Linux only' hint. – Erdal Küçük Nov 24 '20 at 12:59