├── LICENSE ├── README.md ├── config └── example.KConfig ├── easylkb.py └── kernel └── create-image.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 deepseagirl 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easylkb - Easy Linux Kernel Builder 2 | 3 | easylkb is a simple script designed to make Linux Kernel Debugging easier and more accessible. 4 | 5 | this project was originally released in tmp.0ut volume 3: https://tmpout.sh/3/20.html 6 | 7 | this article is a good introduction to this tool: https://hackaday.com/2023/11/22/linux-fu-easy-kernel-debugging/ 8 | 9 | ## How do you install easylkb? 10 | 11 | easylkb is best run on a bare metal Linux system. You need the following things installed in order to use it: 12 | 13 | - python3 14 | - curl 15 | - gcc 16 | - make 17 | - qemu 18 | - debootstrap 19 | 20 | Install all prerequisites on Debian/Ubuntu 21 | 22 | ``` 23 | sudo apt update 24 | sudo apt install make gcc flex bison libncurses-dev libelf-dev libssl-dev debootstrap 25 | ``` 26 | 27 | You can clone this repo and run from the easylkb directory, or you can install with pip (not yet lol). 28 | 29 | ``` 30 | pip install easylkb 31 | ``` 32 | 33 | ## How do you use easylkb? 34 | 35 | Build a specific mainline kernel version: 36 | 37 | ``` 38 | easylkb -k 6.2 39 | ``` 40 | 41 | Build some other kernel in a directory: 42 | ``` 43 | easylkb -p path/to/linux/ 44 | ``` 45 | 46 | Command line flags are tied to specific parts of the build process. 47 | 48 | To (d)ownload, (c)onfigure, and co(m)pile a kernel 49 | ``` 50 | easylkb -k 6.2 -dcm 51 | ``` 52 | 53 | To build a Debian (i)mage from this kernel 54 | ``` 55 | easylkb -k 6.2 -i 56 | ``` 57 | 58 | To (r)un the generated image: 59 | ``` 60 | easylkb -k 6.2 -r 61 | ``` 62 | 63 | Combine all of these steps into one: 64 | ``` 65 | easylkb -k 6.2 -a 66 | ``` 67 | 68 | When it's running, it will run qemu with the Debian image and expose ssh and GDB debugging features accessible via localhost. 69 | 70 | ## How Do I Interact With The Image? 71 | 72 | The image, keys, and run script are stored in the img/ directory within the kernel source. 73 | 74 | You can ssh into your image like so: 75 | ``` 76 | ssh root@localhost -p 10021 -i ~/kernel/linux-6.2/img/bullseye.id_rsa 77 | ``` 78 | 79 | The default login for the resulting image is the user "root" with no password. 80 | 81 | This is an example ssh config entry for the resulting image, which you can add to your `~/.ssh/config` file. 82 | ``` 83 | Host linux62 84 | HostName localhost 85 | User root 86 | Port 10021 87 | IdentityFile ~/kernel/linux-6.2/img/bullseye.id_rsa 88 | StrictHostKeyChecking no 89 | ``` 90 | 91 | Now you can ssh into your kernel by doing: 92 | ``` 93 | ssh linux62 94 | ``` 95 | 96 | You can scp files by doing 97 | ``` 98 | scp myfile.bin linux62: 99 | ``` 100 | 101 | ## Kernel Debugging 102 | 103 | To debug the kernel, you need `$KERNEL_DIR/scripts/gdb/vmlinux-gdb.py` 104 | 105 | Add this to your `~/.gdbinit` file if you want to debug this kernel, changing the path to the kernel source you're working with. 106 | ``` 107 | add-auto-load-safe-path /home/user/kernel/linux-6.2/scripts/gdb/vmlinux-gdb.py 108 | ``` 109 | 110 | Now to debug just do 111 | ``` 112 | cd /path/to/your/kernel/ 113 | gdb ./vmlinux 114 | ``` 115 | Once you're in gdb just do this: 116 | ``` 117 | (gdb) lx-symbols 118 | (gdb) target remote :1234 119 | ``` 120 | Wow! You're debugging the kernel you just built, pretty neat. 121 | 122 | For more info on kernel debugging with gdb: 123 | - https://docs.kernel.org/dev-tools/gdb-kernel-debugging.html 124 | 125 | ## Known Issues 126 | 127 | because this is a generic tool, there may be some instances where the example kernel config doesn't work for your kernel version. 128 | 129 | here are some documented fixes: 130 | - https://github.com/deepseagirl/easylkb/issues/4 Add `DEBUG_INFO_DWARF5` to config for kernel version 6.8 or newer 131 | 132 | -------------------------------------------------------------------------------- /config/example.KConfig: -------------------------------------------------------------------------------- 1 | CONFIG_CONFIGFS_FS=y 2 | CONFIG_DEBUG_FS=y 3 | CONFIG_DEBUG_INFO=y 4 | CONFIG_DEBUG_KMEMLEAK=y 5 | CONFIG_KASAN=y 6 | CONFIG_KASAN_INLINE=y 7 | CONFIG_KCOV=y 8 | CONFIG_KCOV_ENABLE_COMPARISONS=y 9 | CONFIG_KCOV_INSTRUMENT_ALL=y 10 | CONFIG_SECURITYFS=y 11 | CONFIG_SLAB_DEBUG=y 12 | CONFIG_USER_NS=y 13 | CONFIG_FRAME_POINTER=y 14 | CONFIG_DEBUG_KERNEL=y 15 | CONFIG_GDB_SCRIPTS=y 16 | -------------------------------------------------------------------------------- /easylkb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import subprocess 5 | import re 6 | import os 7 | import sys 8 | 9 | class Kbuilder: 10 | def __init__(self, KConfig=None, KPath=None, KVersion="", KHostname="localhost"): 11 | self.BaseDir = os.getcwd() + "/" 12 | self.LogDir = self.BaseDir + "log/" 13 | self.KVersion = KVersion # The kernel version 14 | if KConfig is not None: 15 | self.KConfig = KConfig 16 | else: 17 | self.KConfig="config/example.KConfig" # Default KConfig location 18 | if KPath is not None: 19 | self.KPath = KPath 20 | else: 21 | self.KPath = f"{self.BaseDir}kernel/linux-{KVersion}/" # Path to this kernel 22 | self.ImgPath = self.KPath + "img/" 23 | self.KHostname = KHostname 24 | self.isDownloaded = False # Is the tarball downloaded? 25 | self.isExtracted = False # Is the tarball extracted? 26 | self.nproc = int(subprocess.run(["nproc"], capture_output=True).stdout.decode("utf-8").split("\n")[0]) 27 | self.runkPath = self.ImgPath + "runk.sh" 28 | self.runkScript = "#!/usr/bin/env bash\n" 29 | self.runkScript += f"qemu-system-x86_64" 30 | self.runkScript += f" -m 2G" 31 | self.runkScript += f" -smp 2" 32 | self.runkScript += f" -kernel {self.KPath}/arch/x86/boot/bzImage" 33 | self.runkScript += f" -append \"console=ttyS0 root=/dev/sda earlyprintk=serial net.ifnames=0 nokaslr\"" 34 | self.runkScript += f" -drive file={self.ImgPath}bullseye.img,format=raw" 35 | self.runkScript += f" -net user,host=10.0.2.10,hostfwd=tcp:127.0.0.1:10021-:22" 36 | self.runkScript += f" -net nic,model=e1000" 37 | self.runkScript += f" -nographic" 38 | self.runkScript += f" -enable-kvm" 39 | self.runkScript += f" -cpu host" 40 | self.runkScript += f" -s" 41 | self.runkScript += f" -pidfile {self.ImgPath}vm.pid" 42 | self.runkScript += f" 2>&1 | tee {self.ImgPath}vm.log" 43 | self.runkScript += f"\n" 44 | def logb(self, msgType, inMsg, quiet=False): 45 | endFmt = "\x1b[0m" 46 | startFmt = "" 47 | col1 = "" 48 | col2 = "" 49 | logChar = "" 50 | if msgType == "fail": 51 | col1 = "\x1b[38;5;124m" 52 | col2 = "\x1b[38;5;197m" 53 | logChar = "!" 54 | if msgType == "good": 55 | col1 = "\x1b[38;5;46m" 56 | col2 = "\x1b[38;5;154m" 57 | logChar = "+" 58 | if msgType == "warn": 59 | col1 = "\x1b[38;5;208m" 60 | col2 = "\x1b[38;5;220m" 61 | logChar = "-" 62 | if msgType == "info": 63 | col1 = "\x1b[38;5;51m" 64 | col2 = "\x1b[38;5;159m" 65 | logChar = "i" 66 | if msgType == "log": 67 | col1 = "\x1b[38;5;51m" 68 | col2 = "\x1b[38;5;159m" 69 | logChar = "+" 70 | if msgType == "q": 71 | col1 = "\x1b[38;5;63m" 72 | col2 = "\x1b[38;5;171m" 73 | logChar = "?" 74 | startFmt = f"{col1}[{col2}{logChar}{col1}]{col2} " 75 | outmsg = f"{startFmt}{inMsg}{endFmt}" 76 | if quiet == False: 77 | print(outmsg) 78 | return outmsg 79 | def run(self, cmd, rcwd=None): 80 | # This is a wrapper around subprocess.Popen that follows the output 81 | # cmd = A list containing the command to run 82 | # rcwd = current working dir for this command 83 | # returns retcode [int] 84 | retcode = -1 85 | if rcwd == None: 86 | rcwd = self.BaseDir 87 | if cmd is not None: 88 | try: 89 | self.logb("log", f"Executing {cmd}") 90 | subproc = subprocess.Popen(cmd, 91 | cwd=rcwd, 92 | stderr=subprocess.PIPE) 93 | err = '' 94 | while subproc.poll() is None: 95 | if subproc.stderr is not None: 96 | line = subproc.stderr.readline().decode('utf-8') 97 | err += line 98 | sys.stderr.write(line) 99 | sys.stderr.flush() 100 | 101 | exitcode = subproc.poll() 102 | return exitcode 103 | except Exception as e: 104 | print("[!] Error!") 105 | print(e) 106 | return retcode 107 | def KDownload(self): 108 | if self.KVersion: # This means we're downloading a mainline kernel 109 | version_checker = r"^([3-6])\.\d+(?:\.\d+)?$" # support major versions 3,4,5,6 110 | version = re.match(version_checker, self.KVersion) 111 | if not version: 112 | self.logb("fail","Invalid or unsupported kernel version!") 113 | return 114 | major_ver = version.group(1) 115 | full_ver = version.group(0) 116 | tarball_url = f"https://cdn.kernel.org/pub/linux/kernel/v{major_ver}.x/linux-{full_ver}.tar.xz" 117 | file_name = f"linux-{full_ver}" 118 | cwd = os.getcwd() 119 | download_path = f"{cwd}/kernel/" # TODO: Grab this from the class instead!! 120 | archive_name = f"{file_name}.tar.xz" 121 | extracted_path = download_path + file_name # This is where the kernel source is extracted, kernel/linux-version/ 122 | archive_path = download_path + archive_name 123 | 124 | if os.path.isfile(archive_path): 125 | confirm_overwrite = self.logb("warn", f"Warning - already downloaded archive for version {full_ver}. Overwrite? [y/n] (Default=n)", quiet=True) 126 | archiveOverwrite = input(f"{confirm_overwrite} ") 127 | self.isDownloaded = False if archiveOverwrite.lower() == "y" else True # Trigger redownload 128 | # try to download tarball for target kernel version 129 | if self.isDownloaded == False: 130 | self.logb("good",f"Downloading {tarball_url} to {archive_path}") 131 | dlcmd = self.run(["curl", "-s", "--fail", tarball_url, "-o", archive_path]) 132 | if dlcmd != 0: 133 | self.logb("warn", f"Warning - attempt to download archive for kernel version {full_ver} was unsuccessful. plz check your version") 134 | self.isDownloaded = False 135 | return 136 | else: 137 | self.isDownloaded = True 138 | if os.path.isdir(extracted_path): 139 | self.logb("warn", f"Warning - extracted directory already exists for version {full_ver}.") 140 | self.isExtracted = True 141 | if self.isExtracted == False: 142 | self.logb("good", f"Extracting the tarball for {self.KVersion}") 143 | self.run(["tar", "xf", archive_path, "-C", download_path]) 144 | if not os.path.isdir(extracted_path): # Check if extracted files are where we expect 145 | self.logb("warn", f"Warning - tarball downloaded to {archive_path}, but archive extraction was unsuccessful") 146 | else: 147 | self.logb("warn", f"You must set self.KVersion before using KDownload().") 148 | def KConfigure(self): 149 | cmdret = self.run(["make", "defconfig"], rcwd=self.KPath) 150 | cmdret = self.run(["make", "kvm_guest.config"], rcwd=self.KPath) 151 | 152 | self.logb("log",f"Appending {self.KConfig} to {self.KPath}.config") 153 | KConfigFile = open(self.KConfig, "r") 154 | ConfigFile = open(f"{self.KPath}.config", "a+") # This is the config file to write 155 | ConfigFile.write(KConfigFile.read()) 156 | ConfigFile.close() 157 | KConfigFile.close() 158 | 159 | cmdret = self.run(["make", "olddefconfig"], rcwd=self.KPath) 160 | def KCompile(self): 161 | self.logb("warn","Warning: Building the kernel, this may take a while...") 162 | cmdret = self.run(["make", "-j", f"{self.nproc}"], rcwd=self.KPath) 163 | def DebImageBuild(self): 164 | self.logb("log", f"Building Debian Image - Version: {self.KVersion} Hostname: {self.KHostname}") 165 | try: 166 | self.logb("log",f"Making the debian image path {self.ImgPath}") 167 | os.mkdir(self.ImgPath) # this should create the dir, needs testing 168 | except FileExistsError: 169 | self.logb("warn", f"Dir exists, skipping...") 170 | cmdret = self.run(["cp", f"{self.BaseDir}kernel/create-image.sh", self.ImgPath]) 171 | cmdret = self.run([f"{self.ImgPath}create-image.sh","-n", self.KHostname], rcwd=self.ImgPath) 172 | runkScript = open(self.runkPath, "w") 173 | runkScript.write(self.runkScript) 174 | runkScript.close() 175 | # make executable 176 | os.chmod(self.runkPath, 0o777) 177 | self.logb("good", f"runk.sh written to {self.runkPath}.") 178 | # Also need to print ssh config entry for it 179 | def DebImageRun(self): 180 | self.logb("log", f"Running Debian Image in {self.ImgPath}") 181 | cmdret = self.run(["/bin/bash", self.runkPath], rcwd=self.ImgPath) 182 | 183 | if __name__ == '__main__': 184 | parser = argparse.ArgumentParser(description="easylkb - Easy Linux Kernel Builder") 185 | # Configuration 186 | parser.add_argument('-k', dest='KVersion', help='Kernel Version - Downloads a mainline kernel') 187 | parser.add_argument('-p', dest='KPath', help='Path to Linux kernel, use instead of -k') 188 | parser.add_argument('--kconfig', dest='KConfig', help='KConfig, default is example.KConfig') 189 | # Actions 190 | parser.add_argument('-d', dest='KDownload', action="store_true", help='Downloads the source of the kernel') 191 | parser.add_argument('-c', dest='KConfigure', action="store_true", help='Runs kernel configuration commands') 192 | parser.add_argument('-m', dest='KCompile', action="store_true", help='Compiles the kernel') 193 | parser.add_argument('-i', dest='DebImageBuild', action="store_true", help='Builds bootable Debian image from a built kernel') 194 | parser.add_argument('-r', dest='DebImageRun', action="store_true", help='Run image with QEMU') 195 | parser.add_argument('-a', dest='DoAll', action="store_true", help='Do All: Download (or use source specified by -p), Configure, Compile, Build Image, and Run Image') 196 | args = parser.parse_args() 197 | 198 | if args.KVersion is None and args.KPath is None: 199 | print('Please provide a kernel version with -k, or a kernel path with -p') 200 | exit(1) 201 | 202 | myKVersion = args.KVersion 203 | myKPath = args.KPath 204 | myKConfig = args.KConfig 205 | Kb = Kbuilder(KVersion=myKVersion, KPath=myKPath, KConfig=myKConfig) 206 | 207 | if args.DoAll: 208 | if myKPath is not None: 209 | args.KDownload = False # Disable download if a path is specified 210 | elif myKVersion is not None: 211 | args.KDownload = True 212 | else: 213 | print('Please provide a kernel version with -k, or a kernel path with -p') 214 | exit(1) 215 | # Set all the options 216 | args.KConfigure = True 217 | args.KCompile = True 218 | args.DebImageBuild = True 219 | args.DebImageRun = True 220 | 221 | if args.KDownload: 222 | Kb.KDownload() # Download specified kernel tarball 223 | if args.KConfigure: 224 | Kb.KConfigure() # This applies kernel configurations we need to boot and debug the kernel. 225 | if args.KCompile: 226 | Kb.KCompile() # Compile the kernel 227 | if args.DebImageBuild: 228 | Kb.DebImageBuild() # This builds the debian image from the compiled kernel 229 | if args.DebImageRun: 230 | Kb.DebImageRun() 231 | -------------------------------------------------------------------------------- /kernel/create-image.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2016 syzkaller project authors. All rights reserved. 3 | # Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 4 | 5 | # create-image.sh creates a minimal Debian Linux image suitable for syzkaller. 6 | 7 | set -eux 8 | 9 | # Create a minimal Debian distribution in a directory. 10 | DIR=chroot 11 | PREINSTALL_PKGS=openssh-server,curl,tar,gcc,libc6-dev,time,strace,sudo,less,psmisc,selinux-utils,policycoreutils,checkpolicy,selinux-policy-default,firmware-atheros,debian-ports-archive-keyring 12 | 13 | # If ADD_PACKAGE is not defined as an external environment variable, use our default packages 14 | if [ -z ${ADD_PACKAGE+x} ]; then 15 | ADD_PACKAGE="make,sysbench,git,vim,tmux,usbutils,tcpdump" 16 | fi 17 | 18 | # Variables affected by options 19 | ARCH=$(uname -m) 20 | RELEASE=bullseye 21 | FEATURE=minimal 22 | SEEK=2047 23 | PERF=false 24 | IMG_HOSTNAME="localhost" 25 | 26 | # Display help function 27 | display_help() { 28 | echo "Usage: $0 [option...] " >&2 29 | echo 30 | echo " -a, --arch Set architecture" 31 | echo " -d, --distribution Set on which debian distribution to create" 32 | echo " -f, --feature Check what packages to install in the image, options are minimal, full" 33 | echo " -n, --hostname Set hostname" 34 | echo " -s, --seek Image size (MB), default 2048 (2G)" 35 | echo " -h, --help Display help message" 36 | echo " -p, --add-perf Add perf support with this option enabled. Please set envrionment variable \$KERNEL at first" 37 | echo 38 | } 39 | 40 | while true; do 41 | if [ $# -eq 0 ];then 42 | echo $# 43 | break 44 | fi 45 | case "$1" in 46 | -h | --help) 47 | display_help 48 | exit 0 49 | ;; 50 | -a | --arch) 51 | ARCH=$2 52 | shift 2 53 | ;; 54 | -d | --distribution) 55 | RELEASE=$2 56 | shift 2 57 | ;; 58 | -f | --feature) 59 | FEATURE=$2 60 | shift 2 61 | ;; 62 | -n | --hostname) 63 | IMG_HOSTNAME=$2 64 | shift 2 65 | ;; 66 | -s | --seek) 67 | SEEK=$(($2 - 1)) 68 | shift 2 69 | ;; 70 | -p | --add-perf) 71 | PERF=true 72 | shift 1 73 | ;; 74 | -*) 75 | echo "Error: Unknown option: $1" >&2 76 | exit 1 77 | ;; 78 | *) # No more options 79 | break 80 | ;; 81 | esac 82 | done 83 | 84 | # Handle cases where qemu and Debian use different arch names 85 | case "$ARCH" in 86 | ppc64le) 87 | DEBARCH=ppc64el 88 | ;; 89 | aarch64) 90 | DEBARCH=arm64 91 | ;; 92 | arm) 93 | DEBARCH=armel 94 | ;; 95 | x86_64) 96 | DEBARCH=amd64 97 | ;; 98 | *) 99 | DEBARCH=$ARCH 100 | ;; 101 | esac 102 | 103 | # Foreign architecture 104 | 105 | FOREIGN=false 106 | if [ $ARCH != $(uname -m) ]; then 107 | # i386 on an x86_64 host is exempted, as we can run i386 binaries natively 108 | if [ $ARCH != "i386" -o $(uname -m) != "x86_64" ]; then 109 | FOREIGN=true 110 | fi 111 | fi 112 | 113 | if [ $FOREIGN = "true" ]; then 114 | # Check for according qemu static binary 115 | if ! which qemu-$ARCH-static; then 116 | echo "Please install qemu static binary for architecture $ARCH (package 'qemu-user-static' on Debian/Ubuntu/Fedora)" 117 | exit 1 118 | fi 119 | # Check for according binfmt entry 120 | if [ ! -r /proc/sys/fs/binfmt_misc/qemu-$ARCH ]; then 121 | echo "binfmt entry /proc/sys/fs/binfmt_misc/qemu-$ARCH does not exist" 122 | exit 1 123 | fi 124 | fi 125 | 126 | # Double check KERNEL when PERF is enabled 127 | if [ $PERF = "true" ] && [ -z ${KERNEL+x} ]; then 128 | echo "Please set KERNEL environment variable when PERF is enabled" 129 | exit 1 130 | fi 131 | 132 | # If full feature is chosen, install more packages 133 | if [ $FEATURE = "full" ]; then 134 | PREINSTALL_PKGS=$PREINSTALL_PKGS","$ADD_PACKAGE 135 | fi 136 | 137 | sudo rm -rf $DIR 138 | sudo mkdir -p $DIR 139 | sudo chmod 0755 $DIR 140 | 141 | # 1. debootstrap stage 142 | 143 | DEBOOTSTRAP_PARAMS="--arch=$DEBARCH --include=$PREINSTALL_PKGS --components=main,contrib,non-free,non-free-firmware $RELEASE $DIR" 144 | if [ $FOREIGN = "true" ]; then 145 | DEBOOTSTRAP_PARAMS="--foreign $DEBOOTSTRAP_PARAMS" 146 | fi 147 | 148 | # riscv64 is hosted in the debian-ports repository 149 | # debian-ports doesn't include non-free, so we exclude firmware-atheros 150 | if [ $DEBARCH == "riscv64" ]; then 151 | DEBOOTSTRAP_PARAMS="--keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg --exclude firmware-atheros $DEBOOTSTRAP_PARAMS http://deb.debian.org/debian-ports" 152 | fi 153 | sudo --preserve-env=http_proxy,https_proxy,ftp_proxy,no_proxy debootstrap $DEBOOTSTRAP_PARAMS 154 | 155 | # 2. debootstrap stage: only necessary if target != host architecture 156 | 157 | if [ $FOREIGN = "true" ]; then 158 | sudo cp $(which qemu-$ARCH-static) $DIR/$(which qemu-$ARCH-static) 159 | sudo chroot $DIR /bin/bash -c "/debootstrap/debootstrap --second-stage" 160 | fi 161 | 162 | # Set some defaults and enable promptless ssh to the machine for root. 163 | sudo sed -i '/^root/ { s/:x:/::/ }' $DIR/etc/passwd 164 | echo 'T0:23:respawn:/sbin/getty -L ttyS0 115200 vt100' | sudo tee -a $DIR/etc/inittab 165 | printf '\nauto eth0\niface eth0 inet dhcp\n' | sudo tee -a $DIR/etc/network/interfaces 166 | echo '/dev/root / ext4 defaults 0 0' | sudo tee -a $DIR/etc/fstab 167 | echo 'debugfs /sys/kernel/debug debugfs defaults 0 0' | sudo tee -a $DIR/etc/fstab 168 | echo 'securityfs /sys/kernel/security securityfs defaults 0 0' | sudo tee -a $DIR/etc/fstab 169 | echo 'configfs /sys/kernel/config/ configfs defaults 0 0' | sudo tee -a $DIR/etc/fstab 170 | echo 'binfmt_misc /proc/sys/fs/binfmt_misc binfmt_misc defaults 0 0' | sudo tee -a $DIR/etc/fstab 171 | echo -en "127.0.0.1\tlocalhost\n" | sudo tee $DIR/etc/hosts 172 | echo "nameserver 8.8.8.8" | sudo tee -a $DIR/etc/resolve.conf 173 | echo $IMG_HOSTNAME | sudo tee $DIR/etc/hostname 174 | ssh-keygen -f $RELEASE.id_rsa -t rsa -N '' 175 | sudo mkdir -p $DIR/root/.ssh/ 176 | cat $RELEASE.id_rsa.pub | sudo tee $DIR/root/.ssh/authorized_keys 177 | 178 | # Add perf support 179 | if [ $PERF = "true" ]; then 180 | cp -r $KERNEL $DIR/tmp/ 181 | BASENAME=$(basename $KERNEL) 182 | sudo chroot $DIR /bin/bash -c "apt-get update; apt-get install -y flex bison python-dev libelf-dev libunwind8-dev libaudit-dev libslang2-dev libperl-dev binutils-dev liblzma-dev libnuma-dev" 183 | sudo chroot $DIR /bin/bash -c "cd /tmp/$BASENAME/tools/perf/; make" 184 | sudo chroot $DIR /bin/bash -c "cp /tmp/$BASENAME/tools/perf/perf /usr/bin/" 185 | rm -r $DIR/tmp/$BASENAME 186 | fi 187 | 188 | # Add udev rules for custom drivers. 189 | # Create a /dev/vim2m symlink for the device managed by the vim2m driver 190 | echo 'ATTR{name}=="vim2m", SYMLINK+="vim2m"' | sudo tee -a $DIR/etc/udev/rules.d/50-udev-default.rules 191 | 192 | # Build a disk image 193 | dd if=/dev/zero of=$RELEASE.img bs=1M seek=$SEEK count=1 194 | sudo mkfs.ext4 -F $RELEASE.img 195 | sudo mkdir -p /mnt/$DIR 196 | sudo mount -o loop $RELEASE.img /mnt/$DIR 197 | sudo cp -a $DIR/. /mnt/$DIR/. 198 | sudo umount /mnt/$DIR 199 | --------------------------------------------------------------------------------