Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F154542195
D25886.id76952.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D25886.id76952.diff
View Options
Index: sys/kern/vfs_lookup.c
===================================================================
--- sys/kern/vfs_lookup.c
+++ sys/kern/vfs_lookup.c
@@ -178,11 +178,13 @@
nameicap_tracker_add(struct nameidata *ndp, struct vnode *dp)
{
struct nameicap_tracker *nt;
+ struct componentname *cnp;
if ((ndp->ni_lcf & NI_LCF_CAP_DOTDOT) == 0 || dp->v_type != VDIR)
return;
- if ((ndp->ni_lcf & (NI_LCF_BENEATH_ABS | NI_LCF_BENEATH_LATCHED)) ==
- NI_LCF_BENEATH_ABS) {
+ cnp = &ndp->ni_cnd;
+ if ((cnp->cn_flags & BENEATH) != 0 &&
+ (ndp->ni_lcf & NI_LCF_BENEATH_LATCHED) == 0) {
MPASS((ndp->ni_lcf & NI_LCF_LATCH) != 0);
if (dp != ndp->ni_beneath_latch)
return;
@@ -215,9 +217,12 @@
/*
* For dotdot lookups in capability mode, only allow the component
* lookup to succeed if the resulting directory was already traversed
- * during the operation. Also fail dotdot lookups for non-local
- * filesystems, where external agents might assist local lookups to
- * escape the compartment.
+ * during the operation. This catches situations where already
+ * traversed directory is moved to different parent, and then we walks
+ * over it with dotdots.
+ *
+ * Also fail dotdot lookups for non-local filesystems, where external
+ * agents might assist local lookups to escape the compartment.
*/
static int
nameicap_check_dotdot(struct nameidata *ndp, struct vnode *dp)
@@ -234,14 +239,15 @@
return (ENOTCAPABLE);
TAILQ_FOREACH_REVERSE(nt, &ndp->ni_cap_tracker, nameicap_tracker_head,
nm_link) {
+ if ((ndp->ni_lcf & NI_LCF_LATCH) != 0 &&
+ ndp->ni_beneath_latch == nt->dp) {
+ ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED;
+ nameicap_cleanup(ndp, false);
+ return (0);
+ }
if (dp == nt->dp)
return (0);
}
- if ((ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) {
- ndp->ni_lcf &= ~NI_LCF_BENEATH_LATCHED;
- nameicap_cleanup(ndp, false);
- return (0);
- }
return (ENOTCAPABLE);
}
@@ -318,6 +324,7 @@
*/
if (IN_CAPABILITY_MODE(td) && (cnp->cn_flags & NOCAPCHECK) == 0) {
ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
+ ndp->ni_resflags |= NIRES_STRICTREL;
if (ndp->ni_dirfd == AT_FDCWD) {
#ifdef KTRACE
if (KTRPOINT(td, KTR_CAPFAIL))
@@ -396,6 +403,7 @@
ndp->ni_filecaps.fc_fcntls != CAP_FCNTL_ALL ||
ndp->ni_filecaps.fc_nioctls != -1) {
ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
+ ndp->ni_resflags |= NIRES_STRICTREL;
}
#endif
}
@@ -419,6 +427,16 @@
if (error == 0)
ndp->ni_lcf |= NI_LCF_LATCH;
}
+ if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) {
+ if (cnp->cn_pnbuf[0] == '/' ||
+ (ndp->ni_lcf & NI_LCF_BENEATH_ABS) != 0) {
+ error = EINVAL;
+ } else if ((ndp->ni_lcf & NI_LCF_STRICTRELATIVE) == 0) {
+ ndp->ni_lcf |= NI_LCF_STRICTRELATIVE |
+ NI_LCF_CAP_DOTDOT;
+ }
+ }
+
/*
* If we are auditing the kernel pathname, save the user pathname.
*/
@@ -586,8 +604,8 @@
namei_cleanup_cnp(cnp);
} else
cnp->cn_flags |= HASBUF;
- if ((ndp->ni_lcf & (NI_LCF_BENEATH_ABS |
- NI_LCF_BENEATH_LATCHED)) == NI_LCF_BENEATH_ABS) {
+ if ((ndp->ni_lcf & (NI_LCF_LATCH |
+ NI_LCF_BENEATH_LATCHED)) == NI_LCF_LATCH) {
NDFREE(ndp, 0);
error = ENOTCAPABLE;
}
Index: sys/kern/vfs_syscalls.c
===================================================================
--- sys/kern/vfs_syscalls.c
+++ sys/kern/vfs_syscalls.c
@@ -112,6 +112,26 @@
static int kern_linkat_vp(struct thread *td, struct vnode *vp, int fd,
const char *path, enum uio_seg segflag);
+static uint64_t
+at2cnpflags(u_int at_flags, u_int mask)
+{
+ u_int64_t res;
+
+ res = 0;
+ at_flags &= mask;
+ if ((at_flags & AT_BENEATH) != 0)
+ res |= BENEATH;
+ if ((at_flags & AT_RESOLVE_BENEATH) != 0)
+ res |= RBENEATH;
+ /* FOLLOW is pseudo flag */
+ if ((at_flags & AT_SYMLINK_NOFOLLOW) != 0)
+ res |= NOFOLLOW;
+ if ((mask & AT_SYMLINK_FOLLOW) != 0 &&
+ (at_flags & AT_SYMLINK_FOLLOW) == 0)
+ res |= NOFOLLOW;
+ return (res);
+}
+
int
kern_sync(struct thread *td)
{
@@ -1136,7 +1156,7 @@
* understand exactly what would happen, and we don't think
* that it ever should.
*/
- if ((nd.ni_lcf & NI_LCF_STRICTRELATIVE) == 0 &&
+ if ((nd.ni_resflags & NIRES_STRICTREL) == 0 &&
(error == ENODEV || error == ENXIO) &&
td->td_dupfd >= 0) {
error = dupfdopen(td, fdp, td->td_dupfd, flags, error,
@@ -1183,7 +1203,7 @@
struct filecaps *fcaps;
#ifdef CAPABILITIES
- if ((nd.ni_lcf & NI_LCF_STRICTRELATIVE) != 0)
+ if ((nd.ni_resflags & NIRES_STRICTREL) != 0)
fcaps = &nd.ni_filecaps;
else
#endif
@@ -1484,12 +1504,13 @@
int flag;
flag = uap->flag;
- if ((flag & ~(AT_SYMLINK_FOLLOW | AT_BENEATH)) != 0)
+ if ((flag & ~(AT_SYMLINK_FOLLOW | AT_BENEATH |
+ AT_RESOLVE_BENEATH)) != 0)
return (EINVAL);
return (kern_linkat(td, uap->fd1, uap->fd2, uap->path1, uap->path2,
- UIO_USERSPACE, ((flag & AT_SYMLINK_FOLLOW) != 0 ? FOLLOW :
- NOFOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0)));
+ UIO_USERSPACE, at2cnpflags(flag, AT_SYMLINK_FOLLOW | AT_BENEATH |
+ AT_RESOLVE_BENEATH)));
}
int hardlink_check_uid = 0;
@@ -1854,7 +1875,7 @@
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 |
- ((flag & AT_BENEATH) != 0 ? BENEATH : 0),
+ at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH),
pathseg, path, dfd, &cap_unlinkat_rights, td);
if ((error = namei(&nd)) != 0) {
if (error == EINVAL)
@@ -2057,7 +2078,7 @@
struct nameidata nd;
int error;
- if ((flag & ~(AT_EACCESS | AT_BENEATH)) != 0)
+ if ((flag & ~(AT_EACCESS | AT_BENEATH | AT_RESOLVE_BENEATH)) != 0)
return (EINVAL);
if (amode != F_OK && (amode & ~(R_OK | W_OK | X_OK)) != 0)
return (EINVAL);
@@ -2078,7 +2099,7 @@
usecred = cred;
AUDIT_ARG_VALUE(amode);
NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF |
- AUDITVNODE1 | ((flag & AT_BENEATH) != 0 ? BENEATH : 0),
+ AUDITVNODE1 | at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH),
pathseg, path, fd, &cap_fstat_rights, td);
if ((error = namei(&nd)) != 0)
goto out;
@@ -2369,13 +2390,13 @@
struct nameidata nd;
int error;
- if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
+ if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH |
+ AT_RESOLVE_BENEATH)) != 0)
return (EINVAL);
- NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) != 0 ?
- NOFOLLOW : FOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0) |
- LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd,
- &cap_fstat_rights, td);
+ NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_BENEATH |
+ AT_RESOLVE_BENEATH | AT_SYMLINK_NOFOLLOW) | LOCKSHARED | LOCKLEAF |
+ AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2693,7 +2714,8 @@
sys_chflagsat(struct thread *td, struct chflagsat_args *uap)
{
- if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
+ if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH |
+ AT_RESOLVE_BENEATH)) != 0)
return (EINVAL);
return (kern_chflagsat(td, uap->fd, uap->path, UIO_USERSPACE,
@@ -2722,12 +2744,11 @@
enum uio_seg pathseg, u_long flags, int atflag)
{
struct nameidata nd;
- int error, follow;
+ int error;
AUDIT_ARG_FFLAGS(flags);
- follow = (atflag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
- follow |= (atflag & AT_BENEATH) != 0 ? BENEATH : 0;
- NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
+ NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(atflag, AT_SYMLINK_NOFOLLOW |
+ AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd,
&cap_fchflags_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2822,7 +2843,8 @@
sys_fchmodat(struct thread *td, struct fchmodat_args *uap)
{
- if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
+ if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH |
+ AT_RESOLVE_BENEATH)) != 0)
return (EINVAL);
return (kern_fchmodat(td, uap->fd, uap->path, UIO_USERSPACE,
@@ -2851,12 +2873,11 @@
enum uio_seg pathseg, mode_t mode, int flag)
{
struct nameidata nd;
- int error, follow;
+ int error;
AUDIT_ARG_MODE(mode);
- follow = (flag & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW : FOLLOW;
- follow |= (flag & AT_BENEATH) != 0 ? BENEATH : 0;
- NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
+ NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW |
+ AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd,
&cap_fchmod_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2951,7 +2972,8 @@
sys_fchownat(struct thread *td, struct fchownat_args *uap)
{
- if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
+ if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH |
+ AT_RESOLVE_BENEATH)) != 0)
return (EINVAL);
return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid,
@@ -2963,12 +2985,11 @@
enum uio_seg pathseg, int uid, int gid, int flag)
{
struct nameidata nd;
- int error, follow;
+ int error;
AUDIT_ARG_OWNER(uid, gid);
- follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
- follow |= (flag & AT_BENEATH) != 0 ? BENEATH : 0;
- NDINIT_ATRIGHTS(&nd, LOOKUP, follow | AUDITVNODE1, pathseg, path, fd,
+ NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW |
+ AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd,
&cap_fchown_rights, td);
if ((error = namei(&nd)) != 0)
@@ -3320,13 +3341,14 @@
struct timespec ts[2];
int error, flags;
- if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
+ if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH |
+ AT_RESOLVE_BENEATH)) != 0)
return (EINVAL);
if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0)
return (error);
- NDINIT_ATRIGHTS(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW :
- FOLLOW) | ((flag & AT_BENEATH) != 0 ? BENEATH : 0) | AUDITVNODE1,
+ NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW |
+ AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1,
pathseg, path, fd, &cap_futimes_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -3821,7 +3843,7 @@
restart:
bwillwrite();
NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 |
- ((flag & AT_BENEATH) != 0 ? BENEATH : 0),
+ at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH),
pathseg, path, dfd, &cap_unlinkat_rights, td);
if ((error = namei(&nd)) != 0)
goto fdout;
@@ -4307,7 +4329,8 @@
sys_getfhat(struct thread *td, struct getfhat_args *uap)
{
- if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH)) != 0)
+ if ((uap->flags & ~(AT_SYMLINK_NOFOLLOW | AT_BENEATH |
+ AT_RESOLVE_BENEATH)) != 0)
return (EINVAL);
return (kern_getfhat(td, uap->flags, uap->fd, uap->path, UIO_USERSPACE,
uap->fhp));
@@ -4325,9 +4348,9 @@
error = priv_check(td, PRIV_VFS_GETFH);
if (error != 0)
return (error);
- NDINIT_AT(&nd, LOOKUP, ((flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW :
- FOLLOW) | ((flags & AT_BENEATH) != 0 ? BENEATH : 0) | LOCKLEAF |
- AUDITVNODE1, pathseg, path, fd, td);
+ NDINIT_AT(&nd, LOOKUP, at2cnpflags(flags, AT_SYMLINK_NOFOLLOW |
+ AT_BENEATH | AT_RESOLVE_BENEATH) | LOCKLEAF | AUDITVNODE1,
+ pathseg, path, fd, td);
error = namei(&nd);
if (error != 0)
return (error);
Index: sys/kern/vfs_vnops.c
===================================================================
--- sys/kern/vfs_vnops.c
+++ sys/kern/vfs_vnops.c
@@ -227,6 +227,8 @@
ndp->ni_cnd.cn_flags |= FOLLOW;
if ((fmode & O_BENEATH) != 0)
ndp->ni_cnd.cn_flags |= BENEATH;
+ if ((fmode & O_RESOLVE_BENEATH) != 0)
+ ndp->ni_cnd.cn_flags |= RBENEATH;
if (!(vn_open_flags & VN_OPEN_NOAUDIT))
ndp->ni_cnd.cn_flags |= AUDITVNODE1;
if (vn_open_flags & VN_OPEN_NOCAPCHECK)
@@ -291,6 +293,8 @@
ndp->ni_cnd.cn_flags |= LOCKSHARED;
if ((fmode & O_BENEATH) != 0)
ndp->ni_cnd.cn_flags |= BENEATH;
+ if ((fmode & O_RESOLVE_BENEATH) != 0)
+ ndp->ni_cnd.cn_flags |= RBENEATH;
if (!(vn_open_flags & VN_OPEN_NOAUDIT))
ndp->ni_cnd.cn_flags |= AUDITVNODE1;
if (vn_open_flags & VN_OPEN_NOCAPCHECK)
Index: sys/sys/fcntl.h
===================================================================
--- sys/sys/fcntl.h
+++ sys/sys/fcntl.h
@@ -136,6 +136,7 @@
#if __BSD_VISIBLE
#define O_VERIFY 0x00200000 /* open only after verification */
#define O_BENEATH 0x00400000 /* Fail if not under cwd */
+#define O_RESOLVE_BENEATH 0x00800000 /* XXX */
#endif
/*
@@ -215,6 +216,7 @@
#define AT_SYMLINK_FOLLOW 0x0400 /* Follow symbolic link */
#define AT_REMOVEDIR 0x0800 /* Remove directory instead of file */
#define AT_BENEATH 0x1000 /* Fail if not under dirfd */
+#define AT_RESOLVE_BENEATH 0x2000 /* XXX */
#endif
/*
Index: sys/sys/namei.h
===================================================================
--- sys/sys/namei.h
+++ sys/sys/namei.h
@@ -133,7 +133,8 @@
#define BENEATH 0x0080 /* No escape from the start dir */
#define LOCKSHARED 0x0100 /* Shared lock leaf */
#define NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */
-#define MODMASK 0x01fc /* mask of operational modifiers */
+#define RBENEATH 0x100000000ULL /* XXX */
+#define MODMASK 0xf000001fcULL /* mask of operational modifiers */
/*
* Namei parameter descriptors.
*
@@ -183,6 +184,7 @@
* Namei results flags
*/
#define NIRES_ABS 0x00000001 /* Path was absolute */
+#define NIRES_STRICTREL 0x00000002
/*
* Flags in ni_lcf, valid for the duration of the namei call.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 29, 9:14 PM (10 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32393994
Default Alt Text
D25886.id76952.diff (13 KB)
Attached To
Mode
D25886: Add O_RESOLVE_BENEATH and AT_RESOLVE_BENEATH to mimic Linux' RESOLVE_BENEATH
Attached
Detach File
Event Timeline
Log In to Comment