Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131862395
D29111.id85709.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D29111.id85709.diff
View Options
diff --git a/lib/libc/sys/stat.2 b/lib/libc/sys/stat.2
--- a/lib/libc/sys/stat.2
+++ b/lib/libc/sys/stat.2
@@ -111,6 +111,17 @@
flag in the
.Xr open 2
manual page.
+.It Dv AT_EMPTY_PATH
+If the
+.Fa path
+argument is an empty string, operate on the file or directory
+referenced by the descriptor
+.Fa fd .
+If
+.Fa fd
+is equal to
+.Dv AT_FDCWD ,
+operate on the current working directory.
.El
.Pp
If
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);
@@ -400,7 +401,9 @@
}
#endif
}
- if (error == 0 && (*dpp)->v_type != VDIR)
+ if (error == 0 && (*dpp)->v_type != VDIR &&
+ (cnp->cn_pnbuf[0] != '\0' ||
+ (cnp->cn_flags & EMPTYPATH) == 0))
error = ENOTDIR;
}
if (error == 0 && (cnp->cn_flags & RBENEATH) != 0) {
@@ -466,7 +469,6 @@
* Don't allow empty pathnames.
*/
if (__predict_false(*cnp->cn_pnbuf == '\0')) {
- namei_cleanup_cnp(cnp);
return (ENOENT);
}
@@ -554,6 +556,36 @@
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 & (LOCKPARENT |
+ 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);
+ if ((cnp->cn_flags & LOCKLEAF) != 0) {
+ VOP_LOCK(dp, (cnp->cn_flags &
+ LOCKSHARED) != 0 ?
+ LK_SHARED : LK_EXCLUSIVE);
+ if (VN_IS_DOOMED(dp)) {
+ vput(dp);
+ return (ENOENT);
+ }
+ }
+ 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)
@@ -2387,12 +2407,13 @@
struct nameidata nd;
int error;
- if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH)) != 0)
+ if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_RESOLVE_BENEATH |
+ AT_EMPTY_PATH)) != 0)
return (EINVAL);
NDINIT_ATRIGHTS(&nd, LOOKUP, at2cnpflags(flag, AT_RESOLVE_BENEATH |
- AT_SYMLINK_NOFOLLOW) | LOCKSHARED | LOCKLEAF | AUDITVNODE1,
- pathseg, path, fd, &cap_fstat_rights, td);
+ AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH) | LOCKSHARED | LOCKLEAF |
+ AUDITVNODE1, pathseg, path, fd, &cap_fstat_rights, td);
if ((error = namei(&nd)) != 0)
return (error);
@@ -2710,7 +2731,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 +2765,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 +2860,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 +2894,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 +2989,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 +3006,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 +3358,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
@@ -219,10 +219,13 @@
#define AT_SYMLINK_NOFOLLOW 0x0200 /* Do not follow symbolic links */
#define AT_SYMLINK_FOLLOW 0x0400 /* Follow symbolic link */
#define AT_REMOVEDIR 0x0800 /* Remove directory instead of file */
+#endif /* __POSIX_VISIBLE >= 200809 */
+#if __BSD_VISIBLE
/* #define AT_UNUSED1 0x1000 *//* Was AT_BENEATH */
#define AT_RESOLVE_BENEATH 0x2000 /* Do not allow name resolution
to walk out of dirfd */
-#endif
+#define AT_EMPTY_PATH 0x4000 /* Operate on dirfd if path is empty */
+#endif /* __BSD_VISIBLE */
/*
* Constants used for fcntl(2)
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 /* EMPTYPATH used */
/*
* Flags in ni_lcf, valid for the duration of the namei call.
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Oct 12, 7:04 PM (2 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23637023
Default Alt Text
D29111.id85709.diff (8 KB)
Attached To
Mode
D29111: Add AT_EMPTY_PATH
Attached
Detach File
Event Timeline
Log In to Comment