Subject: kern/13516: sys/lib/libsa/read.c fails with elf files on raw devices
To: None <gnats-bugs@gnats.netbsd.org>
From: David Querbach <querbach@realtime.bc.ca>
List: netbsd-bugs
Date: 07/19/2001 19:37:06
>Number:         13516
>Category:       kern
>Synopsis:       libsa read() fails with elf files on raw devices
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jul 19 19:34:00 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator:     David Querbach
>Release:        current-20010719
>Organization:
Real-Time Systems Inc.
	
>Environment:
System: NetBSD qingdao 1.5.1 NetBSD 1.5.1 (RAID) #0: Tue Jul 17 22:25:40 PDT 2001 root@qingdao:/usr/src/sys/arch/i386/compile/RAID i386


>Description:
	The function exec_elf() in sys/lib/libsa/loadfile.c issues small
	reads, some of which have starting offsets not divisible by the disk
	block size DEV_BSIZE.  If the boot device was opened in F_RAW mode
	(as for an in() in-kernel image), these read requests are passed
	directly to the function read() in sys/lib/libsa/read.c.

	The function read() then rounds the offsets to a multiple of
	DEV_BSIZE, which causes garbage to be returned to exec_elf, which
	then chokes on it.
>How-To-Repeat:
	Build a standalone which returns a NULL filename from devopen,
	indicating that the device is a raw device.  
>Fix:
	Add deblocking code to detect offsets not divisible by DEV_BSIZE,
	and fetch the enclosing block into a local buffer, then satisfy the
	read from this local buffer.

	Apply this patch to sys/lib/libsa/read.c:

Index: read.c
===================================================================
RCS file: /cvsroot/syssrc/sys/lib/libsa/read.c,v
retrieving revision 1.10
diff -c -r1.10 read.c
*** read.c	2000/03/30 12:19:48	1.10
--- read.c	2001/07/20 02:35:36
***************
*** 88,102 ****
  #endif
  #if !defined(LIBSA_NO_RAW_ACCESS)
  	if (f->f_flags & F_RAW) {
  #if !defined(LIBSA_NO_TWIDDLE)
  		twiddle();
  #endif
! 		errno = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ,
! 			btodb(f->f_offset), bcount, dest, &resid);
! 		if (errno)
! 			return (-1);
! 		f->f_offset += resid;
! 		return (resid);
  	}
  #endif
  	resid = bcount;
--- 88,129 ----
  #endif
  #if !defined(LIBSA_NO_RAW_ACCESS)
  	if (f->f_flags & F_RAW) {
+ 		char *dst;
+ 				
  #if !defined(LIBSA_NO_TWIDDLE)
  		twiddle();
  #endif
! 		dst = (char *)dest;
! 		while (bcount) {
! 			size_t blk, off, rem, cnt, res;
! 
! 			blk = btodb(f->f_offset);
! 			off = f->f_offset - dbtob(blk);
! 			rem = DEV_BSIZE - off;
! 			cnt = (bcount < rem) ? bcount : rem;
! 
! 			if (off == 0 && cnt == DEV_BSIZE) {
! 				errno = DEV_STRATEGY(f->f_dev)(f->f_devdata, 
! 				    F_READ, blk, DEV_BSIZE, dst, &res);
! 				if (errno)
! 					return (-1);
! 			}
! 			else {
! 				char buf[DEV_BSIZE];
! 
! 				errno = DEV_STRATEGY(f->f_dev)(f->f_devdata, 
! 				    F_READ, blk, DEV_BSIZE, buf, &res);
! 				if (errno)
! 					return (-1);
! 				memcpy(dst, buf + off, cnt);
! 			}
! 
! 			cnt = (res < cnt) ? res : cnt;
! 			f->f_offset += cnt;
! 			dst += cnt;
! 			bcount -= cnt;
! 		}
! 		return (dst - (char*)dest);
  	}
  #endif
  	resid = bcount;
>Release-Note:
>Audit-Trail:
>Unformatted: