Subject: Re: kern/36548: Trailing NULs written to files over NFS
To: None <gnats-bugs@netbsd.org>
From: Steve Woodford <scw@netbsd.org>
List: netbsd-bugs
Date: 06/24/2007 17:10:11
--Boundary-00=_jdpfGaNAnRLmwD6
Content-Type: text/plain;
  charset="iso-8859-1"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline


> Interestingly, it's the data from the final call to write(2) which is
> being replaced by the NUL bytes. Immediately after the write(2), the
> process invokes exit(2). The file size is correct.

It's actually a bit more subtle than this, as shown by the annotated 
kdump(1) output, attached.

Process creates a file and writes some stuff to it. It does not close 
the file descriptor.

Process then forks and execs /bin/cat to append some more data to the 
same file.

Process waits for /bin/cat to exit, then writes some more data to the 
file. It is the data from these two write(2) calls which end up being 
NUL bytes in the file.

Cheers, Steve

--Boundary-00=_jdpfGaNAnRLmwD6
Content-Type: text/plain;
  charset="iso-8859-1";
  name="nfs-corruption"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
	filename="nfs-corruption"


pid 363 opens/creates .tools_makevars.mk

   363      1 sh       CALL  open(0x3428c,0x601,0x1b6)
   363      1 sh       NAMI  "/export/netbsd/pkgsrc-current/pkgtools/digest/work/.tools_makevars.mk"
   363      1 sh       RET   open 1
   363      1 sh       CALL  break(0x37000)
   363      1 sh       RET   break 0

Starts writing to it
   363      1 sh       CALL  write(1,0x35400,0x1b)
   363      1 sh       GIO   fd 1 wrote 27 bytes
       ".if !defined(_MAKEVARS_MK)
       "
   363      1 sh       RET   write 27/0x1b
   363      1 sh       CALL  write(1,0x35400,0x16)
   363      1 sh       GIO   fd 1 wrote 22 bytes
       "_MAKEVARS_MK=	defined
       "
   363      1 sh       RET   write 22/0x16
   363      1 sh       CALL  write(1,0x35400,1)
   363      1 sh       GIO   fd 1 wrote 1 bytes
       "
       "
   363      1 sh       RET   write 1

Hmm, now it forks...
   363      1 sh       CALL  __vfork14
   366      1 sh       EMUL  "netbsd"
   366      1 sh       RET   fork 0

