Skip to content

Commit 00611d8

Browse files
peffgitster
authored andcommitted
add open_nofollow() helper
Some callers of open() would like to use O_NOFOLLOW, but it is not available on all platforms. Let's abstract this into a helper function so we can provide system-specific implementations. Some light web-searching reveals that we might be able to get something similar on Windows using FILE_FLAG_OPEN_REPARSE_POINT. I didn't dig into this further. For other systems without O_NOFOLLOW or any equivalent, we have two options for fallback: - we can just open anyway, following symlinks; this may have security implications (e.g., following untrusted in-tree symlinks) - we can determine whether the path is a symlink with lstat(). This is slower (two syscalls instead of one), but that may be acceptable for infrequent uses like looking up .gitattributes files (especially because we can get away with a single syscall for the common case of ENOENT). It's also racy, but should be sufficient for our needs (we are worried about in-tree symlinks that we ourselves would have previously created). We could make it non-racy at the cost of making it even slower, by doing an fstat() on the opened descriptor and comparing the dev/ino fields to the original lstat(). This patch implements the lstat() option in its slightly-faster racy form. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 328c109 commit 00611d8

File tree

2 files changed

+23
-0
lines changed

2 files changed

+23
-0
lines changed

git-compat-util.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,6 +1231,13 @@ int access_or_die(const char *path, int mode, unsigned flag);
12311231
/* Warn on an inaccessible file if errno indicates this is an error */
12321232
int warn_on_fopen_errors(const char *path);
12331233

1234+
/*
1235+
* Open with O_NOFOLLOW, or equivalent. Note that the fallback equivalent
1236+
* may be racy. Do not use this as protection against an attacker who can
1237+
* simultaneously create paths.
1238+
*/
1239+
int open_nofollow(const char *path, int flags);
1240+
12341241
#if !defined(USE_PARENS_AROUND_GETTEXT_N) && defined(__GNUC__)
12351242
#define USE_PARENS_AROUND_GETTEXT_N 1
12361243
#endif

wrapper.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,3 +678,19 @@ int is_empty_or_missing_file(const char *filename)
678678

679679
return !st.st_size;
680680
}
681+
682+
int open_nofollow(const char *path, int flags)
683+
{
684+
#ifdef O_NOFOLLOW
685+
return open(path, flags | O_NOFOLLOW);
686+
#else
687+
struct stat st;
688+
if (lstat(path, &st) < 0)
689+
return -1;
690+
if (S_ISLNK(st.st_mode)) {
691+
errno = ELOOP;
692+
return -1;
693+
}
694+
return open(path, flags);
695+
#endif
696+
}

0 commit comments

Comments
 (0)