PR/35278: YAMAMOTO Takashi: veriexec sometimes feeds user va to log(9)

Introduce the (intentionally undocumented) pathname_get(), pathname_path(),
and pathname_put(), to deal with allocating and copying of pathnames from
either kernel- or user-space.
This commit is contained in:
elad 2006-12-24 08:54:55 +00:00
parent 6e478b060b
commit 1124b0b8bc
3 changed files with 88 additions and 9 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_lookup.c,v 1.75 2006/12/13 13:36:19 yamt Exp $ */
/* $NetBSD: vfs_lookup.c,v 1.76 2006/12/24 08:54:55 elad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1993
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.75 2006/12/13 13:36:19 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.76 2006/12/24 08:54:55 elad Exp $");
#include "opt_ktrace.h"
#include "opt_systrace.h"
@ -70,6 +70,11 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_lookup.c,v 1.75 2006/12/13 13:36:19 yamt Exp $")
#define MAGICLINKS 0
#endif
struct pathname_internal {
char *pathbuf;
boolean_t needfree;
};
int vfs_magiclinks = MAGICLINKS;
struct pool pnbuf_pool; /* pathname buffer pool */
@ -191,6 +196,52 @@ symlink_magic(struct proc *p, char *cp, int *len)
#undef MATCH
#undef SUBSTITUTE
int
pathname_get(const char *dirp, enum uio_seg segflg, pathname_t *path)
{
int error;
if (dirp == NULL)
return (EFAULT);
*path = malloc(sizeof(struct pathname_internal), M_TEMP,
M_ZERO|M_WAITOK);
if (segflg == UIO_USERSPACE) {
(*path)->pathbuf = PNBUF_GET();
error = copyinstr(dirp, (*path)->pathbuf, MAXPATHLEN,
NULL);
if (error) {
PNBUF_PUT((*path)->pathbuf);
free(path, M_TEMP);
return (error);
}
(*path)->needfree = TRUE;
} else {
(*path)->pathbuf = __UNCONST(dirp);
(*path)->needfree = FALSE;
}
return (0);
}
const char *
pathname_path(pathname_t path)
{
KASSERT(path != NULL);
return (path->pathbuf);
}
void
pathname_put(pathname_t path)
{
if (path != NULL) {
if (path->pathbuf != NULL && path->needfree)
PNBUF_PUT(path->pathbuf);
free(path, M_TEMP);
}
}
/*
* Convert a pathname into a pointer to a locked vnode.
*

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_syscalls.c,v 1.281 2006/12/14 09:24:54 yamt Exp $ */
/* $NetBSD: vfs_syscalls.c,v 1.282 2006/12/24 08:54:55 elad Exp $ */
/*
* Copyright (c) 1989, 1993
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.281 2006/12/14 09:24:54 yamt Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_syscalls.c,v 1.282 2006/12/24 08:54:55 elad Exp $");
#include "opt_compat_netbsd.h"
#include "opt_compat_43.h"
@ -2015,6 +2015,9 @@ sys_unlink(struct lwp *l, void *v, register_t *retval)
struct vnode *vp;
int error;
struct nameidata nd;
#if NVERIEXEC > 0
pathname_t pathbuf;
#endif /* NVERIEXEC > 0 */
restart:
NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_USERSPACE,
@ -2038,8 +2041,15 @@ restart:
}
#if NVERIEXEC > 0
error = pathname_get(nd.ni_dirp, nd.ni_segflg, &pathbuf);
/* Handle remove requests for veriexec entries. */
if ((error = veriexec_removechk(vp, nd.ni_dirp, l)) != 0) {
if (!error) {
error = veriexec_removechk(vp, pathname_path(pathbuf), l);
pathname_put(pathbuf);
}
if (error) {
VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
if (nd.ni_dvp == vp)
vrele(nd.ni_dvp);
@ -3364,9 +3374,21 @@ rename_files(const char *from, const char *to, struct lwp *l, int retain)
}
#if NVERIEXEC > 0
if (!error)
error = veriexec_renamechk(fvp, fromnd.ni_dirp, tvp,
tond.ni_dirp, l);
if (!error) {
pathname_t frompath, topath;
error = pathname_get(fromnd.ni_dirp, fromnd.ni_segflg,
&frompath);
if (!error)
error = pathname_get(tond.ni_dirp, tond.ni_segflg,
&topath);
if (!error)
error = veriexec_renamechk(fvp, pathname_path(frompath),
tvp, pathname_path(topath), l);
pathname_put(frompath);
pathname_put(topath);
}
#endif /* NVERIEXEC > 0 */
out:

View File

@ -1,4 +1,4 @@
/* $NetBSD: namei.h,v 1.46 2006/12/09 16:11:52 chs Exp $ */
/* $NetBSD: namei.h,v 1.47 2006/12/24 08:54:55 elad Exp $ */
/*
* Copyright (c) 1985, 1989, 1991, 1993
@ -182,6 +182,8 @@ extern struct pool_cache pnbuf_cache; /* pathname buffer cache */
#define PNBUF_GET() pool_cache_get(&pnbuf_cache, PR_WAITOK)
#define PNBUF_PUT(pnb) pool_cache_put(&pnbuf_cache, (pnb))
typedef struct pathname_internal *pathname_t;
int namei(struct nameidata *);
uint32_t namei_hash(const char *, const char **);
int lookup(struct nameidata *);
@ -199,6 +201,10 @@ void nchinit(void);
void nchreinit(void);
void cache_purgevfs(struct mount *);
void namecache_print(struct vnode *, void (*)(const char *, ...));
int pathname_get(const char *, enum uio_seg, pathname_t *);
const char *pathname_path(pathname_t);
void pathname_put(pathname_t);
#endif
/*