bin/98005: loader corrupts other files when rewriting nextboot.conf

Yar Tikhiy yar at comp.chem.msu.su
Sat May 27 03:40:27 PDT 2006


>Number:         98005
>Category:       bin
>Synopsis:       loader corrupts other files when rewriting nextboot.conf
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat May 27 10:40:17 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Yar Tikhiy
>Release:        FreeBSD 7.0-CURRENT i386
>Organization:
None
>Environment:
System: FreeBSD  7.0-CURRENT FreeBSD 7.0-CURRENT #1: Thu May 25
19:55:44 UTC 2006     root@:/usr/obj/usr/src/sys/GENERIC  i386

>Description:
	When nextboot is in effect, loader(8) writes the modified
	contents of the nextboot.conf file, or whatever nextboot_conf
	is set to, to an incorrect location on the disk.  The
	location overwritten is in the block after the one actually
	belonging to the nextboot.conf file.

	This problem is likely to be caused by an off-by-one bug in
	the stand-alone FS access library used by loader(8).

>How-To-Repeat:

### Here's an example.  Booting in the following environment:

# cat /boot/loader.conf
beastie_disable="YES"
nextboot_conf="/root/foo"
# cat /root/foo
nextboot_enable="YES"
kernel="${kernel}"
kernel_options="${kernel_options}"

### After the reboot, /boot/kernel/kernel.symbols appears damaged:

# /root/ckroot
378c378
< MD5 (/boot/kernel/kernel.symbols) = 98d1d52fed7985df0712618de7db8e03
---
> MD5 (/boot/kernel/kernel.symbols) = b42770ba4b010e8aed83ca89440ae79b

### Inspecting its contents.  Note the `nextboot_enable="NO" ' string.
### It apparently came from rewrite_nextboot_file in support.4th.

# hd /boot/kernel/kernel.symbols | grep -A8 nextboot_enable
000a0000  6e 65 78 74 62 6f 6f 74  5f 65 6e 61 62 6c 65 3d  |nextboot_enable=|
000a0010  22 4e 4f 22 20 0a 6b 65  72 6e 65 6c 3d 22 24 7b  |"NO" .kernel="${|
000a0020  6b 65 72 6e 65 6c 7d 22  0a 6b 65 72 6e 65 6c 5f  |kernel}".kernel_|
000a0030  6f 70 74 69 6f 6e 73 3d  22 24 7b 6b 65 72 6e 65  |options="${kerne|
000a0040  6c 5f 6f 70 74 69 6f 6e  73 7d 22 0a 00 00 00 00  |l_options}".....|
000a0050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000a0800  00 00 02 23 0c 0a 20 5a  00 00 05 80 30 01 00 00  |...#.. Z....0...|
000a0810  02 23 10 00 1a 4b 0e 00  00 01 4c 00 00 00 19 30  |.#...K....L....0|

### Let's find out the files' inodes:

# ls -if /root/foo /boot/kernel/kernel.symbols
490 /root/foo                    36 /boot/kernel/kernel.symbols

### Let's see how the files' blocks are laid out:

