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: