Subject: kern/394: NetBSD NFS diskless operation doesn't work properly
To: None <gnats-admin>
From: Chuck Cranor <chuck@netbsd.ccrc.wustl.edu>
List: netbsd-bugs
Date: 08/04/1994 18:35:09
>Number: 394
>Category: kern
>Synopsis: NetBSD NFS diskless operation doesn't work properly
>Confidential: no
>Severity: critical
>Priority: medium
>Responsible: gnats-admin (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Aug 4 18:35:06 1994
>Originator: Chuck Cranor <chuck@maria.wustl.edu>
>Organization:
Washington University, St. Louis MO
>Release: netbsd-current (sup'd aug 3)
>Environment:
diskless
System: NetBSD netbsd.ccrc.wustl.edu 1.0_BETA
NetBSD 1.0_BETA (CCRC) #0: Thu Aug 4 01:35:19 CDT 1994
chuck@xxx.ccrc.wustl.edu:/usr/src/sys/arch/sparc/compile/CCRC sparc
>Description:
Two bugs prevent NetBSD from operating correctly in a diskless
environment.
[1] NetBSD does not use a priv UDP port to talk to rpc.mountd
and to mount its root file system
[2] bind() system call will fail if you specify an IP address
(effects ftp)
>How-To-Repeat:
[1] Try to boot NetBSD from a sun with rpc.mountd run without "-n"
and "nfs_portmon" set to one. Mount will fail with error 72
(I think).
It is highly advisable to run your NFS server with nfs_portmon
turned on, or any user can mount your filesystems with a
simple user level socket/UDP program and violate your
security.
[2] Fix problem [1], and run "ftp"... connect to a host and
try to do an "ls" command in ftp. It will fail
in "bind" with EADDRNOTAVAIL.
>Fix:
[1] SunOS seems to always use priv ports for NFS diskless
boot up. Copy that idea. Patch files
/usr/src/sys/nfs/krpc_subr.c and nfs_vfsops.c.
*** 1.1 1994/08/03 15:35:29
--- krpc_subr.c 1994/08/05 01:16:02
***************
*** 215,220 ****
--- 215,238 ----
if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
goto out;
+ {
+ struct sockaddr_in *sin;
+ u_short tport;
+ MGET(m, M_WAIT, MT_SONAME);
+ sin = mtod(m, struct sockaddr_in *);
+ sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = INADDR_ANY;
+ tport = IPPORT_RESERVED - 1;
+ sin->sin_port = htons(tport);
+ while ((error = sobind(so, m)) == EADDRINUSE &&
+ --tport > IPPORT_RESERVED / 2)
+ sin->sin_port = htons(tport);
+ m_freem(m);
+ if (error)
+ goto out;
+ }
+
/*
* Setup socket address for the server.
*/
*** 1.1 1994/08/03 15:25:32
--- nfs_vfsops.c 1994/08/03 15:14:28
***************
*** 303,308 ****
--- 303,309 ----
args.sotype = SOCK_DGRAM;
args.fh = (nfsv2fh_t *)ndmntp->ndm_fh;
args.hostname = ndmntp->ndm_host;
+ args.flags |= NFSMNT_RESVPORT;
/* Get mbuf for server sockaddr. */
MGET(m, MT_SONAME, M_DONTWAIT);
[2] ifa_ifwithaddr uses bcmp to compare two sockaddrs to see
if they are equal. So, if you allocate a sockaddr_in
you need to zero it or the bcmp will fail. The following
code from netinet/in_pcb.c is what generates EADDRNOTAVAIL
for the bind() system call.
if (sin->sin_addr.s_addr != INADDR_ANY) {
sin->sin_port = 0; /* yech... */
if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
return (EADDRNOTAVAIL);
}
In nfs/nfs_boot.c there is code to bring up the ethernet
interface that you booted off of to mount the root file
system. It sets the interface address with a sockaddr_in
but doesn't zero it (causing ifa_ifwithaddr to always fail).
*** 1.1 1994/08/03 21:06:02
--- nfs_boot.c 1994/08/03 20:55:20
***************
*** 160,165 ****
--- 160,166 ----
*/
/* Set interface address. */
sin = (struct sockaddr_in *)&ireq.ifr_addr;
+ bzero(sin, sizeof(*sin)); /* must be zeroed for ifa_ifwithaddr! */
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = my_ip.s_addr;
>Audit-Trail:
>Unformatted:
------------------------------------------------------------------------------