├── .gitignore ├── COPYING ├── README.md ├── autostart ├── README.md ├── autostart.c ├── autostart.service ├── autostart.sh └── compile_flags.txt ├── extensions.json ├── launch.json ├── local.sh ├── settings.jsonnet ├── syzbot.ipynb ├── tasks.json └── tasks.sh /.gitignore: -------------------------------------------------------------------------------- 1 | local*.sh 2 | settings.json 3 | settings-extra.json 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VSCode for Linux kernel development 2 | 3 | ## Features 4 | 5 | **Editor:** 6 | 7 | * Symbol lookup (go-to-definition etc) based on your `.config` 8 | * Clangd and Checkpatch live squiggles and linting 9 | * Syntax highlighting for KConfig, assembly language, and Device Trees 10 | 11 | **Compilation:** 12 | 13 | * Minimal defconfig generation that boots in a VM 14 | * Easy cross-compilation to arm64 15 | * `Ctrl+Click` on error messages point back to code 16 | 17 | **Testing on a local VM:** 18 | 19 | * Minimal Debian VMs generation 20 | * Autostart of C and shell payloads 21 | * Integrated serial output 22 | * Easy SSH into the VM 23 | 24 | **Patch management:** 25 | 26 | * `git format-patch` and `send-email` assistant 27 | * Mailing list exploration using Patchwork 28 | * `kernel.org`'s cgit links generation 29 | 30 | **Debugging:** 31 | 32 | * Integrated VM debugger using GDB (function and conditional breakpoints, 33 | watchpoints, backtraces, variable inspection, step-by-step, disassembly 34 | views etc...) 35 | * Integrated IPython notebook for ftrace analysis 36 | * BPF selftests cross-compilation and run tasks 37 | * Ctrl-Click addresses like `__sys_sendmsg+0x284/0x370` in your backtraces and 38 | they will automatically get resolved by `addr2line` 39 | * Easy systemtap probing (right click -> "Trace this function") and logging 40 | with deep argument inspection (logs buffer opens immediately on logs) 41 | 42 | **Syzkaller:** 43 | 44 | * Straightforward setup to test syzkaller fuzzer descriptions 45 | * Integrated IPython notebook to reproduce [syzbot](https://syzkaller.appspot.com/upstream) bugs 46 | 47 | **Other:** 48 | 49 | * Transparent remote development from a laptop 50 | * Setup that is easy to modify (bash scripts) and contribute to 51 | * Easy to update 52 | 53 | ## LPC Talk 54 | 55 | This setup was presented at the Linux Plumbers 2023 conference. The slides can be found [here](https://lpc.events/event/17/contributions/1614/attachments/1210/2474/VSCode%20for%20kernel%20development.pdf) and the video below: 56 | 57 | [![VSCode for kernel development](https://img.youtube.com/vi/nmYaSqe0fGg/0.jpg)](https://www.youtube.com/watch?v=nmYaSqe0fGg) 58 | 59 | ## System-wide installation *(done once)* 60 | 61 | Install the dependencies required to run all the supported commands/tasks: 62 | 63 | ``` 64 | curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg 65 | sudo install -o root -g root -m 644 microsoft.gpg /usr/share/keyrings/microsoft-archive-keyring.gpg 66 | sudo sh -c 'echo "deb [arch=amd64,arm64,armhf signed-by=/usr/share/keyrings/microsoft-archive-keyring.gpg] https://packages.microsoft.com/repos/vscode stable main" > /etc/apt/sources.list.d/vscode.list' 67 | sudo apt update 68 | sudo apt install code gdb-multiarch ccache clang clangd llvm lld libguestfs-tools libssl-dev trace-cmd python3-pip jsonnet libelf-dev bison bindfs mkosi proot systemtap flex yacc bc debian-archive-keyring 69 | ``` 70 | 71 | For VS Code to keep track of all the files in your kernel source tree: 72 | 73 | ```shell 74 | sudo bash -c 'echo "fs.inotify.max_user_watches=524288" >> /etc/sysctl.conf' 75 | sudo sysctl -p 76 | ``` 77 | 78 | ## Linux tree setup *(done once per kernel tree)* 79 | 80 | Inside a fresh linux kernel tree, e.g.: 81 | 82 | ```shell 83 | git clone https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 84 | cd linux 85 | ``` 86 | 87 | Create a `.vscode` directory with our config files inside: 88 | 89 | ```shell 90 | git clone https://github.com/FlorentRevest/linux-kernel-vscode .vscode/ 91 | .vscode/tasks.sh update # Needs to be run once to generate settings.json 92 | ``` 93 | 94 | ## Extensions *(done once)* 95 | 96 | If you open the kernel tree in VSCode. A pop-up will appear recommending 97 | workspace extensions, install them all. Here is what they do: 98 | 99 | * [C/C++ via Clangd](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd) 100 | this integrates with a `compile_commands.json` file autogenerated on kernel 101 | builds. 102 | * [Git integration](https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens) 103 | this provides a git blame at the end of the selected line and adds many 104 | options to the source control tab (commit log, file history, branches 105 | switching etc...). 106 | * [x86 and x86_64 Assembly](https://marketplace.visualstudio.com/items?itemName=13xforever.language-x86-64-assembly) 107 | provides syntax highlighting for asm files. 108 | * [ARM64 Assembly](https://marketplace.visualstudio.com/items?itemName=MKornelsen.vscode-arm64) 109 | same, but for arm. 110 | * [Device Tree](https://marketplace.visualstudio.com/items?itemName=plorefice.devicetree) 111 | provides syntax highlighting for dts files. 112 | * [KConfig](https://marketplace.visualstudio.com/items?itemName=luveti.kconfig) 113 | provides syntax highlighting for Kconfig files. 114 | * [Checkpatch](https://marketplace.visualstudio.com/items?itemName=idanp.checkpatch) 115 | provides squiggle highlighting of checkpatch errors on file saves. 116 | * [Patchwork](https://marketplace.visualstudio.com/items?itemName=florent-revest.patchwork) 117 | view, apply and search patches from the 118 | [linux patchwork instance](https://patchwork.kernel.org/). 119 | * [Addr2line](https://marketplace.visualstudio.com/items?itemName=florent-revest.addr2line) 120 | lets users ctrl+click on addresses in backtraces and they get resolved into 121 | lines of code. 122 | * [Git send-email](https://marketplace.visualstudio.com/items?itemName=florent-revest.git-send-email) 123 | facilitates sending patches or series to the list. 124 | * [Syzlang](https://marketplace.visualstudio.com/items?itemName=florent-revest.vscode-syzlang) 125 | highlights syzkaller syscall descriptions. 126 | * [Syzkaller coverage](https://marketplace.visualstudio.com/items?itemName=florent-revest.syzkaller-coverage) 127 | can highlight lines covered by a running instance of syz-manager fuzzing. 128 | * [SystemTap Assistant](https://marketplace.visualstudio.com/items?itemName=florent-revest.systemtap-assistant) 129 | facilitates kernel functions or lines tracing by dynamically generating 130 | systemtap scripts and rendering logs received from these probes in a buffer. 131 | * [SystemTap](https://marketplace.visualstudio.com/items?itemName=nzh21.systemtap-syntax) 132 | highlights systemtap scripts. 133 | * [Microsoft C/C++](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) 134 | only the GDB integration of this plugin is used, every features interacting 135 | with the code is disabled in favor of Clangd which works much better. 136 | * [Trailing spaces](https://marketplace.visualstudio.com/items?itemName=shardulm94.trailing-spaces) 137 | highlights forgotten trailing spaces. 138 | 139 | If the pop-up didn't appear or you dismissed it: 140 | 141 | 1. Click on the Extensions tab on the left hand side of VSCode 142 | 2. Enter "@recommended" in the search bar 143 | 3. Manually click the "Install" button on every extension in the "Workspace 144 | Recommendations" section 145 | 146 | NOTE: You probably want either one of these extensions too (run the command in 147 | the `Ctrl+P` dialog box): 148 | 149 | * [Vim emulation](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim): 150 | 151 | ```shell 152 | ext install vscodevim.vim 153 | ``` 154 | 155 | * [Emacs emulation](https://marketplace.visualstudio.com/items?itemName=vscodeemacs.emacs): 156 | 157 | ```shell 158 | ext install vscodeemacs.emacs 159 | ``` 160 | 161 | ## Basic usage 162 | 163 | * **Compile** the kernel using `Ctrl+Shift+B` (if you don't have a `.config` 164 | yet, it will generate a functional one automatically for you). 165 | * **Run** it with `F5`. 166 | * **Debug** with breakpoints by clicking on the left of a line number. 167 | * **Open** a file by name with `Ctrl+P`. 168 | * **Navigate** between symbol definition/declaration with `F12`. 169 | * Get **clang squiggles** by building the kernel once and waiting for clangd 170 | to index the code for a bit. Clang also supports code refactoring (symbol 171 | renames with `F2` for example) and auto-formatting according to kernel rules 172 | with `Ctrl+Shift+I`. 173 | * Get **`checkpatch` squiggles** by saving the current file. 174 | * Interact with **git** following 175 | [this demo](https://www.youtube.com/watch?v=UQPb73Zz9qk). 176 | * Change the content of `TARGET_ARCH` in `.vscode/local.sh` to `arm64` to 177 | transparently get an *aarch64** workspace (future compilations/virtual 178 | machines will be `arm64`). 179 | * Customize per-workspace VS-Code settings the normal way (edit local 180 | `.vscode/settings.json`, or use `Ctrl+Shift+P` -> "Preferences: Open 181 | Settings (UI)"). Note that fields that exist in `settings.jsonnet` will get 182 | overwritten when you run the `update` task. If needed, extra settings can be 183 | added in `.vscode/settings-extra.json` file. Also, comments in your 184 | `.vscode/settings.json` will get deleted. 185 | * **Autostart** commands or codes at VM start time by modifying the content of 186 | `.vscode/autostart/` (eg: always run tests that exercise the kernel 187 | subsystem you work on). 188 | * Find **more helper tasks** using `Ctrl+Shift+P`, search for `Run task` and 189 | then pick from the list (for example you can run menuconfig, create SSH 190 | sessions, update to the latest version of this setup etc). 191 | * **Interact with your VM** from an external terminal using 192 | commands such as `lkv start`, `lkv ssh`, `lkv stop` etc... 193 | 194 | Make sure to check the *Tips and Tricks* and *Interactive Playground* options 195 | under *Help* in the menu bar to learn more about basic VS Code usage. 196 | 197 | ## Commands outside of VSCode 198 | 199 | All tasks are implemented in the `tasks.sh` file. This script can be run from 200 | anywhere. For example: 201 | 202 | ```shell 203 | alias lkv=~/linux/.vscode/tasks.sh 204 | lkv build # Equivalent to Ctrl+Shift+B 205 | lkv start # Equivalent to F5 206 | lkv ssh 207 | lkv stop 208 | lkv push ./file 209 | lkv pull /root/file 210 | lkv run ls / 211 | lkv chroot 212 | ``` 213 | 214 | ## Technical documentation 215 | 216 | If you want or need to dive into the nitty-gritty of this setup: 217 | 218 | All the VSCode config files are maintained under this git repository. 219 | Improvement PRs can be sent to 220 | https://github.com/FlorentRevest/linux-kernel-vscode and will be easily 221 | fetchable by users thanks to the auto-update task (which updates `.vscode` from 222 | there). 223 | 224 | * `.vscode/tasks.json` [describes per-workspace tasks to 225 | VSCode](https://code.visualstudio.com/docs/editor/tasks#_custom-tasks). 226 | These tasks are entries under the `Ctrl+Shift+P` `Run task` dialog box. All 227 | task basically just call `tasks.sh` with a different command flag. 228 | * `.vscode/tasks.sh` is a bash script with a big switch statement that 229 | implements all tasks exposed by `tasks.json`. They all share a common 230 | preamble customizable 231 | locally by local.sh. 232 | * `.vscode/settings.jsonnet` [provides per-workspace configuration values to 233 | VSCode](https://code.visualstudio.com/docs/getstarted/settings) and its 234 | extensions. This is constructed by `tasks.sh` by evaluating 235 | [`settings.jsonnet`](http://depot/company/teams/security/kernel/tools/vscode/settings.jsonnet) 236 | with the existing settings as an input. The JSonnet file contains sane 237 | defaults valid for all kernel developers. For example, it specifies which 238 | files VSCode should ignore, how to handle spaces and tabs or how to generate 239 | `kernel.org` cgit links from a file path and line. Individual developers can 240 | then customize per-workspace settings for their kernel trees while still 241 | benefiting from the defaults in the JSonnet file. 242 | * `.vscode/syzbot.ipynb` is a reference Jupyter notebook to automate the 243 | repetitive aspects of reproducing a syzkaller bug. Every step along the way 244 | is guided. 245 | * `.vscode/launch.json` 246 | [describes how to run a VM with a debugger attached to VSCode](https://code.visualstudio.com/docs/editor/debugging#_launch-configurations). 247 | * `.vscode/extensions.json` [describes a list of recommended extensions to 248 | VSCode](https://code.visualstudio.com/docs/editor/extension-marketplace#_recommended-extensions). 249 | These are meant to be sane defaults valid for all kernel developers. 250 | Extensions are pulled in from 251 | [the VSCode Marketplace](https://marketplace.visualstudio.com/). 252 | * `.vscode/local.sh` is a local config file not updated by the auto-update 253 | task. It can be used to implement special features or override defaults for 254 | specific needs. 255 | * `.vscode/autostart/` contains the template for a dummy task that gets run 256 | at the end of the VM's boot. Before running a VM, `tasks.sh` is responsible 257 | for detecting changes to these files and updating the files in the VM's 258 | rootfs. 259 | 260 | Note: The [Patchwork](https://github.com/FlorentRevest/vscode-patchwork) and 261 | [Git Send Email](https://github.com/FlorentRevest/vscode-git-send-email) 262 | extensions are homegrown and maintained in other git repositories. 263 | Pull-requests or bug reports are also welcome there. 264 | -------------------------------------------------------------------------------- /autostart/README.md: -------------------------------------------------------------------------------- 1 | This service is automatically re-built and re-installed on the VM image 2 | before every virtual machine run. This lets you easily trigger a userspace 3 | payload at boot time, without having to yourself interact with the VM. 4 | 5 | This consists of: 6 | - a systemd service which, late at boot, starts the next two programs and 7 | redirects their output to the boot terminal 8 | - a shell script if you want to trigger stimuli easily accessible from bash 9 | - a C code if you want to hook into deeper system APIs 10 | 11 | Modify any of these files to easily exercise the kernel behavior you work on. -------------------------------------------------------------------------------- /autostart/autostart.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PRINTF_GREEN(f, ...) printf("\033[1;92m" f "\033[0m", ##__VA_ARGS__) 4 | 5 | int main(void) 6 | { 7 | // PRINTF_GREEN("Hello from autostart.c"); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /autostart/autostart.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Autostart 3 | 4 | [Service] 5 | Type=idle 6 | ExecStart=/usr/bin/autostart.sh 7 | StandardOutput=journal+console 8 | StandardError=journal+console 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /autostart/autostart.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo-green() { 4 | echo -e "\033[0;92m" $@ "\033[0m" 5 | } 6 | 7 | # echo-green "Hello from autostart.sh" 8 | 9 | # If a systemtap tracer module if available, use it to trace /usr/bin/autostart 10 | if [ -e "/host/tmp/tracer.ko" ]; then 11 | # Workaround the detection of kprobes optimization capabilities 12 | export STAP_PR13193_OVERRIDE=1 13 | # Route UDP logs via the default IP interface (it must be ethernet) 14 | DEFAULT_ROUTE=`ip route show default | awk '/dev/ {print $5}'` 15 | # Wrap autostart with a systemtap run. This sets target() to autostart's pid 16 | TRACER="staprun /host/tmp/tracer.ko interface=${DEFAULT_ROUTE} -c" 17 | fi 18 | 19 | $TRACER /usr/bin/autostart 20 | -------------------------------------------------------------------------------- /autostart/compile_flags.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FlorentRevest/linux-kernel-vscode/c8ff44f86fd363cd76cb3b1de59fe12ecafb14f5/autostart/compile_flags.txt -------------------------------------------------------------------------------- /extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "florent-revest.patchwork", 4 | "florent-revest.git-send-email", 5 | "florent-revest.vscode-syzlang", 6 | "florent-revest.syzkaller-coverage", 7 | "florent-revest.addr2line", 8 | "florent-revest.systemtap-assistant", 9 | "llvm-vs-code-extensions.vscode-clangd", 10 | "13xforever.language-x86-64-assembly", 11 | "plorefice.devicetree", 12 | "luveti.kconfig", 13 | "idanp.checkpatch", 14 | "eamodio.gitlens", 15 | "ms-vscode.cpptools", 16 | "MKornelsen.vscode-arm64", 17 | "nzh21.systemtap-syntax", 18 | "shardulm94.trailing-spaces" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Start and debug kernel in a VM", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | "preLaunchTask": "Start virtual machine", 9 | "internalConsoleOptions": "neverOpen", 10 | 11 | "miDebuggerPath": "gdb-multiarch", 12 | "miDebuggerServerAddress": "localhost:1234", 13 | "setupCommands": [ 14 | { 15 | "description": "Give some time for the VM to spin-up", 16 | "text": "-interpreter-exec console \"shell ${workspaceFolder}/.vscode/tasks.sh wait-for-vm\"", 17 | "ignoreFailures": false, 18 | }, 19 | { 20 | "description": "Enable autoloading of Linux GDB scripts", 21 | "text": "add-auto-load-safe-path ${workspaceFolder}/scripts/gdb", 22 | "ignoreFailures": true, 23 | }, 24 | { 25 | "description": "Format Locals as HEX by default", 26 | "text": "set output-radix 16", 27 | "ignoreFailures": true, 28 | }, 29 | ], 30 | 31 | "cwd": "${workspaceFolder}", 32 | "program": "${workspaceFolder}/vmlinux", 33 | 34 | "hardwareBreakpoints": { "require": true, "limit": 4 }, 35 | }, 36 | { 37 | "name": "Start and debug kernel in a VM from early-boot", 38 | "type": "cppdbg", 39 | "request": "launch", 40 | "preLaunchTask": "Start virtual machine waiting for debugger", 41 | "internalConsoleOptions": "neverOpen", 42 | 43 | "miDebuggerPath": "gdb-multiarch", 44 | "miDebuggerServerAddress": "localhost:1234", 45 | "setupCommands": [ 46 | { 47 | "description": "Give some time for the VM to spin-up", 48 | "text": "-interpreter-exec console \"shell ${workspaceFolder}/.vscode/tasks.sh wait-for-vm\"", 49 | "ignoreFailures": true 50 | }, 51 | { 52 | "description": "Enable autoloading of Linux GDB scripts", 53 | "text": "add-auto-load-safe-path ${workspaceFolder}/scripts/gdb", 54 | "ignoreFailures": true, 55 | }, 56 | { 57 | "description": "Format Locals as HEX by default", 58 | "text": "set output-radix 16", 59 | "ignoreFailures": true, 60 | }, 61 | ], 62 | 63 | "cwd": "${workspaceFolder}", 64 | "program": "${workspaceFolder}/vmlinux", 65 | 66 | "hardwareBreakpoints": { "require": true, "limit": 4 }, 67 | }, 68 | { 69 | "name": "Debug kernel in an already-running VM", 70 | "type": "cppdbg", 71 | "request": "launch", 72 | "internalConsoleOptions": "neverOpen", 73 | 74 | "miDebuggerPath": "gdb-multiarch", 75 | "miDebuggerServerAddress": "localhost:1234", 76 | "setupCommands": [ 77 | { 78 | "description": "Wait for the VM to spin-up", 79 | "text": "-interpreter-exec console \"shell ${workspaceFolder}/.vscode/tasks.sh wait-for-vm\"", 80 | "ignoreFailures": false, 81 | }, 82 | { 83 | "description": "Enable autoloading of Linux GDB scripts", 84 | "text": "add-auto-load-safe-path ${workspaceFolder}/scripts/gdb", 85 | "ignoreFailures": true, 86 | }, 87 | { 88 | "description": "Format Locals as HEX by default", 89 | "text": "set output-radix 16", 90 | "ignoreFailures": true, 91 | }, 92 | ], 93 | 94 | "cwd": "${workspaceFolder}", 95 | "program": "${workspaceFolder}/vmlinux", 96 | 97 | "hardwareBreakpoints": { "require": true, "limit": 4 }, 98 | } 99 | ] 100 | } 101 | -------------------------------------------------------------------------------- /local.sh: -------------------------------------------------------------------------------- 1 | # This file is sourced in the middle of tasks.sh, after environment variables 2 | # are setup and before commands are run. It does not get updated by the update 3 | # task so you can use it to plug-in arbitrary extra logic that is specific to 4 | # your local needs and should not be part of the upstream tasks.sh. For example: 5 | 6 | ## Cross-compile/debug/emulate for arm64 7 | # TARGET_ARCH=arm64 8 | 9 | ## Change PATH to use a different QEMU binary 10 | # export PATH=$HOME/qemu/bin/:$PATH 11 | 12 | ## Generate objects in a subdirectory 13 | # MAKE="$MAKE O=.vscode/build-$TARGET_ARCH/" 14 | 15 | ## Enable some random kernel CONFIG by default as part of the .config generation 16 | # if [ $COMMAND = "defconfig" ]; then 17 | # trap "scripts/config -e BPF_SYSCALL" EXIT 18 | # fi 19 | 20 | ## Run make olddefconfig before a build (a bit slow) 21 | # if [ $COMMAND = "build" ]; then 22 | # eval ${MAKE} ARCH=${TARGET_ARCH} olddefconfig 23 | # fi 24 | 25 | ## Make the build verbose 26 | # SILENT_BUILD_FLAG="" 27 | 28 | ## Disable the build spinner 29 | # SPINNER=0 30 | 31 | ## Don't clear the screen before each task 32 | # unset CLEAR 33 | 34 | ## Boot without systemd (use the /sbin/init-minimal shell script instead) 35 | # SKIP_SYSTEMD=1 36 | 37 | ## Add some args to the kernel cmdline when using the "start" task 38 | ## E.g.: Boot straight into a syzbot reproducer 39 | # KERNEL_CMDLINE_EXTRA=init=/root/syzbot-repro 40 | 41 | ## Only fuzz the /dev/ptmx ioctls 42 | # SYZ_MANAGER_CFG_EXTRA='"enable_syscalls": [ "openat$ptmx", "ioctl$*" ],' 43 | 44 | ## Fuzz as an unprivileged user 45 | # SYZ_MANAGER_CFG_EXTRA='"sandbox": "setuid",' 46 | -------------------------------------------------------------------------------- /settings.jsonnet: -------------------------------------------------------------------------------- 1 | // This is a jsonnet file, to evaluate it on the command-line use 2 | // 3 | // jsonnet \ 4 | // --ext-code-file old_settings= \ 5 | // --ext-code-file extra_settings= \ 6 | // 7 | // 8 | // JSonnet is a superset of JSON. Here we are using a minimal subset of 9 | // JSonnet's extra features, see the "External Variables" and "Object 10 | // Orientation" section of jsonnet tutorials (plus we use comments). 11 | std.extVar('old_settings') + { 12 | "files.exclude": { 13 | "**/.*.cmd": true, 14 | "**/.*.d": true, 15 | "**/.*.S": true, 16 | "**/.tmp*": true, 17 | "**/*.tmp": true, 18 | "**/*.o": true, 19 | "**/*.a": true, 20 | "**/*.builtin": true, 21 | "**/*.order": true, 22 | "**/*.orig": true, 23 | "**/*.symvers": true, 24 | "**/*.modinfo": true, 25 | "**/*.map": true, 26 | "*.cache/**": true 27 | }, 28 | "search.exclude": { 29 | "**/.*.cmd": true, 30 | "**/.*.d": true, 31 | "**/.*.S": true, 32 | "**/.tmp*": true, 33 | "**/*.tmp": true, 34 | "**/*.o": true, 35 | "**/*.a": true, 36 | "**/*.builtin": true, 37 | "**/*.order": true, 38 | "**/*.orig": true, 39 | "**/*.symvers": true, 40 | "**/*.modinfo": true, 41 | "**/*.map": true, 42 | "*.cache/**": true 43 | }, 44 | "editor.detectIndentation": false, 45 | "editor.tabSize": 8, 46 | "editor.insertSpaces": false, 47 | "editor.rulers": [80, 100], 48 | "files.associations": { 49 | "**/x86/**/*.S": "asm-intel-x86-generic", 50 | "**/arch/x86/entry/calling.h": "asm-intel-x86-generic", 51 | "**/arm64/**/*.S": "arm64", 52 | "*_defconfig": "kconfig" 53 | }, 54 | "checkpatch.run": "onSave", 55 | "checkpatch.exclude": ["**/.vscode/autostart/*.c"], 56 | "git.alwaysSignOff": true, 57 | "C_Cpp.autocomplete": "disabled", 58 | "C_Cpp.formatting": "disabled", 59 | "C_Cpp.errorSquiggles": "disabled", 60 | "C_Cpp.intelliSenseEngine": "disabled", 61 | "checkpatch.checkpatchPath": "scripts/checkpatch.pl", 62 | "editor.renderWhitespace": "boundary", 63 | "gitlens.showWelcomeOnInstall": false, 64 | "gitlens.showWhatsNewAfterUpgrades": false, 65 | "gitlens.plusFeatures.enabled": false, 66 | "gitlens.mode.statusBar.enabled": false, 67 | "gitlens.statusBar.enabled": false, 68 | "gitlens.remotes": [ 69 | { 70 | "regex": ".+:\\/\\/(git\\.kernel\\.org)\\/(.+)", 71 | "type": "Custom", 72 | "name": "kernel.org", 73 | "protocol": "https", 74 | "urls": { 75 | "repository": "https://git.kernel.org/${repoBase}/${repoPath}/tree", 76 | "branches": "https://git.kernel.org/${repoBase}/${repoPath}/refs", 77 | "branch": "https://git.kernel.org/${repoBase}/${repoPath}/log/?h=${branch}", 78 | "commit": "https://git.kernel.org/${repoBase}/${repoPath}/commit/?id=${id}", 79 | "file": "https://git.kernel.org/${repoBase}/${repoPath}/tree/${file}${line}", 80 | "fileInBranch": "https://git.kernel.org/${repoBase}/${repoPath}/tree/${file}?h=${branch}${line}", 81 | "fileInCommit": "https://git.kernel.org/${repoBase}/${repoPath}/tree/${file}?id=${id}${line}", 82 | "fileLine": "#n${line}", 83 | "fileRange": "#n${start}" 84 | } 85 | } 86 | ], 87 | "trailing-spaces.highlightCurrentLine": false, 88 | "trailing-spaces.deleteModifiedLinesOnly": true, 89 | "trailing-spaces.trimOnSave": true, 90 | "systemtap-assistant.output": ".vscode/autostart/tracer.stp", 91 | "systemtap-assistant.deploy-task": "Build systemtap tracer", 92 | "debug.onTaskErrors": "debugAnyway" 93 | } + std.extVar('extra_settings') 94 | -------------------------------------------------------------------------------- /syzbot.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": {}, 7 | "source": [ 8 | "# Sybot bug reproducer" 9 | ] 10 | }, 11 | { 12 | "attachments": {}, 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "Enter the URL of a syzbot bug you'd like to reproduce:" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": null, 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "bug_url=input('Syzbot bug URL, e.g.: https://syzkaller.appspot.com/bug?extid=fcc47ba2476570cbbeb0')" 26 | ] 27 | }, 28 | { 29 | "attachments": {}, 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Crash selection" 34 | ] 35 | }, 36 | { 37 | "attachments": {}, 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "Download the syzbot page as HTML." 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": {}, 48 | "outputs": [], 49 | "source": [ 50 | "bug_html=!curl {bug_url}" 51 | ] 52 | }, 53 | { 54 | "attachments": {}, 55 | "cell_type": "markdown", 56 | "metadata": {}, 57 | "source": [ 58 | "Parse the crashes table as a Pandas data frame and pretty print interesting fields" 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": null, 64 | "metadata": {}, 65 | "outputs": [], 66 | "source": [ 67 | "import pandas as pd\n", 68 | "crashes = pd.read_html(bug_html.nlstr, match=\"Crashes\", extract_links=\"body\")[0]\n", 69 | "display(crashes.applymap(lambda val: val[0])[[\"Time\", \"Commit\", \"Syz repro\", \"C repro\"]])" 70 | ] 71 | }, 72 | { 73 | "attachments": {}, 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "Select the crash you'd like to reproduce:" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": null, 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "crash_id=int(input(\"Crash to reproduce (by row number), e.g.: 0\"))" 87 | ] 88 | }, 89 | { 90 | "attachments": {}, 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "## Kernel setup" 95 | ] 96 | }, 97 | { 98 | "attachments": {}, 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "Checkout the kernel commit" 103 | ] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "execution_count": null, 108 | "metadata": {}, 109 | "outputs": [], 110 | "source": [ 111 | "!git checkout {crashes[\"Commit\"][crash_id][0]}" 112 | ] 113 | }, 114 | { 115 | "attachments": {}, 116 | "cell_type": "markdown", 117 | "metadata": {}, 118 | "source": [ 119 | "Overwrite the local `.config`" 120 | ] 121 | }, 122 | { 123 | "cell_type": "code", 124 | "execution_count": null, 125 | "metadata": {}, 126 | "outputs": [], 127 | "source": [ 128 | "!curl \"{'https://syzkaller.appspot.com' + crashes['Config'][crash_id][1]}\" > ../.config" 129 | ] 130 | }, 131 | { 132 | "attachments": {}, 133 | "cell_type": "markdown", 134 | "metadata": {}, 135 | "source": [ 136 | "Build" 137 | ] 138 | }, 139 | { 140 | "cell_type": "code", 141 | "execution_count": null, 142 | "metadata": {}, 143 | "outputs": [], 144 | "source": [ 145 | "!SPINNER=0 ./tasks.sh build" 146 | ] 147 | }, 148 | { 149 | "attachments": {}, 150 | "cell_type": "markdown", 151 | "metadata": {}, 152 | "source": [ 153 | "Start the kernel by pressing `F5`" 154 | ] 155 | }, 156 | { 157 | "attachments": {}, 158 | "cell_type": "markdown", 159 | "metadata": {}, 160 | "source": [ 161 | "## C reproducer" 162 | ] 163 | }, 164 | { 165 | "attachments": {}, 166 | "cell_type": "markdown", 167 | "metadata": {}, 168 | "source": [ 169 | "Download the code" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": null, 175 | "metadata": {}, 176 | "outputs": [], 177 | "source": [ 178 | "!curl \"{'https://syzkaller.appspot.com' + crashes['C repro'][crash_id][1]}\" > /tmp/syzbot-repro.c" 179 | ] 180 | }, 181 | { 182 | "attachments": {}, 183 | "cell_type": "markdown", 184 | "metadata": {}, 185 | "source": [ 186 | "Build it" 187 | ] 188 | }, 189 | { 190 | "cell_type": "code", 191 | "execution_count": null, 192 | "metadata": {}, 193 | "outputs": [], 194 | "source": [ 195 | "!clang -static -lpthread /tmp/syzbot-repro.c -o /tmp/syzbot-repro" 196 | ] 197 | }, 198 | { 199 | "attachments": {}, 200 | "cell_type": "markdown", 201 | "metadata": {}, 202 | "source": [ 203 | "Send it to the VM" 204 | ] 205 | }, 206 | { 207 | "cell_type": "code", 208 | "execution_count": null, 209 | "metadata": {}, 210 | "outputs": [], 211 | "source": [ 212 | "!./tasks.sh push /tmp/syzbot-repro" 213 | ] 214 | }, 215 | { 216 | "attachments": {}, 217 | "cell_type": "markdown", 218 | "metadata": {}, 219 | "source": [ 220 | "Run it" 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": null, 226 | "metadata": {}, 227 | "outputs": [], 228 | "source": [ 229 | "!./tasks.sh run /root/syzbot-repro" 230 | ] 231 | }, 232 | { 233 | "attachments": {}, 234 | "cell_type": "markdown", 235 | "metadata": {}, 236 | "source": [ 237 | "## Syz reproducer" 238 | ] 239 | }, 240 | { 241 | "attachments": {}, 242 | "cell_type": "markdown", 243 | "metadata": {}, 244 | "source": [ 245 | "Download the code" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": null, 251 | "metadata": {}, 252 | "outputs": [], 253 | "source": [ 254 | "!curl \"{'https://syzkaller.appspot.com' + crashes['Syz repro'][crash_id][1]}\" > /tmp/syzbot-repro.syz" 255 | ] 256 | }, 257 | { 258 | "attachments": {}, 259 | "cell_type": "markdown", 260 | "metadata": {}, 261 | "source": [ 262 | "Send it to the VM" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": null, 268 | "metadata": {}, 269 | "outputs": [], 270 | "source": [ 271 | "!./tasks.sh push /tmp/syzbot-repro.syz" 272 | ] 273 | }, 274 | { 275 | "attachments": {}, 276 | "cell_type": "markdown", 277 | "metadata": {}, 278 | "source": [ 279 | "Run it (assumes the VM already has a `/usr/bin/syz-execprog`)" 280 | ] 281 | }, 282 | { 283 | "cell_type": "code", 284 | "execution_count": null, 285 | "metadata": {}, 286 | "outputs": [], 287 | "source": [ 288 | "!./tasks.sh run \"syz-execprog -repeat=0 -procs=1 -sandbox='' /root/syzbot-repro.syz\"" 289 | ] 290 | } 291 | ], 292 | "metadata": { 293 | "kernelspec": { 294 | "display_name": "Python 3", 295 | "language": "python", 296 | "name": "python3" 297 | }, 298 | "language_info": { 299 | "codemirror_mode": { 300 | "name": "ipython", 301 | "version": 3 302 | }, 303 | "file_extension": ".py", 304 | "mimetype": "text/x-python", 305 | "name": "python", 306 | "nbconvert_exporter": "python", 307 | "pygments_lexer": "ipython3", 308 | "version": "3.11.5" 309 | }, 310 | "orig_nbformat": 4 311 | }, 312 | "nbformat": 4, 313 | "nbformat_minor": 2 314 | } 315 | -------------------------------------------------------------------------------- /tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | 4 | // All tasks in this file inherit the following top-level fields. These can be 5 | // shared because all tasks are implemented in the tasks.sh shell script. 6 | "type": "shell", 7 | "command": ".vscode/tasks.sh", 8 | "presentation": { 9 | // Do not have VSCode print ".vscode/tasks.sh task" everytime a task is run. 10 | // We can let tasks.sh print something more useful instead. 11 | "echo": false, 12 | }, 13 | "problemMatcher": [], 14 | 15 | // Because of the above, most task definitions only need to map user-readable 16 | // UI labels (what shows under the Ctrl+Shift+P -> "Tasks: Run task" submenu) 17 | // to an argument for the tasks.sh script that identifies the task to run. 18 | "tasks": [ 19 | { 20 | "label": "Create rootfs for virtual machine if absent", 21 | "args": ["create-rootfs"], 22 | }, 23 | { 24 | "label": "Compile and install autostart", 25 | "args": ["install-autostart"], 26 | }, 27 | { 28 | "label": "Start virtual machine", 29 | "args": ["start"], 30 | "presentation": { 31 | "focus": true, 32 | }, 33 | "isBackground": true, 34 | // For this task to be a background task of a launch.json debugger setup, 35 | // a non-empty problem matcher must be defined. This is just a dummy one. 36 | "problemMatcher": [ 37 | { 38 | "pattern": [ 39 | { 40 | "regexp": ".", 41 | "file": 1, 42 | "location": 2, 43 | "message": 3, 44 | } 45 | ], 46 | "background": { 47 | "activeOnStart": true, 48 | "beginsPattern": ".", 49 | "endsPattern": ".", 50 | } 51 | } 52 | ], 53 | }, 54 | { 55 | "label": "Start virtual machine waiting for debugger", 56 | "args": ["start-wait-dbg"], 57 | "presentation": { 58 | "focus": true, 59 | }, 60 | "isBackground": true, 61 | "problemMatcher": [ 62 | { 63 | "pattern": [ 64 | { 65 | "regexp": ".", 66 | "file": 1, 67 | "location": 2, 68 | "message": 3, 69 | } 70 | ], 71 | "background": { 72 | "activeOnStart": true, 73 | "beginsPattern": ".", 74 | "endsPattern": ".", 75 | } 76 | } 77 | ], 78 | }, 79 | { 80 | "label": "Stop virtual machine", 81 | "args": ["stop"], 82 | }, 83 | { 84 | "label": "SSH into the virtual machine", 85 | "args": ["ssh"], 86 | "presentation": { 87 | "focus": true, 88 | }, 89 | }, 90 | { 91 | "label": "Create .config for virtual machine if absent", 92 | "args": ["defconfig"], 93 | }, 94 | { 95 | "label": "Build kernel", 96 | "args": ["build"], 97 | // Map this task to the Ctrl+Shift+P -> "Run build task" command. 98 | "group": { 99 | "kind": "build", 100 | "isDefault": true, 101 | }, 102 | }, 103 | { 104 | "label": "Menuconfig", 105 | "args": ["menuconfig"], 106 | "presentation": { 107 | "focus": true, 108 | }, 109 | }, 110 | { 111 | "label": "Make clean", 112 | "args": ["clean"], 113 | }, 114 | { 115 | "label": "Chroot into the virtual machine's rootfs", 116 | "args": ["chroot"], 117 | }, 118 | { 119 | "label": "Compile and install BPF selftests", 120 | "args": ["install-bpf-selftests"], 121 | }, 122 | { 123 | "label": "Run BPF selftests", 124 | "args": ["run-bpf-selftests"], 125 | }, 126 | { 127 | "label": "Run BPF selftests in this file", 128 | "args": ["run-bpf-selftests", "${file}"], 129 | }, 130 | { 131 | "label": "Update linux-kernel-vscode setup", 132 | "args": ["update"], 133 | }, 134 | { 135 | "label": "Ensure that KCOV is enabled", 136 | "args": ["enable-kcov"], 137 | }, 138 | { 139 | "label": "Fuzz the kernel in the virtual machine", 140 | "args": ["fuzz"], 141 | }, 142 | { 143 | "label": "Build systemtap tracer", 144 | "args": ["systemtap-build"], 145 | } 146 | ] 147 | } 148 | -------------------------------------------------------------------------------- /tasks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # If you want to modify how tasks behave: 4 | # - Keep features specific to your special use cases in the local.sh file. 5 | # - Send PRs to github.com/FlorentRevest/linux-kernel-vscode for changes that 6 | # would benefit all users. 7 | # This improves the framework and makes sure you can always run the update task. 8 | 9 | function depend_on() { 10 | $SCRIPT $@ 11 | if [[ "$CLEAR" == 1 ]]; then 12 | clear 13 | fi 14 | } 15 | 16 | function spinner() { 17 | local pid=$1 18 | 19 | if [[ "$SPINNER" -eq 1 ]]; then 20 | local spin='⣾⣽⣻⢿⡿⣟⣯⣷' 21 | local i=0 22 | tput civis # Hide cursor 23 | while kill -0 $pid 2>/dev/null; do 24 | local i=$(((i + 1) % ${#spin})) 25 | printf "%s" "${spin:$i:1}" # Print one character 26 | echo -en "\033[$1D" # Go back one character 27 | sleep .1 28 | done 29 | tput cnorm # Restore cursor 30 | fi 31 | 32 | wait $pid 33 | return $? 34 | } 35 | 36 | set -e 37 | 38 | # Arguments extraction 39 | if [ "$#" -lt 1 ]; then 40 | echo "Usage: $0 command" 41 | exit 1 42 | fi 43 | COMMAND=$1 44 | 45 | # See https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html 46 | # for the `: ${var:=DEFAULT}` syntax 47 | : ${SCRIPT:=`realpath -s "$0"`} 48 | : ${SCRIPT_DIR:=`dirname "${SCRIPT}"`} 49 | 50 | # Let the user override environment variables for their special needs 51 | files_to_source=$(find ${SCRIPT_DIR}/ -maxdepth 1 -xtype f -name "local*.sh") 52 | for file in $files_to_source; do 53 | source "$file" 54 | done 55 | 56 | # Default context variables, can be overridden by local.sh or in environment. 57 | : ${WORKSPACE_DIR:=`realpath -s "${SCRIPT_DIR}/.."`} 58 | : ${MAKE:="make -j`nproc` LLVM=1 LLVM_IAS=1 CC='ccache clang'"} 59 | : ${TARGET_ARCH:="x86_64"} 60 | : ${TARGET_GDB:="gdb-multiarch"} 61 | : ${SILENT_BUILD_FLAG="-s"} 62 | : ${SUCCESSFUL_EXIT_COMMAND:=""} 63 | : ${BPF_SELFTESTS_DIR:="${WORKSPACE_DIR}/tools/testing/selftests/bpf"} 64 | : ${VM_START_ARGS:=''} 65 | : ${SYZ_MANAGER_CFG_EXTRA:=''} 66 | : ${SYZKALLER_DIR:="${SCRIPT_DIR}/syzkaller/"} 67 | : ${KERNEL_CMDLINE_EXTRA:=''} 68 | : ${SPINNER:=1} 69 | : ${IMAGE_DIR:="${HOME}/.linux-kernel-vscode"} 70 | : ${IMAGE_PATH:="${IMAGE_DIR}/debian-${TARGET_ARCH}.img"} 71 | : ${TRACER_PATH:=".vscode/autostart/tracer.stp"} 72 | if [[ "$TERM_PROGRAM" == "vscode" ]]; then 73 | : ${CLEAR:=1} 74 | fi 75 | if [[ $SKIP_SYSTEMD == 1 ]]; then 76 | KERNEL_CMDLINE_EXTRA="init=/sbin/init-minimal $KERNEL_CMDLINE_EXTRA" 77 | fi 78 | 79 | # Convenience environment variables derived from the context 80 | if [ "${TARGET_ARCH}" = "x86_64" ]; then 81 | : ${VMLINUX:="bzImage"} 82 | : ${CLANG_TARGET:="x86_64-linux-gnu"} 83 | : ${MKOSI_TARGET_ARCH:="x86-64"} 84 | : ${TOOLS_SRCARCH:="x86"} 85 | : ${QEMU_BIN:="qemu-system-x86_64"} 86 | : ${QEMU_CMD:="${QEMU_BIN} -enable-kvm -cpu host -machine q35 -bios qboot.rom"} 87 | : ${SERIAL_TTY:="ttyS0"} 88 | : ${SYZKALLER_TARGETARCH:="amd64"} 89 | : ${ROOT_MNT:="/dev/sda"} 90 | elif [ "${TARGET_ARCH}" = "arm64" ]; then 91 | : ${VMLINUX:="Image"} 92 | : ${CLANG_TARGET:="aarch64-linux-gnu"} 93 | : ${MKOSI_TARGET_ARCH:="arm64"} 94 | : ${TOOLS_SRCARCH:="arm64"} 95 | : ${QEMU_BIN:="qemu-system-aarch64"} 96 | : ${QEMU_CMD:="${QEMU_BIN} -cpu max -machine virt"} 97 | : ${SERIAL_TTY:="ttyAMA0"} 98 | : ${PROOT_ARGS:="-q qemu-aarch64-static"} 99 | : ${SYZKALLER_TARGETARCH:="arm4"} 100 | : ${ROOT_MNT:="/dev/vda"} 101 | else 102 | echo "Unsupported TARGET_ARCH:" $TARGET_ARCH 103 | exit 2 104 | fi 105 | 106 | : ${KERNEL_PATH:="${WORKSPACE_DIR}/arch/${TARGET_ARCH}/boot/${VMLINUX}"} 107 | 108 | # When called outside of a VSCode task, the current working directory can be 109 | # somewhere else than the workspace. Since we implicitly rely on pwd being the 110 | # top of the kernel tree quite often, cd there. 111 | pushd "$WORKSPACE_DIR" >/dev/null 112 | 113 | if [[ "$CLEAR" == 1 ]]; then 114 | clear 115 | fi 116 | 117 | # SSH Keys 118 | : ${SSH_KEY:="${HOME}/.ssh/linux-kernel-vscode-rsa"} 119 | : ${SSH_CMD:="ssh -p 5555 -i ${SSH_KEY} -o IdentitiesOnly=yes -o NoHostAuthenticationForLocalhost=yes root@localhost"} 120 | : ${SCP_CMD:="scp -P 5555 -r -i ${SSH_KEY} -o IdentitiesOnly=yes -o NoHostAuthenticationForLocalhost=yes"} 121 | if [ ! -f ${SSH_KEY} ]; then 122 | ssh-keygen -t rsa -f ${SSH_KEY} -N "" -q 123 | fi 124 | 125 | # QEMU start command 126 | : ${VM_START:="${QEMU_CMD} -s -nographic -smp 4 -m 4G -qmp tcp:localhost:4444,server,nowait -serial mon:stdio \ 127 | -net nic,model=virtio-net-pci -net user,hostfwd=tcp::5555-:22 \ 128 | -virtfs local,path=/,mount_tag=hostfs,security_model=none,multidevs=remap \ 129 | -append \"console=${SERIAL_TTY},115200 root=${ROOT_MNT} rw nokaslr init=/lib/systemd/systemd debug systemd.log_level=info ${KERNEL_CMDLINE_EXTRA}\" \ 130 | -drive file=${IMAGE_PATH},format=raw -kernel ${KERNEL_PATH} ${VM_START_ARGS}"} 131 | 132 | case "${COMMAND}" in 133 | # Virtual machine life-cycle 134 | "start") 135 | depend_on install-autostart 136 | eval ${VM_START} 137 | ;; 138 | "start-wait-dbg") 139 | depend_on install-autostart 140 | eval ${VM_START} -S 141 | ;; 142 | "stop") 143 | # With SKIP_SYSTEMD, nothing handles ACPI shutdowns so clean shutdown does not work. 144 | if [[ -z $SKIP_SYSTEMD ]]; then 145 | echo -n '{"execute":"qmp_capabilities"} {"execute": "system_powerdown"}' | nc -q 1 localhost 4444 146 | else 147 | killall ${QEMU_BIN} 148 | fi 149 | ;; 150 | "ssh") 151 | eval ${SSH_CMD} 152 | ;; 153 | "run") 154 | shift 155 | eval ${SSH_CMD} $@ 156 | ;; 157 | "wait-for-vm") 158 | # On the first boot, a rootfs isn't yet available. Because debootstrap can 159 | # take a while to run, this waits for the rootfs file to show up. 160 | timeout 120 bash -c "until [ -f ${IMAGE_PATH} ] ; do sleep 0.01; done" 161 | ;; 162 | # Kernel build 163 | "defconfig") 164 | # Only generate .config if it doesn't already exist 165 | if [ ! -f ${WORKSPACE_DIR}/.config ]; then 166 | eval ${MAKE} ARCH=${TARGET_ARCH} defconfig kvm_guest.config 167 | scripts/config --enable DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT 168 | eval ${MAKE} ARCH=${TARGET_ARCH} olddefconfig 169 | fi 170 | ;; 171 | "menuconfig") 172 | # It's important to run menuconfigs with the same parameters as builds 173 | eval ${MAKE} ARCH=${TARGET_ARCH} menuconfig 174 | ;; 175 | "clean") 176 | eval ${MAKE} ARCH=${TARGET_ARCH} clean 177 | ;; 178 | "build") 179 | depend_on defconfig 180 | 181 | # Enable reproducible builds for ccache 182 | export KBUILD_BUILD_TIMESTAMP="" 183 | # Generate not only the kernel but also the clangd config 184 | CMD="${MAKE} ${SILENT_BUILD_FLAG} ARCH=${TARGET_ARCH} all compile_commands.json" 185 | echo ${CMD} 186 | eval ${CMD} & 187 | spinner $! 188 | 189 | # A gdb index may need to be re-generated. Don't clear the above make logs. 190 | CLEAR=0 $SCRIPT gdb-index 191 | # A tracer module may need to be re-built 192 | CLEAR=0 $SCRIPT systemtap-build 193 | ;; 194 | "gdb-index") 195 | # Hitting a breakpoint is *much* faster if we pre-build a gdb symbol index 196 | if ! readelf -S vmlinux | grep -q ".gdb_index"; then 197 | OBJCOPY=llvm-objcopy GDB=${TARGET_GDB} gdb-add-index vmlinux 198 | fi 199 | ;; 200 | # Rootfs management 201 | "create-rootfs") 202 | # Only generate a rootfs if it doesn't already exist 203 | if [ ! -f ${IMAGE_PATH} ]; then 204 | img="$(mktemp -u --suffix=.img)" 205 | img_mnt="$(mktemp -d)" 206 | img_bind_mnt="$(mktemp -d)" 207 | trap 'rm -f ${img}; sudo umount -l ${img_bind_mnt}; sudo umount -l ${img_mnt}; rmdir ${img_mnt} ${img_bind_mnt}' ERR 208 | # Image file creation 209 | qemu-img create ${img} 20G 210 | mkfs -t ext4 ${img} 211 | 212 | # Mounts (bind mounts for permission) 213 | mkdir -p ${img_mnt} ${img_bind_mnt} 214 | echo "password required to mount the rootfs:" 215 | sudo mount -o loop ${img} ${img_mnt} 216 | sudo bindfs --uid-offset=$(id -u) --gid-offset=$(id -g) \ 217 | --create-with-perms=0644,ud+X:gd-rwX:od-rwX ${img_mnt} ${img_bind_mnt} 218 | 219 | # Debian rootfs generation and config setting 220 | sudo mkosi --architecture=${MKOSI_TARGET_ARCH} --distribution=debian --release=unstable --output-dir=${img_mnt} --format=directory \ 221 | --package=ssh,acpid,acpi-support-base,gdb,systemtap,file,psmisc,strace,vim,bpftool,bpftrace,trace-cmd,linux-perf \ 222 | --package=apt,less,login,iputils-ping,iproute2,cron,e2fsprogs,systemd-sysv,cpio,dhcpd,fdisk,udev,man 223 | 224 | # Move mkosi-generated rootfs from ${img_mnt}/image to ${img_mnt} to match script's expected directory structure 225 | sudo mv ${img_mnt}/image/* ${img_mnt} && sudo rmdir ${img_mnt}/image 226 | 227 | echo "debian-vm" > ${img_bind_mnt}/etc/hostname 228 | echo "nameserver 8.8.8.8" > ${img_bind_mnt}/etc/resolv.conf 229 | echo "hostfs /host 9p trans=virtio,rw,nofail 0 0" > ${img_bind_mnt}/etc/fstab 230 | printf "[Match]\nName=en*\n[Network]\nDHCP=yes" > ${img_bind_mnt}/etc/systemd/network/80-dhcp.network 231 | sed -i 's~^ExecStart=.*~ExecStart=-/sbin/agetty --autologin root -o "-p -f root" --keep-baud 115200,57600,38400,9600 - $TERM~' ${img_bind_mnt}/lib/systemd/system/serial-getty@.service 232 | mkdir -p ${img_bind_mnt}/root/.ssh/ 233 | cp ${SSH_KEY}.pub ${img_bind_mnt}/root/.ssh/authorized_keys 234 | sudo chroot ${img_mnt} systemctl enable systemd-networkd acpid 235 | cat << EOF > ${img_bind_mnt}/sbin/init-minimal 236 | #!/bin/sh 237 | 238 | # Mount various important file systems 239 | mkdir -p /proc /sys /run/ /tmp /dev 240 | mount -t proc none /proc 241 | mount -t sysfs none /sys 242 | mount -t tmpfs none /run 243 | mount -t tmpfs none /tmp 244 | mount -t devtmpfs none /dev 245 | mkdir -p /dev/pts 246 | mount -t devpts none /dev/pts 247 | # And the content of /etc/fstab 248 | mount -a 249 | 250 | # Set the network interface up 251 | cat /etc/hostname > /proc/sys/kernel/hostname 252 | ip link set eth0 up 253 | dhclient eth0 254 | 255 | # Change cwd to /root 256 | HOME=/root 257 | cd $HOME 258 | 259 | # Start the SSH server 260 | mkdir /run/sshd/ 261 | /usr/sbin/sshd 262 | 263 | # Start the autostart script if there is one 264 | [ -f /usr/bin/autostart.sh ] && /usr/bin/autostart.sh & 265 | 266 | # Set up the serial line and get to a bash prompt 267 | setsid /sbin/getty -l /bin/bash -n 115200 ${SERIAL_TTY} 268 | EOF 269 | chmod +x ${img_bind_mnt}/sbin/init-minimal 270 | cat << EOF > ${img_bind_mnt}/etc/bash.bashrc 271 | # Use a green or red prompt depending on the previous command's exit value 272 | __prompt () { 273 | if [[ $? = "0" ]]; then 274 | PS1='\[\033[01;32m\]' 275 | else 276 | PS1='\[\033[01;31m\]' 277 | fi 278 | PS1="$PS1\u@\h:\w\$ \[\033[00m\]" 279 | } 280 | PROMPT_COMMAND=__prompt 281 | 282 | # On the serial tty, ask the host terminal for dimensions before each command 283 | __resize () { 284 | local escape r c 285 | IFS='[;' read -t 1 -sd R -p "$(printf '\e7\e[r\e[999;999H\e[6n\e8')" escape r c 286 | if [[ "$r" -gt 0 && "$c" -gt 0 ]]; then 287 | stty cols $c rows $r 288 | fi 289 | } 290 | if [[ $TERM = "vt102" ]]; then 291 | trap __resize DEBUG 292 | fi 293 | EOF 294 | 295 | # Atomically make the rootfs file available to unblock wait-for-vm tasks 296 | sync 297 | sudo umount -l ${img_bind_mnt} 298 | sudo umount -l ${img_mnt} 299 | mkdir -p "${IMAGE_DIR}" 300 | mv "${img}" "${IMAGE_PATH}" 301 | fi 302 | ;; 303 | "install-autostart") 304 | depend_on create-rootfs 305 | 306 | cd .vscode/autostart/ 307 | BUILT_AUTOSTART=${IMAGE_DIR}/autostart-${TARGET_ARCH} 308 | 309 | # The poor man's make. We use the last built /tmp/autostart to track if any 310 | # of the source file has changed. Only if one changed, rebuild and install. 311 | if [ ${BUILT_AUTOSTART} -nt autostart.c ] && \ 312 | [ ${BUILT_AUTOSTART} -nt autostart.sh ] && 313 | [ ${BUILT_AUTOSTART} -nt autostart.service ]; then 314 | echo "Autostart already up to date" 315 | exit 0 316 | fi 317 | 318 | clang --target=${CLANG_TARGET} -fuse-ld=lld `cat compile_flags.txt` autostart.c -o ${BUILT_AUTOSTART} 319 | 320 | echo Installing autostart on `basename ${IMAGE_PATH}` 321 | guestfish --rw -a "${IMAGE_PATH}" << EOF 322 | run 323 | mount /dev/sda / 324 | 325 | upload ${BUILT_AUTOSTART} /usr/bin/autostart 326 | chmod 755 /usr/bin/autostart 327 | 328 | upload autostart.sh /usr/bin/autostart.sh 329 | chmod 755 /usr/bin/autostart.sh 330 | 331 | upload autostart.service /lib/systemd/system/autostart.service 332 | ln-sf /lib/systemd/system/autostart.sh /etc/systemd/system/multi-user.target.wants/autostart.service 333 | EOF 334 | ;; 335 | "push") 336 | if [ "$#" -lt 2 ]; then 337 | echo "Usage: $0 push /file/to/push [/destination]" 338 | exit 1 339 | fi 340 | popd >/dev/null 341 | eval ${SCP_CMD} ${2} root@localhost:${3:-/root} 342 | ;; 343 | "pull") 344 | if [ "$#" -lt 2 ]; then 345 | echo "Usage: $0 pull /file/to/pull [/destination]" 346 | exit 1 347 | fi 348 | popd >/dev/null 349 | eval ${SCP_CMD} root@localhost:${2} ${3:-.} 350 | ;; 351 | "chroot") 352 | img_mnt="$(mktemp -d)" 353 | echo "password required to mount the rootfs:" 354 | sudo mount -o loop ${IMAGE_PATH} ${img_mnt} 355 | trap 'sudo umount -l ${img_mnt}; rmdir ${img_mnt}' EXIT 356 | sudo proot -S ${img_mnt} -w / ${PROOT_ARGS} 357 | ;; 358 | # BPF selftests 359 | "install-bpf-selftests") 360 | # Mount the poor man's sysroot 361 | ROOTFS_MOUNT_POINT=${HOME}/.linux-kernel-vscode/mnt 362 | echo "Mounting the VM's rootfs as a sysroot under ${ROOTFS_MOUNT_POINT}. If you miss any library, just install them in the VM:" 363 | echo " apt install libstdc++-12-dev libz-dev libelf-dev libcap-dev" 364 | mkdir -p ${ROOTFS_MOUNT_POINT} 365 | guestmount -a ${IMAGE_PATH} -m /dev/sda --ro -o dev ${ROOTFS_MOUNT_POINT} 366 | trap "guestunmount ${ROOTFS_MOUNT_POINT}" EXIT 367 | 368 | # Compile 369 | CLANG_CROSS_FLAGS="--target=${CLANG_TARGET} --sysroot=${ROOTFS_MOUNT_POINT}" \ 370 | eval ${MAKE} CROSS_COMPILE=${CLANG_TARGET}- SRCARCH=${TOOLS_SRCARCH} -C ${BPF_SELFTESTS_DIR} 371 | 372 | eval ${SCP_CMD} ${BPF_SELFTESTS_DIR}/test_progs root@localhost:/root 373 | ;; 374 | "run-bpf-selftests") 375 | depend_on install-bpf-selftests 376 | eval ${SSH_CMD} /root/test_progs 377 | ;; 378 | "run-bpf-selftest") 379 | if [ "$#" -ne 2 ]; then 380 | echo "Usage: $0 run-bpf-selftest selected_file" 381 | exit 1 382 | fi 383 | SELECTED_FILE=$2 384 | if [ `dirname ${SELECTED_FILE}` == ${BPF_SELFTESTS_DIR}/prog_tests ]; then 385 | depend_on install-bpf-selftests 386 | eval ${SSH_CMD} "/root/test_progs -t `basename ${SELECTED_FILE} .c`" 387 | else 388 | echo -e "\e[31mOpen a test in ${BPF_SELFTESTS_DIR}/prog_tests/\e[0m" 389 | fi 390 | ;; 391 | # Fuzzing 392 | "enable-kcov") 393 | depend_on defconfig 394 | if grep -q -F "CONFIG_KCOV=y" .config; then 395 | echo KCOV is already enabled 396 | else 397 | echo Enabling KCOV... 398 | scripts/config -e KCOV -e KCOV_ENABLE_COMPARISONS 399 | eval ${MAKE} ARCH=${TARGET_ARCH} olddefconfig 400 | 401 | echo Rebuilding the kernel with KCOV... 402 | ${SCRIPT} build 403 | fi 404 | ;; 405 | "fuzz") 406 | depend_on enable-kcov 407 | 408 | if [ ! -d "${SYZKALLER_DIR}" ] ; then 409 | git clone https://github.com/google/syzkaller ${SYZKALLER_DIR} 410 | fi 411 | make -C ${SYZKALLER_DIR} TARGETARCH=${SYZKALLER_TARGETARCH} manager fuzzer execprog executor 412 | 413 | cat > /tmp/syz-manager.cfg << EOF 414 | { 415 | "target": "linux/${SYZKALLER_TARGETARCH}", 416 | "http": "0.0.0.0:56741", 417 | "sshkey": "${SSH_KEY}", 418 | "workdir": "${SCRIPT_DIR}/syzkaller-workdir", 419 | "kernel_obj": "${WORKSPACE_DIR}", 420 | "syzkaller": "${SYZKALLER_DIR}", 421 | "type": "isolated", 422 | "reproduce": false, 423 | ${SYZ_MANAGER_CFG_EXTRA} 424 | "vm": { 425 | "targets": [ "127.0.0.1:5555" ], 426 | "target_dir": "/root/fuzzing/", 427 | "target_reboot": false 428 | } 429 | } 430 | EOF 431 | ${SYZKALLER_DIR}/bin/syz-manager -config /tmp/syz-manager.cfg 432 | ;; 433 | # Tracing 434 | "systemtap-build") 435 | if [ -f ${TRACER_PATH} ]; then 436 | echo Re-building ${TRACER_PATH} ... 437 | # Workaround the presence of mcount nops with PR15123_ASSUME_MFENTRY 438 | # Skip the loading part of the pipeline with -p4. Use Guru mode with -g 439 | # Workaround clang warnings (treated as errors) with -Wno-everything 440 | PR15123_ASSUME_MFENTRY=1 stap -p4 -g -r ${WORKSPACE_DIR} -m tracer \ 441 | -B LLVM=1 -B CFLAGS_MODULE="-Wno-everything" ${TRACER_PATH} > /dev/null 442 | # The guest doesn't know $WORKSPACE_DIR but it can hardcode /host/tmp/ 443 | echo Installing to /tmp/tracer.ko ... 444 | mv tracer.ko /tmp/ 445 | else 446 | rm -f /tmp/tracer.ko 447 | fi 448 | ;; 449 | # linux-kernel-vscode pull 450 | "update") 451 | cd .vscode 452 | 453 | trap "cp -r /tmp/local.sh /tmp/autostart ." EXIT 454 | cp local.sh /tmp/ 455 | cp -r autostart/ /tmp/ 456 | 457 | git checkout -- local.sh autostart/* 458 | git pull 459 | 460 | chmod u+x "${SCRIPT_DIR}/tasks.sh" 461 | # see comments in the .jsonnet file to understand this magic. 462 | if [ ! -e "settings.json" ]; then 463 | # Seed JSonnet with empty object 464 | echo "{}" > "settings.json" 465 | fi 466 | if [ ! -e "settings-extra.json" ]; then 467 | # Seed JSonnet with empty object 468 | echo "{}" > "settings-extra.json" 469 | fi 470 | tmp="$(mktemp --suffix=.json)" 471 | jsonnet settings.jsonnet \ 472 | --ext-code-file old_settings="settings.json" \ 473 | --ext-code-file extra_settings="settings-extra.json" > "${tmp}" 474 | mv "$tmp" settings.json 475 | ;; 476 | *) 477 | echo "Invalid command" 478 | ;; 479 | esac 480 | --------------------------------------------------------------------------------