// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
// imagegen generates syz_mount_image/syz_read_part_table calls from disk images.
package main
import (
"bytes"
"encoding/hex"
"flag"
"fmt"
"io/ioutil"
"os"
)
type Segment struct {
offset int
data []byte
}
func main() {
flagV := flag.Bool("v", false, "verbose output")
flagImage := flag.String("image", "", "image file")
flagSkip := flag.Int("skip", 32, "min zero bytes to skip")
flagAlign := flag.Int("align", 32, "non-zero block alignment")
flagFS := flag.String("fs", "", "filesystem")
flag.Parse()
data, err := ioutil.ReadFile(*flagImage)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to read input file: %v\n", err)
os.Exit(1)
}
data0 := data
zeros := make([]byte, *flagAlign+*flagSkip)
var segs []Segment
offset := 0
for len(data) != 0 {
pos := bytes.Index(data, zeros)
if pos == -1 {
segs = append(segs, Segment{offset, data})
break
}
pos = (pos + *flagAlign - 1) & ^(*flagAlign - 1)
if pos != 0 {
segs = append(segs, Segment{offset, data[:pos]})
}
for pos < len(data) && data[pos] == 0 {
pos++
}
pos = pos & ^(*flagAlign - 1)
offset += pos
data = data[pos:]
}
totalData := 0
for _, seg := range segs {
totalData += len(seg.data)
}
fmt.Fprintf(os.Stderr, "image size: %v, segments: %v, data: %v\n",
len(data0), len(segs), totalData)
if *flagV {
for i, seg := range segs {
next := len(data0)
if i != len(segs)-1 {
next = segs[i+1].offset
}
skip := next - seg.offset - len(seg.data)
fmt.Fprintf(os.Stderr, "segment: %8v-%8v [%8v] -%8v\n",
seg.offset, seg.offset+len(seg.data), len(seg.data), skip)
}
}
restored := make([]byte, len(data0))
for _, seg := range segs {
copy(restored[seg.offset:], seg.data)
}
if !bytes.Equal(data0, restored) {
fmt.Fprintf(os.Stderr, "restored data differs!\n")
os.Exit(1)
}
if *flagFS == "part" {
fmt.Printf(`syz_read_part_table(0x%x, 0x%x, &(0x7f0000000200)=[`,
len(data0), len(segs))
addr := 0x7f0000010000
for i, seg := range segs {
if i != 0 {
fmt.Printf(", ")
}
fmt.Printf(`{&(0x%x)="%v", 0x%x, 0x%x}`,
addr, hex.EncodeToString(seg.data), len(seg.data), seg.offset)
addr = (addr + len(seg.data) + 0xff) & ^0xff
}
fmt.Printf("])\n")
} else {
syscallSuffix := *flagFS
if syscallSuffix == "ext2" || syscallSuffix == "ext3" {
syscallSuffix = "ext4"
}
fmt.Printf(`syz_mount_image$%v(&(0x7f0000000000)='%v\x00', &(0x7f0000000100)='./file0\x00',`+
` 0x%x, 0x%x, &(0x7f0000000200)=[`,
syscallSuffix, *flagFS, len(data0), len(segs))
addr := 0x7f0000010000
for i, seg := range segs {
if i != 0 {
fmt.Printf(", ")
}
fmt.Printf(`{&(0x%x)="%v", 0x%x, 0x%x}`,
addr, hex.EncodeToString(seg.data), len(seg.data), seg.offset)
addr = (addr + len(seg.data) + 0xff) & ^0xff
}
fmt.Printf("], 0x0, &(0x%x))\n", addr)
}
}