Subject: kern/337: rename can cause kernel panic on a nullfs
To: None <gnats-admin>
From: Duncan McEwan <duncan@Comp.VUW.AC.NZ>
List: netbsd-bugs
Date: 07/11/1994 00:35:04
>Number: 337
>Category: kern
>Synopsis: rename can cause kernel panic on a nullfs
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: gnats-admin (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Jul 11 00:35:02 1994
>Originator: Duncan McEwan
>Organization:
Computer Science Dept, Victoria University of Wellington, New Zealand
>Release:
>Environment:
System: NetBSD orsinis.pc.comp.vuw.ac.nz 0.9C
NetBSD 0.9C (ORSINIS) #4: Tue Jul 5 17:34:43 NZST 1994
root@orsinis.pc.comp.vuw.ac.nz:/am/orsinis/home/src/sys/arch/i386/compile/ORSINIS i386
>Description:
If the target file of a rename system call doesn't exist on a nullfs
filesystem, the kernel can panic when it attempts to dereference a
null pointer.
>How-To-Repeat:
mkdir /tmp/foo
mount -t null /tmp/foo /mnt
cd /mnt
touch bar
mv bar baz
At this point (at least on my system) the kernel panics with
vm_fault(f86a4000, 0, 1, 0) -> 1
kernel: page fault trap, code=0
stopped at _null_bypass+0x4f: movl 0x18(%eax), %eax
Examining the contents of eax show it to be 0.
>Fix:
The above assembler coresponds to line 253 of sys/miscfs/nullfs/null_vnops.c
($NetBSD: null_vnops.c,v 1.2 1994/06/29 06:34:35). On the 4th interation around
the enclosing loop, this_vp_p contains a pointer to a pointer to the vnode for
the destination file. Unfortunately, when renaming to a file that doesn't
already exist, the vnode pointer is NULL, hence the panic.
My fix was to prevent dereferencing *this_vp_p if it is NULL as follows.
*** null_vnops.c.ORIG Wed Jun 29 22:29:54 1994
--- null_vnops.c Mon Jul 11 18:31:23 1994
***************
*** 251,258 ****
* that aren't. (We must always map first vp or vclean fails.)
*/
! if (i && (*this_vp_p)->v_op != null_vnodeop_p) {
old_vps[i] = NULL;
} else {
old_vps[i] = *this_vp_p;
*(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
/*
--- 251,259 ----
* that aren't. (We must always map first vp or vclean fails.)
*/
! if (i && *this_vp_p != 0 && (*this_vp_p)->v_op != null_vnodeop_p) {
old_vps[i] = NULL;
} else {
old_vps[i] = *this_vp_p;
+ if (! *this_vp_p) continue;
*(vps_p[i]) = NULLVPTOLOWERVP(*this_vp_p);
/*
There are other nicer ways of structuring the code to achieve the same effect,
but this was enough to convince myself that preventing the null dereference
fixed the panic. I'll leave it up to someone in the core team to figure out if
this is the appropriate fix, and if so, what the best way of restructuring the
code is.
>Audit-Trail:
>Unformatted:
------------------------------------------------------------------------------