From nobody@FreeBSD.org  Fri Mar 23 10:57:35 2001
Return-Path: <nobody@FreeBSD.org>
Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21])
	by hub.freebsd.org (Postfix) with ESMTP id B1E9037B719
	for <freebsd-gnats-submit@FreeBSD.org>; Fri, 23 Mar 2001 10:57:34 -0800 (PST)
	(envelope-from nobody@FreeBSD.org)
Received: (from nobody@localhost)
	by freefall.freebsd.org (8.11.1/8.11.1) id f2NIvY209246;
	Fri, 23 Mar 2001 10:57:34 -0800 (PST)
	(envelope-from nobody)
Message-Id: <200103231857.f2NIvY209246@freefall.freebsd.org>
Date: Fri, 23 Mar 2001 10:57:34 -0800 (PST)
From: jtrainor@fastekintl.com
To: freebsd-gnats-submit@FreeBSD.org
Subject: kldload() panics if error code is returned from <module_name>_load().
X-Send-Pr-Version: www-1.0

>Number:         26034
>Category:       kern
>Synopsis:       kldload() panics if error code is returned from <module_name>_load().
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri Mar 23 11:00:03 PST 2001
>Closed-Date:    Sat Apr 28 19:27:16 PDT 2001
>Last-Modified:  Sat Apr 28 19:27:36 PDT 2001
>Originator:     Jim Trainor
>Release:        FreeBSD 4.2-RELEASE #0: 11/20/2000
>Organization:
Fastek International Ltd.
>Environment:
FreeBSD BSDDEV.fastekintl.com 4.2-RELEASE FreeBSD 4.2-RELEASE #0: Mon Nov 20 13:02:55 GMT 2000     jkh@bento.FreeBSD.org:/usr/src/sys/compile/GENERIC  i386

>Description:
panic trap 12 (page fault) in kldload while attempting to return an error from <module_name>_load.  If I set the return value prior to entering the case statement, proper behavior is observed.  If I set the return value inside the case statement, panic occurs.  See code below.
>How-To-Repeat:
/* =============================================================== */
/* Program..... KLD Character Device Implementation Skeleton       */
/* Version..... 1.0                                                */
/* File........ CDEVEXAM.C                                         */
/* Date........ 03/04/2001                                         */
/* Programmer.. Jim Trainor                                        */
/* Copyright (c)2001 Fastek International Ltd.                     */
/* --------------------------------------------------------------- */
/* */
/* --------------------------------------------------------------- */
/* This code is from the article "Dynamic Kernel Linker (KLD)      */
/* Facility Programming Tutorial" by Andrew Reiter.  The article   */
/* was in "daemonnews" October 2000.                               */
/* The module is loaded with "kldload ./cdev_exam.ko"              */
/* --------------------------------------------------------------- */
/* $Header$                                                        */
/* --------------------------------------------------------------- */
/* <revision comments in the form>                                 */
/* mm/dd/yyyy - pid - comment                                      */
/* =============================================================== */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/uio.h>
#include <sys/conf.h>	/* for macro DEV_MODULE */

/* --------------------------------------------------------------- */
/* Device access function declarations                             */
/* --------------------------------------------------------------- */
int example_open(dev_t dev, int oflags, int devtype, struct proc *p);
int example_close(dev_t dev, int fflag, int devtype, struct proc *p);
int example_read(dev_t dev, struct uio *uio, int ioflag);
int example_write(dev_t dev, struct uio *uio, int ioflag);

/* --------------------------------------------------------------- */
/* Define global variables.                                        */
/* --------------------------------------------------------------- */
/* Stores string recv'd by _write() */
static char buf[512+1];
static int len;

/* 
 * Used as the variable that is the reference to our device
 * in devfs... we must keep this variable sane until we 
 * call kldunload.
 */
  
static dev_t sdev;

/* --------------------------------------------------------------- */
/* File operations supported by our device driver                  */
/* --------------------------------------------------------------- */
static struct cdevsw example_cdevsw = 
{
	example_open,
	example_close,
	example_read,
	example_write,
	noioctl,
	nopoll,
	nommap,
	nostrategy,
	"example",
	34,			/* /usr/src/sys/conf/majors */		
	nodump,
	nopsize,
	D_TTY,
	-1
};

