Subject: kern/1664: kernel panic in rip_usrreq
To: None <gnats-bugs@gnats.netbsd.org>
From: David Maltz <dmaltz@orval.mach.cs.cmu.edu>
List: netbsd-bugs
Date: 10/20/1995 18:29:31
>Number: 1664
>Category: kern
>Synopsis: unhandled case in rip_usrreq results in repeatable panic
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people (Kernel Bug People)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Oct 20 18:50:04 1995
>Last-Modified:
>Originator: David Maltz
>Organization:
CMU CSD
>Release: NetBSD-current 8/12/95
>Environment:
System: NetBSD orval.mach.cs.cmu.edu 1.0A NetBSD 1.0A (ORVAL) #0: Sun Aug 27 14:52:06 EDT 1995 dmaltz@orval.mach.cs.cmu.edu:/usr/src/sys/arch/i386/compile/ORVAL i386
>Description:
any ioctl on an AF_INET SOCK_RAW results in a kernel panic in
rip_usrreq.
see netinet/raw_ip.c:
/*ARGSUSED*/
int
rip_usrreq(so, req, m, nam, control)
register struct socket *so;
int req;
struct mbuf *m, *nam, *control;
{
register int error = 0;
register struct inpcb *inp = sotoinpcb(so);
#ifdef MROUTING
extern struct socket *ip_mrouter;
#endif
switch (req) {
case PRU_ATTACH:
.
.
default:
panic("rip_usrreq");
}
case PRU_CONTROL is not caught.
>How-To-Repeat:
su to root and run the following code:
/* crash.c
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#ifndef _net_if_h
#define _net_if_h
/* C and bad header file writers suck */
#include <net/if.h>
#endif
char *ifname = "ep0";
int main()
{
int s;
struct ifreq ifreq;
struct in_addr addr;
s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (s < 0)
perror("couldn't open raw socket to advert with");
strcpy(ifreq.ifr_name, ifname);
if (ioctl(s, SIOCGIFADDR, &ifreq) < 0)
perror("couldn't find address (SIOCGIFADDR)");
if (ifreq.ifr_addr.sa_family != AF_INET)
perror("dfu: SIOCGIFADDR didn't return an inet addr\n");
if ( 0 > bind(s, &ifreq.ifr_addr, ifreq.ifr_addr.sa_len))
perror("wired: binding failed");
return 1;
}
>Fix:
I am only a budding kernel hacker, so take this suggestion with a
grain of salt. I have not tried it, never mind testing it.
At least add to the switch stmt in rip_usrreq
case PRU_CONTROL:
error = EINVAL;
break;
to avoid the panic.
Or handle it properly and adapt code from netinet/udp_usrreq.c
if (req == PRU_CONTROL)
return (in_control(so, (long)m, (caddr_t)addr,
(struct ifnet *)control));
(Why is the if stmt broken out of the large switch anyway? add req !=
PRU_CONTROL to the if (inp == NULL ...) test and fold the PRU_CONTROL
case back into the switch.)
>Audit-Trail:
>Unformatted: