Date: Mon, 25 Nov 2002 12:09:02 +0100 From: Olivier Houchard <cognet@ci0.org> To: Bruce Evans <bde@zeta.org.au> Cc: freebsd-audit@FreeBSD.ORG Subject: Re: do_dup patch Message-ID: <20021125110902.GA10961@ci0.org> In-Reply-To: <20021125210116.I56453-100000@gamplex.bde.org> References: <20021125093228.GA10213@ci0.org> <20021125210116.I56453-100000@gamplex.bde.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, Nov 25, 2002 at 09:32:05PM +1100, Bruce Evans wrote: > On Mon, 25 Nov 2002, Olivier Houchard wrote: > > > This patch makes the "new" and "old" do_dup arguments unsigned int instead of > > int. I can't see any reason they would have to be int, and right now a call to > > dup or dup2 with an invalid negative fd, such as dup(-999999); will panic a > > -CURRENT box (the problem doesn't exist on -STABLE because the file descriptor > > validity is checked in dup() and dup2()). > > Is there anything wrong with committing this ? > > Yes; it is sort of backwards. > > File descriptors are small positive (signed) ints, and the dup() and dup2() > syscalls take file descriptors as parameters. However, dup() and dup2() > are misdeclared as taking u_int's as their parameters. This used to be > obfuscate/optimize away an explicit comparison with 0 in the bounds check > for the parameters. E.g., in RELENG_4: > > % #ifndef _SYS_SYSPROTO_H_ > % struct dup2_args { > % u_int from; > % u_int to; > ^^^^^ > Bogus type for bogus optimization. This is pseudo-code; see > <sys/sysproto.h> for the actual declaration. This misdeclaration > needs something like normal 2's complement machines to work since > we never actually convert the parameters from ints to u_ints; > we just pass ints and pretend that they are u_ints. > > % }; > % #endif > % /* ARGSUSED */ > % int > % dup2(p, uap) > % struct proc *p; > % struct dup2_args *uap; > % { > % register struct filedesc *fdp = p->p_fd; > % register u_int old = uap->from, new = uap->to; > % int i, error; > % > % retry: > % if (old >= fdp->fd_nfiles || > ^^^^^^^^^^^^^^^^^^^^^ > > Bogus optimization. The upper and lower bounds are checked in a > single comparison. The only reason to do this seems to be to > hand-optimize for 20+-year old compilers on pdp11-like machines > where the 2 comparisons can be collapes into a single machine > instruction and the compiler doesn't do this automatically. > > % fdp->fd_ofiles[old] == NULL || > % new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || > % new >= maxfilesperproc) { > % return (EBADF); > % } > > In -current, this has rotted to: > > % int > % dup2(td, uap) > % struct thread *td; > % struct dup2_args *uap; > % { > % > % return (do_dup(td, DUP_FIXED, (int)uap->from, (int)uap->to, > ^^^^^ ^^^^^ > > Bogus casts to break warnings about our type errors. > > % td->td_retval)); > > % } > % ... > % static int > % do_dup(td, type, old, new, retval) > % enum dup_type type; > % int old, new; > % register_t *retval; > % struct thread *td; > % { > % register struct filedesc *fdp; > % struct proc *p; > % struct file *fp; > % struct file *delfp; > % int error, newfd; > % > % p = td->td_proc; > % fdp = p->p_fd; > % > % /* > % * Verify we have a valid descriptor to dup from and possibly to > % * dup to. > % */ > % FILEDESC_LOCK(fdp); > % if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL || > ^^^^^^^^^^^^^^^^^^^^^ > > Bug. The bogus optimization has been broken by changing the types. > > % new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || > % new >= maxfilesperproc) { > % FILEDESC_UNLOCK(fdp); > % return (EBADF); > % } > > Bruce Right. So what would be the best ? Changing dup and dup2 prototypes in syscall.master to make new and old signed instead of unsigned and checking that new >= 0 && old >= 0 in do_dup ? Thanks, Olivier To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-audit" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021125110902.GA10961>