/* --------------------------------------------------------------- */
/* chardev_example_load()                                          */
/*                                                                 */
/* This is used as the function that handles what is to occur      */
/* when the KLD binary is loaded and unloaded via the kldload      */
/* and kldunload programs.                                         */
/* --------------------------------------------------------------- */
static int
chardev_example_load(struct module *m, int what, void *arg)
{
	int err = 0;
  
    /* Test load failure case 1 - before case */
/*	err = EINVAL; */

	if(!err)
	{
		switch (what) 
		{
		case MOD_LOAD:					/* kldload */
			/* Test load failure case 2 - inside case */
			err = EINVAL;
			if(!err)
			{
				sdev = make_dev(&example_cdevsw,	/* explained below */
					0,
					UID_ROOT,
					GID_WHEEL,
					0600,
					"example");
				printf("Example device loaded.\n");
			}
		break;
		case MOD_UNLOAD:
			destroy_dev(sdev);			/* explained below */
			printf("Example device unloaded.\n");
		break;
		default:
			err = EINVAL;
		break;
		}
	}
	return(err);
}

/* --------------------------------------------------------------- */
/* example_open()                                                  */
/*                                                                 */
/* This open function solely checks for open(2) flags. We are only */
/* allowing for the flags to be O_RDWR for the purpose of showing  */
/* how one could only allow a read-only device, for example.       */
/* --------------------------------------------------------------- */
int example_open(dev_t dev, int oflags, int devtype, struct proc *p)
{
	int err = 0;

	memset(&buf, '\0', 513);
	len = 0;
	uprintf("Opened device \"example\" successfully.\n");
	return(err);
}

/* --------------------------------------------------------------- */
/* example_close()                                                 */
/*                                                                 */
/* Simply "closes" our device that was opened with example_open.   */
/* --------------------------------------------------------------- */
int example_close(dev_t dev, int fflag, int devtype, struct proc *p)
{
	memset(&buf, '\0', 513);
	len = 0;
	uprintf("Closing device \"example.\"\n"); 
	return(0);
} 

/* --------------------------------------------------------------- */
/* example_write()                                                 */
/*                                                                 */
/* The read function just takes the buf that was saved             */
/* via example_write() and returns it to userland for              */
/* accessing.                                                      */
/* --------------------------------------------------------------- */
int example_read(dev_t dev, struct uio *uio, int ioflag)
{
	int err = 0;

	if (len <= 0)
	{
		err = -1; 
	}
	else
	{/* copy buf to userland */
		err = copystr(&buf, uio->uio_iov->iov_base, 513, &len);
	}
	return(err);
}

/* --------------------------------------------------------------- */
/* example_write()                                                 */
/*                                                                 */
/* example_write takes in a character string and saves it to buf   */        
/* for later accessing.                                            */
/* --------------------------------------------------------------- */
int example_write(dev_t dev, struct uio *uio, int ioflag)
{
	int err = 0;

	err = copyinstr(uio->uio_iov->iov_base, &buf, 512, &len);
	if (err != 0)
	{
		uprintf("Write to \"example\" failed.\n");
	}
	return(err);
}

DEV_MODULE(chardev_example, chardev_example_load, NULL);


>Fix:

>Release-Note:
>Audit-Trail:

From: Peter Wemm <peter@netplex.com.au>
To: jtrainor@fastekintl.com
Cc: freebsd-gnats-submit@FreeBSD.ORG
Subject: Re: kern/26034: kldload() panics if error code is returned from <module_name>_load(). 
Date: Fri, 23 Mar 2001 13:50:52 -0800

 jtrainor@fastekintl.com wrote:
 > 
 > >Number:         26034
 > >Category:       kern
 > >Synopsis:       kldload() panics if error code is returned from <module_name
     >_load().
 
 > >Description:
 > panic trap 12 (page fault) in kldload while attempting to return an error fro
     m <module_name>_load.  If I set the return value prior to entering the case
      statement, proper behavior is observed.  If I set the return value inside 
     the case statement, panic occurs.  See code below.
 
 This is because if you fail on the MOD_LOAD case, the linker calls all the
 MOD_UNLOADs for the modules in the kld file.  In your case, you
 are calling "destroy_dev(sdev);" on MOD_UNLOAD, which is panicing since
 sdev is uninitialized.  This is actually a bug in your module due to the
 existing module load/unload semantics.  Remember, there can be more than
 one module inside a .ko kld file.
 
 One could argue that a MOD_UNLOAD event should be skipped for modules that
 have failed to load successfully..  I think this change needs to happen.
 
 Cheers,
 -Peter
 --
 Peter Wemm - peter@FreeBSD.org; peter@yahoo-inc.com; peter@netplex.com.au
 "All of this is for nothing if we don't go to the stars" - JMS/B5
 
State-Changed-From-To: open->closed 
State-Changed-By: dd 
State-Changed-When: Sat Apr 28 19:27:16 PDT 2001 
State-Changed-Why:  
Problem appears to be in the sample code. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=26034 
>Unformatted:
