Skip to content

root: make readlink return -EINVAL for non-symlinks#378

Merged
cyphar merged 3 commits into
mainfrom
readlink-einval
May 24, 2026
Merged

root: make readlink return -EINVAL for non-symlinks#378
cyphar merged 3 commits into
mainfrom
readlink-einval

Conversation

@cyphar
Copy link
Copy Markdown
Owner

@cyphar cyphar commented May 24, 2026

readlink() will return -EINVAL for non-symlinks, but the race-free
readlinkat(fd, "") approach returns -ENOENT if fd is not a symlink. This
mismatch can very easily cause confusion (in fact, I found this bug
while trying to use Root::readlink elsewhere).

As -ENOENT cannot be returned from readlinkat(fd, "") for any other
reason, map it to -EINVAL to match the API to what users would expect.
It's a bit strange the kernel does this, but oh well...

Fixes: e5d212d ("root: add readlink method")
Signed-off-by: Aleksa Sarai aleksa@amutable.com

@cyphar cyphar added this to the 0.2.5 milestone May 24, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 24, 2026

Codecov Report

❌ Patch coverage is 87.50000% with 1 line in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/root.rs 75.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@cyphar cyphar force-pushed the readlink-einval branch 3 times, most recently from f013ce3 to 1228e80 Compare May 24, 2026 11:58
cyphar added 3 commits May 25, 2026 01:16
In commit 1391acd ("tests: capi: test ptr==NULL and bufsize<=0
cases") we switched to making the starting point of the trucated tests
dynamic, which led me to missing the actual_size==1 case (where the
capacity and actual_size are 0 after halving actual_size, resulting in
zero-length strings instead of one-character strings for the tests).

There were also a few other bugs here (such as our Vec::set_len usage)
and the whole "test multiple buffer sizes" logic was incredibly implicit
and hairy. The solution is just to make all of this more explicit.

Fixes: 1391acd ("tests: capi: test ptr==NULL and bufsize<=0 cases")
Signed-off-by: Aleksa Sarai <aleksa@amutable.com>
Previously these were only tested within the Root::create tests, which
only tested that most basic usecase worked. We should really test error
cases and cases where readlink should succeed where resolving should
fail (i.e., dangling and looped symlinks).

Signed-off-by: Aleksa Sarai <aleksa@amutable.com>
readlink() will return -EINVAL for non-symlinks, but the race-free
readlinkat(fd, "") approach returns -ENOENT if fd is not a symlink. This
mismatch can very easily cause confusion (in fact, I found this bug
while trying to use Root::readlink elsewhere).

As -ENOENT cannot be returned from readlinkat(fd, "") for any other
reason, map it to -EINVAL to match the API to what users would expect.
It's a bit strange the kernel does this, but oh well...

Fixes: e5d212d ("root: add readlink method")
Signed-off-by: Aleksa Sarai <aleksa@amutable.com>
@cyphar cyphar force-pushed the readlink-einval branch from 1228e80 to 08856cc Compare May 24, 2026 15:39
@cyphar cyphar merged commit 60be111 into main May 24, 2026
119 checks passed
@cyphar cyphar deleted the readlink-einval branch May 24, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant