Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107732002
D23574.id68375.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D23574.id68375.diff
View Options
Index: lib/libc/stdlib/realpath.c
===================================================================
--- lib/libc/stdlib/realpath.c
+++ lib/libc/stdlib/realpath.c
@@ -43,13 +43,16 @@
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
+#include "libc_private.h"
+
+extern int __realpath(const char *path, char *buf, size_t size, int flags);
/*
* Find the real name of path, by removing all ".", ".." and symlink
* components. Returns (resolved) on success, or (NULL) on failure,
* in which case the path which caused trouble is left in (resolved).
*/
-static char *
+static char * __noinline
realpath1(const char *path, char *resolved)
{
struct stat sb;
@@ -223,6 +226,10 @@
if (resolved == NULL)
return (NULL);
}
+ if (__getosreldate() > 1234) {
+ if (__realpath(path, resolved, PATH_MAX, 0) == 0)
+ return (resolved);
+ }
res = realpath1(path, resolved);
if (res == NULL)
free(m);
Index: lib/libc/sys/Symbol.map
===================================================================
--- lib/libc/sys/Symbol.map
+++ lib/libc/sys/Symbol.map
@@ -828,6 +828,7 @@
__sys_readlink;
_readv;
__sys_readv;
+ ___realpath;
_reboot;
__sys_reboot;
_recvfrom;
Index: libexec/rtld-elf/rtld-libc/Makefile.inc
===================================================================
--- libexec/rtld-elf/rtld-libc/Makefile.inc
+++ libexec/rtld-elf/rtld-libc/Makefile.inc
@@ -49,7 +49,7 @@
sysarch __sysctl issetugid __getcwd utrace \
thr_self thr_kill pread mmap lseek _exit _fstat _fstatat _fstatfs \
getdirentries _getdirentries _close _fcntl _open _openat _read \
- _sigprocmask _write readlink _setjmp setjmp setjmperr
+ _sigprocmask _write readlink __realpath _setjmp setjmp setjmperr
# Finally add additional architecture-dependent libc dependencies
Index: sys/bsm/audit_kevents.h
===================================================================
--- sys/bsm/audit_kevents.h
+++ sys/bsm/audit_kevents.h
@@ -657,6 +657,7 @@
#define AUE_LGETUUID 43261 /* CADETS. */
#define AUE_EXECVEAT 43262 /* FreeBSD/Linux. */
#define AUE_SHMRENAME 43263 /* FreeBSD-specific. */
+#define AUE_REALPATH 43264 /* FreeBSD-specific. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
Index: sys/compat/freebsd32/syscalls.master
===================================================================
--- sys/compat/freebsd32/syscalls.master
+++ sys/compat/freebsd32/syscalls.master
@@ -1160,5 +1160,7 @@
572 AUE_SHMRENAME NOPROTO { int shm_rename(const char *path_from, \
const char *path_to, int flags); }
573 AUE_NULL NOPROTO { int sigfastblock(int cmd, uint32_t *ptr); }
+574 AUE_REALPATH NOPROTO { int __realpath(const char *path, char *buf, \
+ size_t size, int flags); }
; vim: syntax=off
Index: sys/kern/syscalls.master
===================================================================
--- sys/kern/syscalls.master
+++ sys/kern/syscalls.master
@@ -3218,6 +3218,14 @@
_Inout_opt_ uint32_t *ptr
);
}
+574 AUE_REALPATH STD {
+ int __realpath(
+ _In_z_ const char *path,
+ _Out_writes_z_(size) char *buf,
+ size_t size,
+ int flags
+ );
+ }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
Index: sys/kern/vfs_cache.c
===================================================================
--- sys/kern/vfs_cache.c
+++ sys/kern/vfs_cache.c
@@ -42,6 +42,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/capsicum.h>
#include <sys/counter.h>
#include <sys/filedesc.h>
#include <sys/fnv_hash.h>
@@ -387,8 +388,12 @@
"Number of times shrinking was already in progress");
static void cache_zap_locked(struct namecache *ncp, bool neg_locked);
-static int vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
+static int vn_fullpath_hardlink(struct thread *td, struct nameidata *ndp, char **retbuf,
+ char **freebuf, size_t *buflen);
+static int vn_fullpath_any(struct thread *td, struct vnode *vp, struct vnode *rdir,
char *buf, char **retbuf, size_t *buflen);
+static int vn_fullpath_dir(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, size_t *len, bool slash_prefixed, size_t addend);
static MALLOC_DEFINE(M_VFSCACHE, "vfscache", "VFS name cache entries");
@@ -2201,7 +2206,7 @@
rdir = fdp->fd_rdir;
vrefact(rdir);
FILEDESC_SUNLOCK(fdp);
- error = vn_fullpath1(td, cdir, rdir, buf, retbuf, buflen);
+ error = vn_fullpath_any(td, cdir, rdir, buf, retbuf, buflen);
vrele(rdir);
vrele(cdir);
@@ -2212,6 +2217,37 @@
return (error);
}
+static int
+kern___realpath(struct thread *td, const char *path, char *buf, size_t size,
+ int flags, enum uio_seg pathseg)
+{
+ struct nameidata nd;
+ char *retbuf, *freebuf;
+ int error;
+
+ if (flags != 0)
+ return (EINVAL);
+ NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | SAVENAME | WANTPARENT | AUDITVNODE1,
+ pathseg, path, AT_FDCWD, &cap_fstat_rights, td);
+ if ((error = namei(&nd)) != 0)
+ return (error);
+ error = vn_fullpath_hardlink(td, &nd, &retbuf, &freebuf, &size);
+ if (error == 0) {
+ error = copyout(retbuf, buf, size);
+ free(freebuf, M_TEMP);
+ }
+ NDFREE(&nd, 0);
+ return (error);
+}
+
+int
+sys___realpath(struct thread *td, struct __realpath_args *uap)
+{
+
+ return (kern___realpath(td, uap->path, uap->buf, uap->size, uap->flags,
+ UIO_USERSPACE));
+}
+
/*
* Retrieve the full filesystem path that correspond to a vnode from the name
* cache (if available)
@@ -2235,7 +2271,7 @@
rdir = fdp->fd_rdir;
vrefact(rdir);
FILEDESC_SUNLOCK(fdp);
- error = vn_fullpath1(td, vn, rdir, buf, retbuf, &buflen);
+ error = vn_fullpath_any(td, vn, rdir, buf, retbuf, &buflen);
vrele(rdir);
if (!error)
@@ -2263,7 +2299,7 @@
return (EINVAL);
buflen = MAXPATHLEN;
buf = malloc(buflen, M_TEMP, M_WAITOK);
- error = vn_fullpath1(td, vn, rootvnode, buf, retbuf, &buflen);
+ error = vn_fullpath_any(td, vn, rootvnode, buf, retbuf, &buflen);
if (!error)
*freebuf = buf;
else
@@ -2334,40 +2370,40 @@
}
/*
- * The magic behind vn_getcwd() and vn_fullpath().
+ * Resolve a directory to a pathname.
+ *
+ * The name of the directory can always be found in the namecache or fetched
+ * from the filesystem. There is also guaranteed to be only one parent, meaning
+ * we can just follow vnodes up until we find the root.
+ *
+ * The vnode must be referenced.
*/
static int
-vn_fullpath1(struct thread *td, struct vnode *vp, struct vnode *rdir,
- char *buf, char **retbuf, size_t *len)
+vn_fullpath_dir(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, size_t *len, bool slash_prefixed, size_t addend)
{
- int error, slash_prefixed;
#ifdef KDTRACE_HOOKS
struct vnode *startvp = vp;
#endif
struct vnode *vp1;
size_t buflen;
+ int error;
+
+ VNPASS(vp->v_type == VDIR || VN_IS_DOOMED(vp), vp);
+ VNPASS(vp->v_usecount > 0, vp);
buflen = *len;
- buflen--;
- buf[buflen] = '\0';
+ if (!slash_prefixed) {
+ MPASS(*len >= 2);
+ buflen--;
+ buf[buflen] = '\0';
+ }
+
error = 0;
- slash_prefixed = 0;
SDT_PROBE1(vfs, namecache, fullpath, entry, vp);
counter_u64_add(numfullpathcalls, 1);
- vref(vp);
- if (vp->v_type != VDIR) {
- error = vn_vptocnp(&vp, td->td_ucred, buf, &buflen);
- if (error)
- return (error);
- if (buflen == 0) {
- vrele(vp);
- return (ENOMEM);
- }
- buf[--buflen] = '/';
- slash_prefixed = 1;
- }
while (vp != rdir && vp != rootvnode) {
/*
* The vp vnode must be already fully constructed,
@@ -2420,7 +2456,7 @@
break;
}
buf[--buflen] = '/';
- slash_prefixed = 1;
+ slash_prefixed = true;
}
if (error)
return (error);
@@ -2437,12 +2473,128 @@
counter_u64_add(numfullpathfound, 1);
vrele(vp);
- SDT_PROBE3(vfs, namecache, fullpath, return, 0, startvp, buf + buflen);
*retbuf = buf + buflen;
+ SDT_PROBE3(vfs, namecache, fullpath, return, 0, startvp, *retbuf);
*len -= buflen;
+ *len += addend;
return (0);
}
+/*
+ * Resolve an arbitrary vnode to a pathname.
+ *
+ * Note 2 caveats:
+ * - hardlinks are not tracked, thus if the vnode is not a directory this can
+ * resolve to a different path than the one used to find it
+ * - namecache is not mandatory, meaning names are not guaranteed to be added
+ * (in which case resolving fails)
+ */
+static int
+vn_fullpath_any(struct thread *td, struct vnode *vp, struct vnode *rdir,
+ char *buf, char **retbuf, size_t *buflen)
+{
+ size_t orig_buflen;
+ bool slash_prefixed;
+ int error;
+
+ if (*buflen < 2)
+ return (EINVAL);
+
+ orig_buflen = *buflen;
+
+ vref(vp);
+ slash_prefixed = false;
+ if (vp->v_type != VDIR) {
+ *buflen -= 1;
+ buf[*buflen] = '\0';
+ error = vn_vptocnp(&vp, td->td_ucred, buf, buflen);
+ if (error)
+ return (error);
+ if (*buflen == 0) {
+ vrele(vp);
+ return (ENOMEM);
+ }
+ *buflen -= 1;
+ buf[*buflen] = '/';
+ slash_prefixed = true;
+ }
+
+ return (vn_fullpath_dir(td, vp, rdir, buf, retbuf, buflen, slash_prefixed,
+ orig_buflen - *buflen));
+}
+
+/*
+ * Resolve an arbitrary vnode to a pathname (taking care of hardlinks).
+ *
+ * Since the namecache does not track handlings, the caller is expected to first
+ * look up the target vnode with SAVENAME | WANTPARENT flags passed to namei.
+ *
+ * Then we have 2 cases:
+ * - if the found vnode is a directory, the path can be constructed just by
+ * fullowing names up the chain
+ * - otherwise we populate the buffer with the saved name and start resolving
+ * from the parent
+ */
+static int
+vn_fullpath_hardlink(struct thread *td, struct nameidata *ndp, char **retbuf,
+ char **freebuf, size_t *buflen)
+{
+ char *buf, *tmpbuf;
+ struct filedesc *fdp;
+ struct vnode *rdir;
+ struct componentname *cnp;
+ struct vnode *vp;
+ size_t addend;
+ int error;
+ bool slash_prefixed;
+
+ if (*buflen < 2)
+ return (EINVAL);
+ if (*buflen > MAXPATHLEN)
+ *buflen = MAXPATHLEN;
+
+ slash_prefixed = false;
+
+ buf = malloc(*buflen, M_TEMP, M_WAITOK);
+ fdp = td->td_proc->p_fd;
+ FILEDESC_SLOCK(fdp);
+ rdir = fdp->fd_rdir;
+ vrefact(rdir);
+ FILEDESC_SUNLOCK(fdp);
+
+ addend = 0;
+ vp = ndp->ni_vp;
+ if (vp->v_type != VDIR) {
+ cnp = &ndp->ni_cnd;
+ addend = cnp->cn_namelen + 2;
+ if (*buflen < addend) {
+ error = ENOMEM;
+ goto out_bad;
+ }
+ *buflen -= addend;
+ tmpbuf = buf + *buflen;
+ tmpbuf[0] = '/';
+ memcpy(&tmpbuf[1], cnp->cn_nameptr, cnp->cn_namelen);
+ tmpbuf[addend - 1] = '\0';
+ slash_prefixed = true;
+ vp = ndp->ni_dvp;
+ }
+
+ vref(vp);
+ error = vn_fullpath_dir(td, vp, rdir, buf, retbuf, buflen, slash_prefixed, addend);
+ if (error != 0)
+ goto out_bad;
+
+ vrele(rdir);
+ *freebuf = buf;
+
+ return (0);
+out_bad:
+ vrele(rdir);
+ free(buf, M_TEMP);
+ return (error);
+}
+
struct vnode *
vn_dir_dd_ino(struct vnode *vp)
{
Index: sys/security/audit/audit_bsm.c
===================================================================
--- sys/security/audit/audit_bsm.c
+++ sys/security/audit/audit_bsm.c
@@ -737,6 +737,7 @@
audit_sys_auditon(ar, rec);
break;
+ case AUE_REALPATH:
case AUE_AUDITCTL:
UPATH1_VNODE1_TOKENS;
break;
Index: usr.bin/truss/syscalls.c
===================================================================
--- usr.bin/truss/syscalls.c
+++ usr.bin/truss/syscalls.c
@@ -115,6 +115,9 @@
.args = { { Int, 0 }, { Int, 1 }, { CapRights | OUT, 2 } } },
{ .name = "__getcwd", .ret_type = 1, .nargs = 2,
.args = { { Name | OUT, 0 }, { Int, 1 } } },
+ { .name = "__realpath", .ret_type = 1, .nargs = 4,
+ .args = { { Name | IN, 0 }, { Name | OUT, 1 }, { Sizet, 2 },
+ { Int, 3} } },
{ .name = "_umtx_op", .ret_type = 1, .nargs = 5,
.args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
{ Ptr, 4 } } },
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 18, 8:45 PM (50 m, 59 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15891805
Default Alt Text
D23574.id68375.diff (11 KB)
Attached To
Mode
D23574: vfs: add kernel-side realpathat
Attached
Detach File
Event Timeline
Log In to Comment