Date: Mon, 25 Nov 2002 21:32:05 +1100 (EST) From: Bruce Evans <bde@zeta.org.au> To: Olivier Houchard <cognet@ci0.org> Cc: freebsd-audit@FreeBSD.ORG Subject: Re: do_dup patch Message-ID: <20021125210116.I56453-100000@gamplex.bde.org> In-Reply-To: <20021125093228.GA10213@ci0.org>
next in thread | previous in thread | raw e-mail | index | archive | help
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
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?20021125210116.I56453-100000>
