diff options
| author | 2019-05-13 22:55:27 +0000 | |
|---|---|---|
| committer | 2019-05-13 22:55:27 +0000 | |
| commit | 1de745bca436d2f8732f18785f95bf07a0af4fd5 (patch) | |
| tree | 0b7e97ab8390170d430b7d0f71291029c45228b4 | |
| parent | Remove unused pad check, which is handled by tls1_cbc_remove_padding() now. (diff) | |
| download | wireguard-openbsd-1de745bca436d2f8732f18785f95bf07a0af4fd5.tar.xz wireguard-openbsd-1de745bca436d2f8732f18785f95bf07a0af4fd5.zip | |
Add a kernel implementation of realpath() as __realpath().
We want this so that we can stop allowing readlink() on traversed
vnodes in unveil().
This includes all the kernel side and the system call.
This is not yet used in libc for realpath, so nothing calls this yet.
The libc wrapper will be committed later.
Testing by many, and ports build by naddy@
ok deraadt@
| -rw-r--r-- | sys/kern/init_sysent.c | 8 | ||||
| -rw-r--r-- | sys/kern/kern_pledge.c | 3 | ||||
| -rw-r--r-- | sys/kern/syscalls.c | 6 | ||||
| -rw-r--r-- | sys/kern/syscalls.master | 5 | ||||
| -rw-r--r-- | sys/kern/vfs_getcwd.c | 4 | ||||
| -rw-r--r-- | sys/kern/vfs_lookup.c | 60 | ||||
| -rw-r--r-- | sys/kern/vfs_syscalls.c | 91 | ||||
| -rw-r--r-- | sys/sys/namei.h | 7 | ||||
| -rw-r--r-- | sys/sys/syscall.h | 8 | ||||
| -rw-r--r-- | sys/sys/syscallargs.h | 10 |
10 files changed, 178 insertions, 24 deletions
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 79933937915..a6a4b2e283e 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -1,10 +1,10 @@ -/* $OpenBSD: init_sysent.c,v 1.201 2019/05/09 20:30:22 cheloha Exp $ */ +/* $OpenBSD: init_sysent.c,v 1.202 2019/05/13 22:55:27 beck Exp $ */ /* * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * created from; OpenBSD: syscalls.master,v 1.189 2019/01/11 18:46:30 deraadt Exp + * created from; OpenBSD: syscalls.master,v 1.190 2019/05/09 20:30:22 cheloha Exp */ #include <sys/param.h> @@ -262,8 +262,8 @@ struct sysent sysent[] = { sys_nosys }, /* 113 = unimplemented fktrace */ { 2, s(struct sys_unveil_args), 0, sys_unveil }, /* 114 = unveil */ - { 0, 0, 0, - sys_nosys }, /* 115 = obsolete vtrace */ + { 2, s(struct sys___realpath_args), 0, + sys___realpath }, /* 115 = __realpath */ { 0, 0, 0, sys_nosys }, /* 116 = obsolete t32_gettimeofday */ { 0, 0, 0, diff --git a/sys/kern/kern_pledge.c b/sys/kern/kern_pledge.c index 04ade838271..6c68e592122 100644 --- a/sys/kern/kern_pledge.c +++ b/sys/kern/kern_pledge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_pledge.c,v 1.251 2019/02/14 15:41:47 florian Exp $ */ +/* $OpenBSD: kern_pledge.c,v 1.252 2019/05/13 22:55:27 beck Exp $ */ /* * Copyright (c) 2015 Nicholas Marriott <nicm@openbsd.org> @@ -253,6 +253,7 @@ const uint64_t pledge_syscalls[SYS_MAXSYSCALL] = { [SYS_stat] = PLEDGE_STDIO, [SYS_access] = PLEDGE_STDIO, [SYS_readlink] = PLEDGE_STDIO, + [SYS___realpath] = PLEDGE_STDIO, /* XXX Fix me Theo! Fix me! */ [SYS_adjtime] = PLEDGE_STDIO, /* setting requires "settime" */ [SYS_adjfreq] = PLEDGE_SETTIME, diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 2acf552dfc5..b6fc8fc6d5e 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -1,10 +1,10 @@ -/* $OpenBSD: syscalls.c,v 1.200 2019/05/09 20:30:22 cheloha Exp $ */ +/* $OpenBSD: syscalls.c,v 1.201 2019/05/13 22:55:27 beck Exp $ */ /* * System call names. * * DO NOT EDIT-- this file is automatically generated. - * created from; OpenBSD: syscalls.master,v 1.189 2019/01/11 18:46:30 deraadt Exp + * created from; OpenBSD: syscalls.master,v 1.190 2019/05/09 20:30:22 cheloha Exp */ char *syscallnames[] = { @@ -135,7 +135,7 @@ char *syscallnames[] = { "sendsyslog", /* 112 = sendsyslog */ "#113 (unimplemented fktrace)", /* 113 = unimplemented fktrace */ "unveil", /* 114 = unveil */ - "#115 (obsolete vtrace)", /* 115 = obsolete vtrace */ + "__realpath", /* 115 = __realpath */ "#116 (obsolete t32_gettimeofday)", /* 116 = obsolete t32_gettimeofday */ "#117 (obsolete t32_getrusage)", /* 117 = obsolete t32_getrusage */ "getsockopt", /* 118 = getsockopt */ diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 8474448d844..8c6ea62e801 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ -; $OpenBSD: syscalls.master,v 1.190 2019/05/09 20:30:22 cheloha Exp $ +; $OpenBSD: syscalls.master,v 1.191 2019/05/13 22:55:27 beck Exp $ ; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 @@ -240,7 +240,8 @@ 113 UNIMPL fktrace 114 STD { int sys_unveil(const char *path, \ const char *permissions); } -115 OBSOL vtrace +115 STD { int sys___realpath(const char *pathname, \ + char *resolved); } 116 OBSOL t32_gettimeofday 117 OBSOL t32_getrusage 118 STD { int sys_getsockopt(int s, int level, int name, \ diff --git a/sys/kern/vfs_getcwd.c b/sys/kern/vfs_getcwd.c index 4e04ceb0925..2707c1dcdde 100644 --- a/sys/kern/vfs_getcwd.c +++ b/sys/kern/vfs_getcwd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_getcwd.c,v 1.31 2018/05/27 06:02:14 visa Exp $ */ +/* $OpenBSD: vfs_getcwd.c,v 1.32 2019/05/13 22:55:27 beck Exp $ */ /* $NetBSD: vfs_getcwd.c,v 1.3.2.3 1999/07/11 10:24:09 sommerfeld Exp $ */ /* @@ -265,7 +265,7 @@ vfs_getcwd_getcache(struct vnode **lvpp, struct vnode **uvpp, char **bpp, return (error); } -/* Common routine shared by sys___getcwd() and vn_isunder() */ +/* Common routine shared by sys___getcwd() and vn_isunder() and sys___realpath() */ int vfs_getcwd_common(struct vnode *lvp, struct vnode *rvp, char **bpp, char *bufp, int limit, int flags, struct proc *p) diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index e9637a7f3e4..a57f6f99915 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_lookup.c,v 1.76 2019/01/03 21:52:31 beck Exp $ */ +/* $OpenBSD: vfs_lookup.c,v 1.77 2019/05/13 22:55:27 beck Exp $ */ /* $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */ /* @@ -61,6 +61,29 @@ void unveil_start_relative(struct proc *p, struct nameidata *ni); void unveil_check_component(struct proc *p, struct nameidata *ni, struct vnode *dp ); int unveil_check_final(struct proc *p, struct nameidata *ni); +int +component_push(struct componentname *cnp, char *component, size_t len) +{ + if (cnp->cn_rpi + len + 1 >= MAXPATHLEN) + return 0; + if (cnp->cn_rpi > 1) + cnp->cn_rpbuf[cnp->cn_rpi++] = '/'; + memcpy(cnp->cn_rpbuf + cnp->cn_rpi, component, len); + cnp->cn_rpi+=len; + cnp->cn_rpbuf[cnp->cn_rpi] = '\0'; + return 1; +} + +void +component_pop(struct componentname *cnp) +{ + while(cnp->cn_rpi && cnp->cn_rpbuf[cnp->cn_rpi] != '/' ) + cnp->cn_rpi--; + if (cnp->cn_rpi == 0 && cnp->cn_rpbuf[0] == '/') + cnp->cn_rpi++; + cnp->cn_rpbuf[cnp->cn_rpi] = '\0'; +} + void ndinitat(struct nameidata *ndp, u_long op, u_long flags, enum uio_seg segflg, int dirfd, const char *namep, struct proc *p) @@ -190,6 +213,11 @@ fail: if (cnp->cn_pnbuf[0] == '/') { dp = ndp->ni_rootdir; vref(dp); + if (cnp->cn_flags & REALPATH && cnp->cn_rpi == 0) { + cnp->cn_rpbuf[0] = '/'; + cnp->cn_rpbuf[1] = '\0'; + cnp->cn_rpi = 1; + } } else if (ndp->ni_dirfd == AT_FDCWD) { dp = fdp->fd_cdir; vref(dp); @@ -303,6 +331,13 @@ badlink: vref(dp); ndp->ni_unveil_match = NULL; unveil_check_component(p, ndp, dp); + if (cnp->cn_flags & REALPATH) { + cnp->cn_rpbuf[0] = '/'; + cnp->cn_rpbuf[1] = '\0'; + cnp->cn_rpi = 1; + } + } else if (cnp->cn_flags & REALPATH) { + component_pop(cnp); } } pool_put(&namei_pool, cnp->cn_pnbuf); @@ -441,6 +476,19 @@ dirloop: printf("{%s}: ", cnp->cn_nameptr); *cp = c; } #endif + if (cnp->cn_flags & REALPATH) { + size_t len = cp - cnp->cn_nameptr; + if (len == 2 && cnp->cn_nameptr[0] == '.' && + cnp->cn_nameptr[1] == '.') + component_pop(cnp); + else if (!(len == 1 && cnp->cn_nameptr[0] == '.')) { + if (!component_push(cnp, cnp->cn_nameptr, len)) { + error = ENAMETOOLONG; + goto bad; + } + } + } + ndp->ni_pathlen -= cnp->cn_namelen; ndp->ni_next = cp; /* @@ -529,10 +577,12 @@ dirloop: printf("not found\n"); #endif /* - * Allow for unveiling of a file in a directory - * where we don't have access to create it ourselves + * Allow for unveiling or realpath'ing a file in a + * directory where we don't have access to create it + * ourselves */ - if (ndp->ni_pledge == PLEDGE_UNVEIL && error == EACCES) + if ((ndp->ni_pledge == PLEDGE_UNVEIL || + (cnp->cn_flags & REALPATH)) && error == EACCES) error = EJUSTRETURN; if (error != EJUSTRETURN) @@ -808,3 +858,5 @@ bad: *vpp = NULL; return (error); } + + diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index be31bc6229c..5b649af01d7 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_syscalls.c,v 1.314 2019/03/24 18:14:20 beck Exp $ */ +/* $OpenBSD: vfs_syscalls.c,v 1.315 2019/05/13 22:55:27 beck Exp $ */ /* $NetBSD: vfs_syscalls.c,v 1.71 1996/04/23 10:29:02 mycroft Exp $ */ /* @@ -868,6 +868,95 @@ change_dir(struct nameidata *ndp, struct proc *p) } int +sys___realpath(struct proc *p, void *v, register_t *retval) +{ + struct sys___realpath_args /* { + syscallarg(const char *) pathname; + syscallarg(char *) resolved; + } */ *uap = v; + char *pathname; + char *cwdbuf; + char *rpbuf; + struct nameidata nd; + size_t pathlen; + int cwdlen = MAXPATHLEN * 4; + int error = 0; + + pathname = pool_get(&namei_pool, PR_WAITOK); + rpbuf = pool_get(&namei_pool, PR_WAITOK); + cwdbuf = malloc(cwdlen, M_TEMP, M_WAITOK); + + if ((error = copyinstr(SCARG(uap, pathname), pathname, MAXPATHLEN, + &pathlen))) + goto end; + + if (pathlen < 2) { + error = EINVAL; + goto end; + } + + /* Get cwd for relative path if needed, prepend to rpbuf */ + rpbuf[0] = '\0'; + if (pathname[0] != '/') { + char *path, *bp, *bend; + int lenused; + + bp = &cwdbuf[cwdlen]; + bend = bp; + *(--bp) = '\0'; + + error = vfs_getcwd_common(p->p_fd->fd_cdir, NULL, &bp, path, + cwdlen/2, GETCWD_CHECK_ACCESS, p); + + if (error) + goto end; + + lenused = bend - bp; + *retval = lenused; + + if (strlcpy(rpbuf, bp, MAXPATHLEN) >= MAXPATHLEN) { + error = ENAMETOOLONG; + goto end; + } + } + + if (pathlen == 2 && pathname[0] == '/') + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME | REALPATH, + UIO_SYSSPACE, pathname, p); + else + NDINIT(&nd, CREATE, FOLLOW | LOCKLEAF | LOCKPARENT | SAVENAME | + REALPATH, UIO_SYSSPACE, pathname, p); + + nd.ni_cnd.cn_rpbuf = rpbuf; + nd.ni_cnd.cn_rpi = strlen(rpbuf); + + nd.ni_pledge = PLEDGE_RPATH; + nd.ni_unveil = UNVEIL_READ; + if ((error = namei(&nd)) != 0) + goto end; + + /* release lock and reference from namei */ + if (nd.ni_vp) { + VOP_UNLOCK(nd.ni_vp); + vrele(nd.ni_vp); + } + if (nd.ni_dvp && nd.ni_dvp != nd.ni_vp){ + VOP_UNLOCK(nd.ni_dvp); + vrele(nd.ni_dvp); + } + + error = copyoutstr(nd.ni_cnd.cn_rpbuf, SCARG(uap, resolved), + MAXPATHLEN, NULL); + + pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf); +end: + pool_put(&namei_pool, rpbuf); + pool_put(&namei_pool, pathname); + free(cwdbuf, M_TEMP, cwdlen); + return (error); +} + +int sys_unveil(struct proc *p, void *v, register_t *retval) { struct sys_unveil_args /* { diff --git a/sys/sys/namei.h b/sys/sys/namei.h index aea0e511212..535a219603a 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -1,4 +1,4 @@ -/* $OpenBSD: namei.h,v 1.39 2019/01/17 03:26:19 beck Exp $ */ +/* $OpenBSD: namei.h,v 1.40 2019/05/13 22:55:27 beck Exp $ */ /* $NetBSD: namei.h,v 1.11 1996/02/09 18:25:20 christos Exp $ */ /* @@ -80,7 +80,7 @@ struct nameidata { /* * Lookup parameters: this structure describes the subset of - * information from the nameidata structure that is passed + * information from the nameidat satructure that is passed * through the VOP interface. */ struct componentname { @@ -95,6 +95,8 @@ struct nameidata { * Shared between lookup and commit routines. */ char *cn_pnbuf; /* pathname buffer */ + char *cn_rpbuf; /* realpath buffer */ + size_t cn_rpi; /* realpath index */ char *cn_nameptr; /* pointer to looked up name */ long cn_namelen; /* length of looked up component */ long cn_consume; /* chars to consume in lookup() */ @@ -143,6 +145,7 @@ struct nameidata { #define MAKEENTRY 0x004000 /* entry is to be added to name cache */ #define ISLASTCN 0x008000 /* this is last component of pathname */ #define ISSYMLINK 0x010000 /* symlink needs interpretation */ +#define REALPATH 0x020000 /* save pathname buffer for realpath */ #define REQUIREDIR 0x080000 /* must be a directory */ #define STRIPSLASHES 0x100000 /* strip trailing slashes */ #define PDIRUNLOCK 0x200000 /* vfs_lookup() unlocked parent dir */ diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index abbaf6eb647..2e6d31d731e 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -1,10 +1,10 @@ -/* $OpenBSD: syscall.h,v 1.200 2019/01/11 18:52:41 deraadt Exp $ */ +/* $OpenBSD: syscall.h,v 1.201 2019/05/13 22:55:27 beck Exp $ */ /* * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * created from; OpenBSD: syscalls.master,v 1.189 2019/01/11 18:46:30 deraadt Exp + * created from; OpenBSD: syscalls.master,v 1.190 2019/05/09 20:30:22 cheloha Exp */ /* syscall: "syscall" ret: "int" args: "int" "..." */ @@ -342,7 +342,9 @@ /* syscall: "unveil" ret: "int" args: "const char *" "const char *" */ #define SYS_unveil 114 - /* 115 is obsolete vtrace */ +/* syscall: "__realpath" ret: "int" args: "const char *" "char *" */ +#define SYS___realpath 115 + /* 116 is obsolete t32_gettimeofday */ /* 117 is obsolete t32_getrusage */ /* syscall: "getsockopt" ret: "int" args: "int" "int" "int" "void *" "socklen_t *" */ diff --git a/sys/sys/syscallargs.h b/sys/sys/syscallargs.h index ebe0ec9212f..532e51b596e 100644 --- a/sys/sys/syscallargs.h +++ b/sys/sys/syscallargs.h @@ -1,10 +1,10 @@ -/* $OpenBSD: syscallargs.h,v 1.203 2019/01/11 18:52:41 deraadt Exp $ */ +/* $OpenBSD: syscallargs.h,v 1.204 2019/05/13 22:55:27 beck Exp $ */ /* * System call argument lists. * * DO NOT EDIT-- this file is automatically generated. - * created from; OpenBSD: syscalls.master,v 1.189 2019/01/11 18:46:30 deraadt Exp + * created from; OpenBSD: syscalls.master,v 1.190 2019/05/09 20:30:22 cheloha Exp */ #ifdef syscallarg @@ -567,6 +567,11 @@ struct sys_unveil_args { syscallarg(const char *) permissions; }; +struct sys___realpath_args { + syscallarg(const char *) pathname; + syscallarg(char *) resolved; +}; + struct sys_getsockopt_args { syscallarg(int) s; syscallarg(int) level; @@ -1218,6 +1223,7 @@ int sys_pselect(struct proc *, void *, register_t *); int sys_sigsuspend(struct proc *, void *, register_t *); int sys_sendsyslog(struct proc *, void *, register_t *); int sys_unveil(struct proc *, void *, register_t *); +int sys___realpath(struct proc *, void *, register_t *); int sys_getsockopt(struct proc *, void *, register_t *); int sys_thrkill(struct proc *, void *, register_t *); int sys_readv(struct proc *, void *, register_t *); |
