Page MenuHomeFreeBSD

D29111.id85294.diff
No OneTemporary

D29111.id85294.diff

diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -319,6 +319,7 @@
ndp->ni_lcf |= NI_LCF_STRICTRELATIVE;
ndp->ni_resflags |= NIRES_STRICTREL;
if (ndp->ni_dirfd == AT_FDCWD) {
+ /* XXXKIB allow for EMPTYPATH ? */
#ifdef KTRACE
if (KTRPOINT(td, KTR_CAPFAIL))
ktrcapfail(CAPFAIL_LOOKUP, NULL, NULL);
@@ -466,7 +467,6 @@
* Don't allow empty pathnames.
*/
if (__predict_false(*cnp->cn_pnbuf == '\0')) {
- namei_cleanup_cnp(cnp);
return (ENOENT);
}
@@ -554,6 +554,28 @@
error = namei_getpath(ndp);
if (__predict_false(error != 0)) {
+ if (error == ENOENT) {
+ MPASS(*cnp->cn_pnbuf == '\0');
+ if ((cnp->cn_flags & EMPTYPATH) != 0) {
+ MPASS((cnp->cn_flags & (LOCKLEAF |
+ LOCKPARENT | LOCKSHARED |
+ WANTPARENT)) == 0);
+ error = namei_setup(ndp, &dp, &pwd);
+ if (error == 0) {
+ ndp->ni_vp = dp;
+ vref(dp);
+ SDT_PROBE4(vfs, namei, lookup, return,
+ error, ndp->ni_vp, false, ndp);
+ namei_cleanup_cnp(cnp);
+ pwd_drop(pwd);
+ ndp->ni_resflags |= NIRES_EMPTYPATH;
+ NDVALIDATE(ndp);
+ return (0);
+ }
+ }
+ namei_cleanup_cnp(cnp);
+ }
+ SDT_PROBE4(vfs, namei, lookup, return, error, NULL, false, ndp);
return (error);
}
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -129,6 +129,8 @@
res |= (at_flags & AT_SYMLINK_NOFOLLOW) != 0 ? NOFOLLOW :
FOLLOW;
}
+ if ((mask & AT_EMPTY_PATH) != 0 && (at_flags & AT_EMPTY_PATH) != 0)
+ res |= EMPTYPATH;
return (res);
}
@@ -1496,12 +1498,13 @@
int flag;
flag = uap->flag;
- if ((flag & ~(AT_SYMLINK_FOLLOW | AT_RESOLVE_BENEATH)) != 0)
+ if ((flag & ~(AT_SYMLINK_FOLLOW | AT_RESOLVE_BENEATH |
+ AT_EMPTY_PATH)) != 0)
return (EINVAL);
return (kern_linkat(td, uap->fd1, uap->fd2, uap->path1, uap->path2,
UIO_USERSPACE, at2cnpflags(flag, AT_SYMLINK_FOLLOW |
- AT_RESOLVE_BENEATH)));
+ AT_RESOLVE_BENEATH | AT_EMPTY_PATH)));
}
int hardlink_check_uid = 0;
@@ -1578,6 +1581,23 @@
LOCKPARENT | SAVENAME | AUDITVNODE2 | NOCACHE, segflag, path, fd,
&cap_linkat_target_rights, td);
if ((error = namei(&nd)) == 0) {
+ if ((nd.ni_resflags & NIRES_EMPTYPATH) != 0) {
+ error = priv_check(td, PRIV_VFS_FHOPEN);
+ if (error != 0) {
+ NDFREE(&nd, NDF_ONLY_PNBUF);
+ if (nd.ni_vp != NULL) {
+ if (nd.ni_dvp == nd.ni_vp)
+ vrele(nd.ni_dvp);
+ else
+ vput(nd.ni_dvp);
+ vrele(nd.ni_vp);
+ } else {
+ vput(nd.ni_dvp);
+ }
+ vrele(vp);
+ return (error);
+ }
+ }
if (nd.ni_vp != NULL) {
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp == nd.ni_vp)
@@ -2710,7 +2730,8 @@
sys_chflagsat(struct thread *td, struct chflagsat_args *uap)
{
- if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0)
+ if ((uap->atflag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
+ AT_EMPTY_PATH)) != 0)
return (EINVAL);
return (kern_chflagsat(td, uap->fd, uap->path, UIO_USERSPACE,
@@ -2743,8 +2764,8 @@
AUDIT_ARG_FFLAGS(flags);
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(atflag, AT_SYMLINK_NOFOLLOW |
- AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd,
- &cap_fchflags_rights, td);
+ AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1, pathseg, path,
+ fd, &cap_fchflags_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
NDFREE_NOTHING(&nd);
@@ -2838,7 +2859,8 @@
sys_fchmodat(struct thread *td, struct fchmodat_args *uap)
{
- if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0)
+ if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
+ AT_EMPTY_PATH)) != 0)
return (EINVAL);
return (kern_fchmodat(td, uap->fd, uap->path, UIO_USERSPACE,
@@ -2871,8 +2893,8 @@
AUDIT_ARG_MODE(mode);
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW |
- AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd,
- &cap_fchmod_rights, td);
+ AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1, pathseg, path,
+ fd, &cap_fchmod_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
NDFREE_NOTHING(&nd);
@@ -2966,7 +2988,8 @@
sys_fchownat(struct thread *td, struct fchownat_args *uap)
{
- if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0)
+ if ((uap->flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
+ AT_EMPTY_PATH)) != 0)
return (EINVAL);
return (kern_fchownat(td, uap->fd, uap->path, UIO_USERSPACE, uap->uid,
@@ -2982,8 +3005,8 @@
AUDIT_ARG_OWNER(uid, gid);
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW |
- AT_RESOLVE_BENEATH) | AUDITVNODE1, pathseg, path, fd,
- &cap_fchown_rights, td);
+ AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1, pathseg, path,
+ fd, &cap_fchown_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -3334,13 +3357,14 @@
struct timespec ts[2];
int error, flags;
- if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0)
+ if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
+ AT_EMPTY_PATH)) != 0)
return (EINVAL);
if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0)
return (error);
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_SYMLINK_NOFOLLOW |
- AT_RESOLVE_BENEATH) | AUDITVNODE1,
+ AT_RESOLVE_BENEATH | AT_EMPTY_PATH) | AUDITVNODE1,
pathseg, path, fd, &cap_futimes_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h
--- a/sys/sys/fcntl.h
+++ b/sys/sys/fcntl.h
@@ -222,6 +222,7 @@
/* #define AT_UNUSED1 0x1000 *//* Was AT_BENEATH */
#define AT_RESOLVE_BENEATH 0x2000 /* Do not allow name resolution
to walk out of dirfd */
+#define AT_EMPTY_PATH 0x4000
#endif
/*
diff --git a/sys/sys/namei.h b/sys/sys/namei.h
--- a/sys/sys/namei.h
+++ b/sys/sys/namei.h
@@ -144,10 +144,12 @@
#define WANTPARENT 0x0010 /* want parent vnode returned unlocked */
#define FAILIFEXISTS 0x0020 /* return EEXIST if found */
#define FOLLOW 0x0040 /* follow symbolic links */
+#define EMPTYPATH 0x0080 /* Allow empty path for *at */
#define LOCKSHARED 0x0100 /* Shared lock leaf */
#define NOFOLLOW 0x0000 /* do not follow symbolic links (pseudo) */
#define RBENEATH 0x100000000ULL /* No escape, even tmp, from start dir */
#define MODMASK 0xf000001ffULL /* mask of operational modifiers */
+
/*
* Namei parameter descriptors.
*
@@ -198,6 +200,7 @@
*/
#define NIRES_ABS 0x00000001 /* Path was absolute */
#define NIRES_STRICTREL 0x00000002 /* Restricted lookup result */
+#define NIRES_EMPTYPATH 0x00000004
/*
* Flags in ni_lcf, valid for the duration of the namei call.

File Metadata

Mime Type
text/plain
Expires
Wed, Sep 25, 3:58 AM (18 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
12727785
Default Alt Text
D29111.id85294.diff (6 KB)

Event Timeline