Page MenuHomeFreeBSD

D2808.id6181.diff
No OneTemporary

D2808.id6181.diff

Index: sys/kern/vfs_lookup.c
===================================================================
--- sys/kern/vfs_lookup.c
+++ sys/kern/vfs_lookup.c
@@ -182,7 +182,7 @@
*/
if (error == 0 && IN_CAPABILITY_MODE(td) &&
(cnp->cn_flags & NOCAPCHECK) == 0) {
- ndp->ni_strictrelative = 1;
+ ndrequire_strict_relative_lookups(ndp, ENOTCAPABLE);
if (ndp->ni_dirfd == AT_FDCWD) {
#ifdef KTRACE
if (KTRPOINT(td, KTR_CAPFAIL))
@@ -248,7 +248,7 @@
&rights) ||
ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL ||
ndp->ni_filecaps.fc_nioctls != -1) {
- ndp->ni_strictrelative = 1;
+ ndrequire_strict_relative_lookups(ndp, ENOTCAPABLE);
}
#endif
}
@@ -287,7 +287,7 @@
ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
#endif
namei_cleanup_cnp(cnp);
- return (ENOTCAPABLE);
+ return (ndp->ni_strictrelative);
}
while (*(cnp->cn_nameptr) == '/') {
cnp->cn_nameptr++;
@@ -627,7 +627,7 @@
if (KTRPOINT(curthread, KTR_CAPFAIL))
ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
#endif
- error = ENOTCAPABLE;
+ error = ndp->ni_strictrelative;
goto bad;
}
if ((cnp->cn_flags & ISLASTCN) != 0 &&
@@ -1123,6 +1123,38 @@
}
}
+void
+ndrequire_strict_relative_lookups(struct nameidata *ndp, int errnum)
+{
+ /*
+ * Monotonic ordering of possible field values:
+ *
+ * EPERM - user-level code has requested an O_BENEATH lookup
+ * ENOTCAPABLE - Capsicum demands strict relative lookups
+ * 0 - allow relative lookups
+ *
+ * We can always move up this list but never down.
+ */
+
+ KASSERT((errnum == EPERM) || (errnum == ENOTCAPABLE),
+ ("invalid errno (not EPERM or ENOTCAPABLE)"));
+
+ switch (errnum) {
+ case EPERM:
+ ndp->ni_strictrelative = errnum;
+ break;
+
+ case ENOTCAPABLE:
+ if (ndp->ni_strictrelative != EPERM) {
+ ndp->ni_strictrelative = errnum;
+ }
+ break;
+
+ default:
+ KASSERT(false, ("invalid errno for strict relative lookups"));
+ }
+}
+
/*
* Determine if there is a suitable alternate filename under the specified
* prefix for the specified path. If the create flag is set, then the
Index: sys/kern/vfs_syscalls.c
===================================================================
--- sys/kern/vfs_syscalls.c
+++ sys/kern/vfs_syscalls.c
@@ -1049,7 +1049,7 @@
struct vnode *vp;
struct nameidata nd;
cap_rights_t rights;
- int cmode, error, indx;
+ int beneath, cmode, error, indx;
indx = -1;
@@ -1058,6 +1058,7 @@
/* XXX: audit dirfd */
cap_rights_init(&rights, CAP_LOOKUP);
flags_to_rights(flags, &rights);
+ beneath = ((flags & O_BENEATH) == O_BENEATH);
/*
* Only one of the O_EXEC, O_RDONLY, O_WRONLY and O_RDWR flags
* may be specified.
@@ -1086,6 +1087,9 @@
cmode = ((mode & ~fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd,
&rights, td);
+ if (beneath) {
+ ndrequire_strict_relative_lookups(&nd, EPERM);
+ }
td->td_dupfd = -1; /* XXX check for fdopen */
error = vn_open(&nd, &flags, cmode, fp);
if (error != 0) {
@@ -1100,7 +1104,7 @@
/*
* Handle special fdopen() case. bleh.
*
- * Don't do this for relative (capability) lookups; we don't
+ * Don't do this for capability or O_BENEATH lookups: we don't
* understand exactly what would happen, and we don't think
* that it ever should.
*/
@@ -1150,8 +1154,11 @@
struct filecaps *fcaps;
#ifdef CAPABILITIES
- if (nd.ni_strictrelative == 1)
+ if (nd.ni_strictrelative != 0 &&
+ cap_rights_is_valid(&nd.ni_filecaps.fc_rights))
+ {
fcaps = &nd.ni_filecaps;
+ }
else
#endif
fcaps = NULL;
Index: sys/sys/fcntl.h
===================================================================
--- sys/sys/fcntl.h
+++ sys/sys/fcntl.h
@@ -131,6 +131,7 @@
#if __BSD_VISIBLE
#define O_VERIFY 0x00200000 /* open only after verification */
+#define O_BENEATH 0x00400000 /* stay beneath a specified directory */
#endif
/*
Index: sys/sys/namei.h
===================================================================
--- sys/sys/namei.h
+++ sys/sys/namei.h
@@ -150,7 +150,8 @@
#define AUDITVNODE2 0x08000000 /* audit the looked up vnode information */
#define TRAILINGSLASH 0x10000000 /* path ended in a slash */
#define NOCAPCHECK 0x20000000 /* do not perform capability checks */
-#define PARAMASK 0x3ffffe00 /* mask of parameter descriptors */
+#define BENEATH 0x40000000 /* strict downwards-only lookup */
+#define PARAMASK 0x7ffffe00 /* mask of parameter descriptors */
/*
* Initialization of a nameidata structure.
@@ -168,6 +169,12 @@
enum uio_seg segflg, const char *namep, int dirfd, struct vnode *startdir,
cap_rights_t *rightsp, struct thread *td);
+/*
+ * Set the ni_strictrelative field of a struct nameidata according to a
+ * monotonically-increasing policy.
+ */
+void ndrequire_strict_relative_lookups(struct nameidata*, int errnum);
+
#define NDF_NO_DVP_RELE 0x00000001
#define NDF_NO_DVP_UNLOCK 0x00000002
#define NDF_NO_DVP_PUT 0x00000003

File Metadata

Mime Type
text/plain
Expires
Mon, Oct 13, 3:30 PM (16 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23681601
Default Alt Text
D2808.id6181.diff (4 KB)

Event Timeline