filemon: Reject FILEMON_SET_FD commands when the fd is a kqueue

When FILEMON_SET_FD is used, the filemon handle effectively wraps the
passed file.  In particular, the handle may be inherited by a child
process, or transferred over a unix domain socket, so we must verify
that the backing file permits this.

Reported by:	syzbot+36e6be9e02735fe66ca8@syzkaller.appspotmail.com
Reviewed by:	emaste
MFC after:	1 week
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D34128
This commit is contained in:
Mark Johnston 2022-02-03 09:41:17 -05:00
parent d51c80351f
commit b84ed4e7f6

View File

@ -359,9 +359,10 @@ static int
filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused, filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused,
struct thread *td) struct thread *td)
{ {
int error = 0;
struct filemon *filemon; struct filemon *filemon;
struct file *fp;
struct proc *p; struct proc *p;
int error;
if ((error = devfs_get_cdevpriv((void **) &filemon)) != 0) if ((error = devfs_get_cdevpriv((void **) &filemon)) != 0)
return (error); return (error);
@ -376,12 +377,21 @@ filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused,
break; break;
} }
error = fget_write(td, *(int *)data, error = fget_write(td, *(int *)data, &cap_pwrite_rights, &fp);
&cap_pwrite_rights, if (error == 0) {
&filemon->fp); /*
if (error == 0) * The filemon handle may be passed to another process,
* so the underlying file handle must support this.
*/
if ((fp->f_ops->fo_flags & DFLAG_PASSABLE) == 0) {
fdrop(fp, curthread);
error = EINVAL;
break;
}
filemon->fp = fp;
/* Write the file header. */ /* Write the file header. */
filemon_write_header(filemon); filemon_write_header(filemon);
}
break; break;
/* Set the monitored process ID. */ /* Set the monitored process ID. */