Skip to content

Commit f49a494

Browse files
committed
*: remove broken O_RESOLVE_BENEATH fallback for Linux
On Linux, openat(2) famously does not return an error if you pass it invalid flag bits. This was something I fixed in openat2(2) but for backward compatibility reasons, openat(2) will always silently ignore unknown O_* flags (which makes adding new ones quite painful). As a result, the fallback path added by commits e1c5f0e ("t_chmod_secure: probe kernel RESOLVE_BENEATH at runtime; drop test skip") and commit 7f60ec0 ("syscall: also use O_RESOLVE_BENEATH on FreeBSD and MacOS") would always return sucess and could cause spurious test failures so we can just remove it. O_RESOLVE_BENEATH will never get added to Linux for this reason, and anyone doing so out-of-tree is just creating a massive foot-gun so there is no need to entertain such broken kernels. Fixes: 7f60ec0 ("syscall: also use O_RESOLVE_BENEATH on FreeBSD and MacOS") Fixes: e1c5f0e ("t_chmod_secure: probe kernel RESOLVE_BENEATH at runtime; drop test skip") Signed-off-by: Aleksa Sarai <aleksa@amutable.com>
1 parent c0219ca commit f49a494

2 files changed

Lines changed: 15 additions & 19 deletions

File tree

syscall.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1815,9 +1815,7 @@ int secure_relative_open(const char *basedir, const char *relpath, int flags, mo
18151815
if (fd != -1 || errno != ENOSYS)
18161816
return fd;
18171817
}
1818-
#endif
1819-
1820-
#ifdef O_RESOLVE_BENEATH
1818+
#elif defined(O_RESOLVE_BENEATH)
18211819
return secure_relative_open_resolve_beneath(basedir, relpath, flags, mode);
18221820
#endif
18231821

t_chmod_secure.c

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,21 @@ static int errs = 0;
4545
static int kernel_resolve_beneath_supported(void)
4646
{
4747
int fd;
48-
#ifdef __linux__
49-
{
50-
struct open_how how;
51-
memset(&how, 0, sizeof how);
52-
how.flags = O_RDONLY | O_DIRECTORY;
53-
how.resolve = RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS;
54-
fd = syscall(SYS_openat2, AT_FDCWD, ".", &how, sizeof how);
55-
if (fd >= 0) {
56-
close(fd);
57-
return 1;
58-
}
59-
/* ENOSYS = kernel < 5.6. Fall through to the O_RESOLVE_BENEATH
60-
* probe in case we're a Linux build running on a kernel that
61-
* gained O_RESOLVE_BENEATH via some out-of-tree backport. */
48+
#if defined __linux__
49+
struct open_how how;
50+
memset(&how, 0, sizeof how);
51+
how.flags = O_RDONLY | O_DIRECTORY;
52+
how.resolve = RESOLVE_BENEATH | RESOLVE_NO_MAGICLINKS;
53+
fd = syscall(SYS_openat2, AT_FDCWD, ".", &how, sizeof how);
54+
if (fd >= 0) {
55+
close(fd);
56+
return 1;
6257
}
63-
#endif
64-
#ifdef O_RESOLVE_BENEATH
58+
/* O_RESOLVE_BENEATH is not defined on Linux, and even if it were, Linux's
59+
* openat(2) does not return -EINVAL for unknown flag bits and so if
60+
* O_RESOLVE_BENEATH happened to get defined somehow, the following
61+
* fallback would always return success. */
62+
#elif defined O_RESOLVE_BENEATH
6563
fd = openat(AT_FDCWD, ".", O_RDONLY | O_DIRECTORY | O_RESOLVE_BENEATH);
6664
if (fd >= 0) {
6765
close(fd);

0 commit comments

Comments
 (0)