| // 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) |
| } |
| } |