# fsdb -r /dev/ad0s3a
** /dev/ad0s3a (NO WRITE)
Examining file system `/dev/ad0s3a'
Last Mounted on /
current inode: directory
I=2 MODE=40755 SIZE=512
        MTIME=May 25 20:46:43 2006 [0 nsec]
        CTIME=May 25 20:46:43 2006 [0 nsec]
        ATIME=May 27 12:21:18 2006 [0 nsec]
OWNER=root GRP=wheel LINKCNT=20 FLAGS=0 BLKCNT=4 GEN=58ef642f
fsdb (inum: 2)> inode 490
current inode: regular file
I=490 MODE=100644 SIZE=76
        MTIME=May 27 12:15:23 2006 [0 nsec]
        CTIME=May 27 12:15:23 2006 [0 nsec]
        ATIME=May 27 12:21:37 2006 [0 nsec]
OWNER=root GRP=wheel LINKCNT=1 FLAGS=0 BLKCNT=4 GEN=6f069864
fsdb (inum: 490)> blocks
Blocks for inode 490:
Direct blocks:
6551 (1 frag)
fsdb (inum: 490)> inode 36
current inode: regular file
I=36 MODE=100555 SIZE=18022637
        MTIME=May 25 19:55:57 2006 [0 nsec]
        CTIME=May 25 20:22:34 2006 [0 nsec]
        ATIME=May 27 12:21:19 2006 [0 nsec]
OWNER=root GRP=wheel LINKCNT=1 FLAGS=0 BLKCNT=89c0 GEN=3c3ab2a9
fsdb (inum: 36)> blocks
Blocks for inode 36:
Direct blocks:
6104, 6112, 6120, 6128, 6136, 6144, 6152, 6160, 6200, 6208, 6216, 6224
Indirect blocks:
6232, 6240, 6248, 6256, 6264, 6272, 6280, 6288, 6296, 6304, 6312, 6320, 6328,
6336, 6344, 6352, 6360, 6368, 6376, 6384, 6392, 6400, 6408, 6416, 6424, 6432,
6440, 6448, 6552, 6560, 6568, 6576, 6584, 6592, 6600, 6608, 6616, 6624, 6632,
            ^^^^
...

### Note that block 6552 belongs to the damaged file while block 6551
### contains /root/foo, which plays the role of a nextboot_conf file.
### BTW, 6551 is a fragment address.

### Now we need to know the FS parameters to do some easy math.

# dumpfs /dev/ad0s3a | head -20
magic   19540119 (UFS2) time    Sat May 27 12:21:51 2006
superblock location     65536   id      [ 4475a06c d0014a51 ]
ncg     4       size    262144  blocks  253815
bsize   16384   shift   14      mask    0xffffc000
fsize   2048    shift   11      mask    0xfffff800
frag    8       shift   3       fsbtodb 2
minfree 8%      optim   time    symlinklen 120
maxbsize 16384  maxbpg  2048    maxcontig 8     contigsumsize 8
nbfree  20648   ndir    49      nifree  63361   nffree  1229
bpg     8193    fpg     65544   ipg     16448
nindir  2048    inopb   64      maxfilesize     140806241583103
sbsize  2048    cgsize  12288   csaddr  2112    cssize  2048
sblkno  40      cblkno  48      iblkno  56      dblkno  2112
cgrotor 0       fmod    0       ronly   0       clean   1
avgfpdir 64     avgfilesize 16384
flags   none
fsmnt   /
volname         swuid   0
...

### Aha, bsize is 16384.  40 blocks precede block 6552 in the damaged
### file according to fsdb.
### Therefore the file offset of block 6552 is 40*16384 = 0xa0000,
### which is exactly the offset of the damaged part (see above.)

### Let's see the raw disk contents.  Keep in mind that FFS blocks
### are addressed in a funny way.  The "bs" value here isn't bsize,
### but fsize.

# dd bs=2048 iseek=6551 count=2 if=/dev/ad0s3a | hd
00000000  6e 65 78 74 62 6f 6f 74  5f 65 6e 61 62 6c 65 3d  |nextboot_enable=|
00000010  22 59 45 53 22 0a 6b 65  72 6e 65 6c 3d 22 24 7b  |"YES".kernel="${|
00000020  6b 65 72 6e 65 6c 7d 22  0a 6b 65 72 6e 65 6c 5f  |kernel}".kernel_|
00000030  6f 70 74 69 6f 6e 73 3d  22 24 7b 6b 65 72 6e 65  |options="${kerne|
00000040  6c 5f 6f 70 74 69 6f 6e  73 7d 22 0a 00 00 00 00  |l_options}".....|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000800  6e 65 78 74 62 6f 6f 74  5f 65 6e 61 62 6c 65 3d  |nextboot_enable=|
00000810  22 4e 4f 22 20 0a 6b 65  72 6e 65 6c 3d 22 24 7b  |"NO" .kernel="${|
00000820  6b 65 72 6e 65 6c 7d 22  0a 6b 65 72 6e 65 6c 5f  |kernel}".kernel_|
00000830  6f 70 74 69 6f 6e 73 3d  22 24 7b 6b 65 72 6e 65  |options="${kerne|
00000840  6c 5f 6f 70 74 69 6f 6e  73 7d 22 0a 00 00 00 00  |l_options}".....|
00000850  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
2+0 records in
2+0 records out
4096 bytes transferred in 0.011375 secs (360082 bytes/sec)

### We can see clearly that the loader wrote the modified data
### to the 2048-byte fragment following the correct one.

### And of course, the FS metadata aren't damaged:

# fsck -f /
** /dev/ad0s3a
** Last Mounted on /
** Root file system
** Phase 1 - Check Blocks and Sizes
** Phase 2 - Check Pathnames
** Phase 3 - Check Connectivity
** Phase 4 - Check Reference Counts
** Phase 5 - Check Cyl groups
2429 files, 87402 used, 166413 free (1229 frags, 20648 blocks, 0.5% fragmentation)

>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list