aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/build/freebsd.go
blob: 4b403d5879ea86abcc121a12ad8247641f507b1f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2019 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.

package build

import (
	"fmt"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/google/syzkaller/pkg/osutil"
)

type freebsd struct{}

func (ctx freebsd) build(params Params) (ImageDetails, error) {
	confDir := fmt.Sprintf("%v/sys/%v/conf/", params.KernelDir, params.TargetArch)
	confFile := "SYZKALLER"

	config := params.Config
	if config == nil {
		config = []byte(`
include "./GENERIC"

ident		SYZKALLER
options 	COVERAGE
options 	KCOV
options 	KASAN

options 	TCPHPTS
options 	RATELIMIT

options 	DEBUG_VFS_LOCKS
options 	DIAGNOSTIC
`)
	}
	if err := osutil.WriteFile(filepath.Join(confDir, confFile), config); err != nil {
		return ImageDetails{}, err
	}

	if _, err := osutil.RunCmd(10*time.Minute, params.KernelDir, "rm", "-rf", "obj"); err != nil {
		return ImageDetails{}, err
	}
	objPrefix := filepath.Join(params.KernelDir, "obj")
	output, err := ctx.make(params.KernelDir, objPrefix, params.BuildCPUs, "kernel-toolchain")
	if err != nil {
		return ImageDetails{}, err
	}
	if _, err := ctx.make(params.KernelDir, objPrefix, params.BuildCPUs, "buildkernel",
		"WITH_EXTRA_TCP_STACKS=", fmt.Sprintf("KERNCONF=%v", confFile)); err != nil {
		// The kernel-toolchain make target has to be built separately
		// because FreeBSD's build doesn't correctly order the two
		// targets. Its output is useful for debugging though, so
		// include it here.
		return ImageDetails{}, fmt.Errorf("%s: %w", string(output), err)
	}

	kernelObjDir := filepath.Join(objPrefix, params.KernelDir,
		fmt.Sprintf("%v.%v", params.TargetArch, params.TargetArch), "sys", confFile)
	for _, s := range []struct{ dir, src, dst string }{
		{params.UserspaceDir, "image", "image"},
		{params.UserspaceDir, "key", "key"},
		{kernelObjDir, "kernel.full", "obj/kernel.full"},
	} {
		fullSrc := filepath.Join(s.dir, s.src)
		fullDst := filepath.Join(params.OutputDir, s.dst)
		if err := osutil.CopyFile(fullSrc, fullDst); err != nil {
			return ImageDetails{}, fmt.Errorf("failed to copy %v -> %v: %w", fullSrc, fullDst, err)
		}
	}

	script := fmt.Sprintf(`
set -eux
md=$(sudo mdconfig -a -t vnode image)
partn=$(gpart show /dev/${md} | awk '/freebsd-ufs/{print $3}' | head -n 1)
tmpdir=$(mktemp -d)
sudo mount /dev/${md}p${partn} $tmpdir

sudo MAKEOBJDIRPREFIX=%s make -C %s installkernel WITH_EXTRA_TCP_STACKS= KERNCONF=%s DESTDIR=$tmpdir

cat | sudo tee ${tmpdir}/boot/loader.conf.local <<__EOF__
ipsec_load="YES"
pf_load="YES"
sctp_load="YES"
tcp_bbr_load="YES"
tcp_rack_load="YES"
sem_load="YES"
mqueuefs_load="YES"
cryptodev_load="YES"
cc_cdg_load="YES"
cc_chd_load="YES"
cc_cubic_load="YES"
cc_dctcp_load="YES"
cc_hd_load="YES"
cc_htcp_load="YES"
cc_vegas_load="YES"
filemon_load="YES"

kern.ipc.tls.enable="1"
vm.panic_on_oom="1"
__EOF__

cat | sudo tee -a ${tmpdir}/etc/sysctl.conf <<__EOF__
net.inet.sctp.udp_tunneling_port=9899
net.inet.tcp.udp_tunneling_port=9811
net.inet.tcp.bb.log_auto_all=1
net.inet.tcp.bb.log_auto_ratio=1
net.inet.tcp.bb.log_auto_mode=1
vm.redzone.panic=1
__EOF__

sudo umount $tmpdir
sudo mdconfig -d -u ${md#md}
`, objPrefix, params.KernelDir, confFile)

	if debugOut, err := osutil.RunCmd(10*time.Minute, params.OutputDir, "/bin/sh", "-c", script); err != nil {
		return ImageDetails{}, fmt.Errorf("error copying kernel: %w\n%v", err, debugOut)
	}
	return ImageDetails{}, nil
}

func (ctx freebsd) clean(params Params) error {
	objPrefix := filepath.Join(params.KernelDir, "obj")
	_, err := ctx.make(params.KernelDir, objPrefix, params.BuildCPUs, "cleanworld")
	return err
}

func (ctx freebsd) make(kernelDir, objPrefix string, jobs int, makeArgs ...string) ([]byte, error) {
	args := append([]string{
		fmt.Sprintf("MAKEOBJDIRPREFIX=%v", objPrefix),
		"make",
		"-C", kernelDir,
		"-j", strconv.Itoa(jobs),
	}, makeArgs...)
	output, err := osutil.RunCmd(3*time.Hour, kernelDir, "sh", "-c", strings.Join(args, " "))
	return output, err
}