Page MenuHomeFreeBSD

D23574.id68375.diff
No OneTemporary

D23574.id68375.diff

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

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)

Event Timeline