ktrace: Avoid recursion in namei()

sys_ktrace() calls namei(), which may call ktrnamei().  But sys_ktrace()
also calls ktrace_enter() first, so if the caller is itself being
traced, the assertion in ktrace_enter() is triggered.  And, ktrnamei()
does not check for recursion like most other ktrace ops do.

Fix the bug by simply deferring the ktrace_enter() call.

Also make the parameter to ktrnamei() const and convert to ANSI.

Reported by:	syzbot+d0a4de45e58d3c08af4b@syzkaller.appspotmail.com
Reviewed by:	kib
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D30340
This commit is contained in:
Mark Johnston 2021-05-22 12:07:32 -04:00
parent e67ef6ce66
commit e4b16f2fb1
2 changed files with 6 additions and 9 deletions

View File

@ -698,8 +698,7 @@ ktruserret(struct thread *td)
} }
void void
ktrnamei(path) ktrnamei(const char *path)
char *path;
{ {
struct ktr_request *req; struct ktr_request *req;
int namelen; int namelen;
@ -1017,7 +1016,6 @@ sys_ktrace(struct thread *td, struct ktrace_args *uap)
return (EINVAL); return (EINVAL);
kiop = NULL; kiop = NULL;
ktrace_enter(td);
if (ops != KTROP_CLEAR) { if (ops != KTROP_CLEAR) {
/* /*
* an operation which requires a file argument. * an operation which requires a file argument.
@ -1025,23 +1023,22 @@ sys_ktrace(struct thread *td, struct ktrace_args *uap)
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, td); NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->fname, td);
flags = FREAD | FWRITE | O_NOFOLLOW; flags = FREAD | FWRITE | O_NOFOLLOW;
error = vn_open(&nd, &flags, 0, NULL); error = vn_open(&nd, &flags, 0, NULL);
if (error) { if (error)
ktrace_exit(td);
return (error); return (error);
}
NDFREE(&nd, NDF_ONLY_PNBUF); NDFREE(&nd, NDF_ONLY_PNBUF);
vp = nd.ni_vp; vp = nd.ni_vp;
VOP_UNLOCK(vp); VOP_UNLOCK(vp);
if (vp->v_type != VREG) { if (vp->v_type != VREG) {
(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td); (void)vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
ktrace_exit(td);
return (EACCES); return (EACCES);
} }
kiop = ktr_io_params_alloc(td, vp); kiop = ktr_io_params_alloc(td, vp);
} }
/* /*
* Clear all uses of the tracefile. * Clear all uses of the tracefile.
*/ */
ktrace_enter(td);
if (ops == KTROP_CLEARFILE) { if (ops == KTROP_CLEARFILE) {
restart: restart:
sx_slock(&allproc_lock); sx_slock(&allproc_lock);

View File

@ -269,7 +269,7 @@ struct ktr_io_params;
struct vnode *ktr_get_tracevp(struct proc *, bool); struct vnode *ktr_get_tracevp(struct proc *, bool);
void ktr_io_params_free(struct ktr_io_params *); void ktr_io_params_free(struct ktr_io_params *);
void ktrnamei(char *); void ktrnamei(const char *);
void ktrcsw(int, int, const char *); void ktrcsw(int, int, const char *);
void ktrpsig(int, sig_t, sigset_t *, int); void ktrpsig(int, sig_t, sigset_t *, int);
void ktrfault(vm_offset_t, int); void ktrfault(vm_offset_t, int);