semarie send this fix to tech@ some time ago[0] before any realpath
changes, I reported it independently later on[1] while missing his mail.
Here is semarie's diff adapted to -current. See both mails for more
details. It fixes unveiling files on read-only file systems; this case
is tested in regress and currently fails:
/dev/sd1d on /usr type ffs (local, nodev, read-only)
testing stat components to nonexistent "rw"
unveil_test: /usr/src/regress/sys/kern/unveil/syscalls.c:610 - unveil:
Read-only file system
[FAIL] unveil = 1, nonunveil = 0
604 static int
605 test_stat2(int do_uv)
606 {
607 if (do_uv) {
608 printf("testing stat components to nonexistent
\"rw\"\n");
609 if (unveil("/usr/share/man/nonexistent", "rw") ==
-1)
610 err(1, "%s:%d - unveil", __FILE__,
__LINE__);
611 }
With this diff, unveil regress passes completely; realpath regress
still passes completely as before, but that is due to the fact that the
currently tested paths do not include any file paths residing on
read-only file systems as is the case with unveil - doing so makes it
fail and pass before and after this diff respectively.
Original work was done by semarie, but I sat down and worked through the
code to actually give a confident OK. I also tweaked the comment
slightly trying to cover both scenarios now.
semarie?
Feedback?
0: https://marc.info/?t=154055857000005&r=1&w=2
1: https://marc.info/?l=openbsd-bugs&m=155999955818708&w=2
Index: kern/vfs_lookup.c
===================================================================
RCS file: /cvs/src/sys/kern/vfs_lookup.c,v
retrieving revision 1.78
diff -u -p -r1.78 vfs_lookup.c
--- kern/vfs_lookup.c 8 Jul 2019 09:21:10 -0000 1.78
+++ kern/vfs_lookup.c 14 Jul 2019 12:31:40 -0000
@@ -578,11 +578,11 @@ dirloop:
#endif
/*
* Allow for unveiling or realpath'ing a file in a
- * directory where we don't have access to create it
- * ourselves
+ * directory which we cannot create ourselves.
*/
if ((ndp->ni_pledge == PLEDGE_UNVEIL ||
- (cnp->cn_flags & REALPATH)) && error == EACCES)
+ (cnp->cn_flags & REALPATH)) &&
+ (error == EACCES || error == EROFS))
error = EJUSTRETURN;
if (error != EJUSTRETURN)