And exec(2)s /bin/cat
   366      1 sh       CALL  execve(0x342dc,0x3434c,0x3435c)
   366      1 sh       NAMI  "/bin/cat"
   366      1 sh       NAMI  "/libexec/ld.elf_so"
   366      1 cat      EMUL  "netbsd"
   366      1 cat      RET   execve JUSTRETURN
   363      1 sh       RET   __vfork14 366/0x16e
   363      1 sh       CALL  getpgrp
   363      1 sh       RET   getpgrp 98/0x62
   363      1 sh       CALL  wait4(0xffffffff,0xbfffe388,0,0)
   366      1 cat      CALL  mmap(0,0x8000,3,0x1002,0xffffffff,0,0,0)
   366      1 cat      RET   mmap 537202688/0x20051000
   366      1 cat      CALL  open(0x20040570,0,0x20050590)
   366      1 cat      NAMI  "/etc/ld.so.conf"
   366      1 cat      RET   open -1 errno 2 No such file or directory
   366      1 cat      CALL  open(0xbfffe264,0,0x20053000)
   366      1 cat      NAMI  "/lib/libc.so.12"
   366      1 cat      RET   open 3
   366      1 cat      CALL  __fstat30(3,0xbfffe1cc)
   366      1 cat      RET   __fstat30 0
   366      1 cat      CALL  mmap(0,0x1000,1,1,3,0,0,0)
   366      1 cat      RET   mmap 536940544/0x20011000
   366      1 cat      CALL  munmap(0x20011000,0x1000)
   366      1 cat      RET   munmap 0
   366      1 cat      CALL  mmap(0,0xfa000,5,0xf000002,3,0,0,0)
   366      1 cat      RET   mmap 537264128/0x20060000
   366      1 cat      CALL  mmap(0x20143000,0x7000,3,0x12,3,0,0,0xdb000)
   366      1 cat      RET   mmap 538193920/0x20143000
   366      1 cat      CALL  mmap(0x2014a000,0x10000,3,0x1012,0xffffffff,0,0,0)
   366      1 cat      RET   mmap 538222592/0x2014a000
   366      1 cat      CALL  mprotect(0x2013c000,0x7000,0)
   366      1 cat      RET   mprotect 0
   366      1 cat      CALL  close(3)
   366      1 cat      RET   close 0
   366      1 cat      CALL  __sysctl(0xbfffe8d4,2,0x201518fc,0xbfffe8dc,0,0)
   366      1 cat      RET   __sysctl 0
   366      1 cat      CALL  issetugid
   366      1 cat      RET   issetugid 0
   366      1 cat      CALL  open(0xbfffea75,0,0)
   366      1 cat      NAMI  "/export/netbsd/pkgsrc-current/pkgtools/digest/work/.tools_makevars.mk.tmp"
   366      1 cat      RET   open 3
   366      1 cat      CALL  __fstat30(1,0xbfffe804)
   366      1 cat      RET   __fstat30 0
   366      1 cat      CALL  __sysctl(0xbfffe688,2,0xbfffe6e0,0xbfffe6e4,0,0)
   366      1 cat      RET   __sysctl 0
   366      1 cat      CALL  readlink(0x20136c64,0xbfffe743,0x3f)
   366      1 cat      NAMI  "/etc/malloc.conf"
   366      1 cat      RET   readlink -1 errno 2 No such file or directory
   366      1 cat      CALL  mmap(0,0x1000,3,0x1002,0xffffffff,0,0,0)
   366      1 cat      RET   mmap 536940544/0x20011000
   366      1 cat      CALL  break(0x12128)
   366      1 cat      RET   break 0
   366      1 cat      CALL  break(0x13128)
   366      1 cat      RET   break 0
   366      1 cat      CALL  break(0x14000)
   366      1 cat      RET   break 0
   366      1 cat      CALL  break(0x16000)
   366      1 cat      RET   break 0
   366      1 cat      CALL  read(3,0x14000,0x2000)
   366      1 cat      GIO   fd 3 read 718 bytes
       "_BLNK_PHYSICAL_PATH.LOCALBASE=	/usr/pkg
	_BLNK_PHYSICAL_PATH.WRKDIR=	/export/netbsd/pkgsrc-current/pkgtools\
	/digest/work
	_IGNORE_INFO_PATH=	
	_MANCOMPRESSED=	no
	_MANZ=	no
	_USE_TOOLS=	[ awk basename cat chgrp chmod chown cmp cp cut date d\
	iff dirname echo egrep env expr false file find grep head hostname id \
	install ln ls mkdir mv pax printf pwd rm rmdir sed sh sort tail test t\
	ouch tr true uname wc xargs
	_WRAP_PATH=	/export/netbsd/pkgsrc-current/pkgtools/digest/work/.bu\
	ildlink/bin:/export/netbsd/pkgsrc-current/pkgtools/digest/work/.gcc/bi\
	n:/export/netbsd/pkgsrc-current/pkgtools/digest/work/.tools/bin:/usr/p\
	kg/bin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/pkg/sbin:/usr/pkg/bin:/usr/X\
	11R6/bin:/usr/local/sbin:/usr/local/bin
       "
   366      1 cat      RET   read 718/0x2ce


/bin/cat now appends to the file first written to by PID 363, above:
   366      1 cat      CALL  write(1,0x14000,0x2ce)
   366      1 cat      GIO   fd 1 wrote 718 bytes
       "_BLNK_PHYSICAL_PATH.LOCALBASE=	/usr/pkg
	_BLNK_PHYSICAL_PATH.WRKDIR=	/export/netbsd/pkgsrc-current/pkgtools\
	/digest/work
	_IGNORE_INFO_PATH=	
	_MANCOMPRESSED=	no
	_MANZ=	no
	_USE_TOOLS=	[ awk basename cat chgrp chmod chown cmp cp cut date d\
	iff dirname echo egrep env expr false file find grep head hostname id \
	install ln ls mkdir mv pax printf pwd rm rmdir sed sh sort tail test t\
	ouch tr true uname wc xargs
	_WRAP_PATH=	/export/netbsd/pkgsrc-current/pkgtools/digest/work/.bu\
	ildlink/bin:/export/netbsd/pkgsrc-current/pkgtools/digest/work/.gcc/bi\
	n:/export/netbsd/pkgsrc-current/pkgtools/digest/work/.tools/bin:/usr/p\
	kg/bin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/pkg/sbin:/usr/pkg/bin:/usr/X\
	11R6/bin:/usr/local/sbin:/usr/local/bin
       "
   366      1 cat      RET   write 718/0x2ce
   366      1 cat      CALL  read(3,0x14000,0x2000)
   366      1 cat      GIO   fd 3 read 0 bytes
       ""
   366      1 cat      RET   read 0
   366      1 cat      CALL  close(3)
   366      1 cat      RET   close 0
   366      1 cat      CALL  close(1)
   366      1 cat      RET   close 0

/bin/cat is done
   366      1 cat      CALL  exit(0)


PID 363 now writes some more to the file. The data from both these write(2)
calls are written as NUL.
   363      1 sh       RET   wait4 366/0x16e
   363      1 sh       CALL  write(1,0x35400,1)
   363      1 sh       GIO   fd 1 wrote 1 bytes
       "
       "
   363      1 sh       RET   write 1
   363      1 sh       CALL  write(1,0x35400,0x16)
   363      1 sh       GIO   fd 1 wrote 22 bytes
       ".endif # _MAKEVARS_MK
       "
   363      1 sh       RET   write 22/0x16
   363      1 sh       CALL  exit(0)


--Boundary-00=_jdpfGaNAnRLmwD6--