From owner-svn-src-all@freebsd.org Tue Sep 22 22:48:13 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id B47DB3E2775; Tue, 22 Sep 2020 22:48:13 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4BwxKn4K6Zz3YSN; Tue, 22 Sep 2020 22:48:13 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 7771F26B13; Tue, 22 Sep 2020 22:48:13 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 08MMmDR9066005; Tue, 22 Sep 2020 22:48:13 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 08MMmCie066000; Tue, 22 Sep 2020 22:48:12 GMT (envelope-from kib@FreeBSD.org) Message-Id: <202009222248.08MMmCie066000@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Tue, 22 Sep 2020 22:48:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r366022 - in head/sys: kern sys X-SVN-Group: head X-SVN-Commit-Author: kib X-SVN-Commit-Paths: in head/sys: kern sys X-SVN-Commit-Revision: 366022 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 22 Sep 2020 22:48:13 -0000 Author: kib Date: Tue Sep 22 22:48:12 2020 New Revision: 366022 URL: https://svnweb.freebsd.org/changeset/base/366022 Log: Add O_RESOLVE_BENEATH and AT_RESOLVE_BENEATH to mimic Linux' RESOLVE_BENEATH. It is like O_BENEATH, but disables to walk out of the subtree rooted in the starting directory. O_BENEATH does not care if path walks out if it returned. Requested by: Dan Gohman PR: 248335 Reviewed by: markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D25886 Modified: head/sys/kern/vfs_lookup.c head/sys/kern/vfs_syscalls.c head/sys/kern/vfs_vnops.c head/sys/sys/fcntl.h head/sys/sys/namei.h Modified: head/sys/kern/vfs_lookup.c ============================================================================== --- head/sys/kern/vfs_lookup.c Tue Sep 22 22:43:32 2020 (r366021) +++ head/sys/kern/vfs_lookup.c Tue Sep 22 22:48:12 2020 (r366022) @@ -428,6 +428,16 @@ namei_setup(struct nameidata *ndp, struct vnode **dpp, 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. */ Modified: head/sys/kern/vfs_syscalls.c ============================================================================== --- head/sys/kern/vfs_syscalls.c Tue Sep 22 22:43:32 2020 (r366021) +++ head/sys/kern/vfs_syscalls.c Tue Sep 22 22:48:12 2020 (r366022) @@ -124,6 +124,8 @@ at2cnpflags(u_int at_flags, u_int mask) at_flags &= mask; if ((at_flags & AT_BENEATH) != 0) res |= BENEATH; + if ((at_flags & AT_RESOLVE_BENEATH) != 0) + res |= RBENEATH; if ((at_flags & AT_SYMLINK_FOLLOW) != 0) res |= FOLLOW; /* NOFOLLOW is pseudo flag */ @@ -1503,11 +1505,13 @@ sys_linkat(struct thread *td, struct linkat_args *uap) 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, at2cnpflags(flag, AT_SYMLINK_FOLLOW | AT_BENEATH))); + UIO_USERSPACE, at2cnpflags(flag, AT_SYMLINK_FOLLOW | AT_BENEATH | + AT_RESOLVE_BENEATH))); } int hardlink_check_uid = 0; @@ -1872,7 +1876,7 @@ kern_funlinkat(struct thread *td, int dfd, const char restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | - at2cnpflags(flag, AT_BENEATH), + at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), pathseg, path, dfd, &cap_unlinkat_rights, td); if ((error = namei(&nd)) != 0) { if (error == EINVAL) @@ -2075,7 +2079,7 @@ kern_accessat(struct thread *td, int fd, const char *p 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); @@ -2096,7 +2100,7 @@ kern_accessat(struct thread *td, int fd, const char *p usecred = cred; AUDIT_ARG_VALUE(amode); NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | - AUDITVNODE1 | at2cnpflags(flag, AT_BENEATH), + AUDITVNODE1 | at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), pathseg, path, fd, &cap_fstat_rights, td); if ((error = namei(&nd)) != 0) goto out; @@ -2387,11 +2391,12 @@ kern_statat(struct thread *td, int flag, int fd, const 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, at2cnpflags(flag, AT_BENEATH | - AT_SYMLINK_NOFOLLOW) | LOCKSHARED | LOCKLEAF | + AT_RESOLVE_BENEATH | AT_SYMLINK_NOFOLLOW) | LOCKSHARED | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, td); if ((error = namei(&nd)) != 0) @@ -2710,7 +2715,8 @@ int 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, @@ -2743,7 +2749,7 @@ kern_chflagsat(struct thread *td, int fd, const char * AUDIT_ARG_FFLAGS(flags); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(atflag, AT_SYMLINK_NOFOLLOW | - AT_BENEATH) | AUDITVNODE1, pathseg, path, fd, + AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchflags_rights, td); if ((error = namei(&nd)) != 0) return (error); @@ -2838,7 +2844,8 @@ int 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, @@ -2871,7 +2878,7 @@ kern_fchmodat(struct thread *td, int fd, const char *p AUDIT_ARG_MODE(mode); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | - AT_BENEATH) | AUDITVNODE1, pathseg, path, fd, + AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchmod_rights, td); if ((error = namei(&nd)) != 0) return (error); @@ -2966,7 +2973,8 @@ int 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, @@ -2982,7 +2990,7 @@ kern_fchownat(struct thread *td, int fd, const char *p AUDIT_ARG_OWNER(uid, gid); NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | - AT_BENEATH) | AUDITVNODE1, pathseg, path, fd, + AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, &cap_fchown_rights, td); if ((error = namei(&nd)) != 0) @@ -3334,13 +3342,14 @@ kern_utimensat(struct thread *td, int fd, const char * 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, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW | - AT_BENEATH) | AUDITVNODE1, + AT_BENEATH | AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd, &cap_futimes_rights, td); if ((error = namei(&nd)) != 0) return (error); @@ -3835,7 +3844,7 @@ kern_frmdirat(struct thread *td, int dfd, const char * restart: bwillwrite(); NDINIT_ATRIGHTS(&nd, DELETE, LOCKPARENT | LOCKLEAF | AUDITVNODE1 | - at2cnpflags(flag, AT_BENEATH), + at2cnpflags(flag, AT_BENEATH | AT_RESOLVE_BENEATH), pathseg, path, dfd, &cap_unlinkat_rights, td); if ((error = namei(&nd)) != 0) goto fdout; @@ -4320,7 +4329,8 @@ int 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)); @@ -4339,7 +4349,7 @@ kern_getfhat(struct thread *td, int flags, int fd, con if (error != 0) return (error); NDINIT_AT(&nd, LOOKUP, at2cnpflags(flags, AT_SYMLINK_NOFOLLOW | - AT_BENEATH) | LOCKLEAF | AUDITVNODE1, + AT_BENEATH | AT_RESOLVE_BENEATH) | LOCKLEAF | AUDITVNODE1, pathseg, path, fd, td); error = namei(&nd); if (error != 0) Modified: head/sys/kern/vfs_vnops.c ============================================================================== --- head/sys/kern/vfs_vnops.c Tue Sep 22 22:43:32 2020 (r366021) +++ head/sys/kern/vfs_vnops.c Tue Sep 22 22:48:12 2020 (r366022) @@ -200,6 +200,8 @@ open2nameif(int fmode, u_int vn_open_flags) res = ISOPEN | LOCKLEAF; if ((fmode & O_BENEATH) != 0) res |= BENEATH; + if ((fmode & O_RESOLVE_BENEATH) != 0) + res |= RBENEATH; if ((vn_open_flags & VN_OPEN_NOAUDIT) == 0) res |= AUDITVNODE1; if ((vn_open_flags & VN_OPEN_NOCAPCHECK) != 0) Modified: head/sys/sys/fcntl.h ============================================================================== --- head/sys/sys/fcntl.h Tue Sep 22 22:43:32 2020 (r366021) +++ head/sys/sys/fcntl.h Tue Sep 22 22:48:12 2020 (r366022) @@ -136,6 +136,9 @@ typedef __pid_t pid_t; #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 /* As O_BENEATH, but do not allow + resolve to walk out of cwd even to + return back */ #endif /* @@ -215,6 +218,9 @@ typedef __pid_t pid_t; #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 /* As AT_BENEATH, but do not allow + resolve to walk out of dirfd even + to return back */ #endif /* Modified: head/sys/sys/namei.h ============================================================================== --- head/sys/sys/namei.h Tue Sep 22 22:43:32 2020 (r366021) +++ head/sys/sys/namei.h Tue Sep 22 22:48:12 2020 (r366022) @@ -133,7 +133,8 @@ int cache_fplookup(struct nameidata *ndp, enum cache_f #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 /* No escape, even tmp, from start dir */ +#define MODMASK 0xf000001fcULL /* mask of operational modifiers */ /* * Namei parameter descriptors. *