forked from public/airgap
1
0
Fork 0

Compare commits

...

100 Commits

Author SHA1 Message Date
Ryan Heywood 75acac32a9
Release 2025.05.0 2025-05-15 00:33:15 -04:00
Anton Livaja bdc971a931
Merge remote-tracking branch 'origin/ryansquared/add-guestctl' 2025-05-14 19:12:21 -07:00
Anton Livaja da8e9b915b
Merge remote-tracking branch 'origin/ryansquared/update-hashes' 2025-05-14 19:11:53 -07:00
Ryan Heywood d7a0b6c5e5
Containerfile: add guestctl to host 2025-05-12 17:09:13 -04:00
Ryan Heywood 30fa06a5fb
update hashes, fix hash updater 2025-05-07 22:58:07 -04:00
Ryan Heywood 82c0d8e55a
Merge remote-tracking branch 'origin/iommu-net' 2025-05-01 17:33:19 -04:00
Anton Livaja 890e715e86
fix: remove unnecessary echo 2025-05-01 14:17:33 -07:00
Ryan Heywood 133a7c9b5b
Merge remote-tracking branch 'origin/iommu-net' 2025-05-01 16:45:27 -04:00
Anton Livaja 8722409004
fix: remove git hooks 2025-05-01 13:41:25 -07:00
Lance Vick 73ab8eae21
Merge branch 'main' into iommu-net 2025-05-01 13:21:18 -07:00
Anton Livaja 72efb86b6f
fix: rename from repros to airgap-guest 2025-05-01 10:51:19 -07:00
Anton Livaja 723ba49cd3
fix: add missint cmd 2025-05-01 09:16:11 -07:00
Anton Livaja c608ad5ccd
feat: add hot plugging for usb devices 2025-04-30 18:48:15 -07:00
Lance Vick 06010bea59
fix: add shell command to supported command list 2025-04-30 18:00:40 -07:00
Lance Vick d1229c0f45
feat: add netvm shell for raw shel access 2025-04-30 17:56:00 -07:00
Lance Vick 24a254a914
fix: overhaul socket buffer handling for far higher stability and blocking boot 2025-04-30 17:30:18 -07:00
Lance Vick bb2f87d471
fix: netvm start edge case handling 2025-04-30 00:24:52 -07:00
Lance Vick b980eb3a97
feat: add dhcpcd to netvm 2025-04-29 19:37:15 -07:00
Lance Vick 22469ca0b9
feat: block netvm start until qemu responds to pings 2025-04-29 19:36:58 -07:00
Lance Vick 3985d8ac19
feat: netvm start now auto-attaches network pci devices 2025-04-28 17:30:42 -07:00
Lance Vick ea07569187
feat: netvm push/pull support, fixed run, and lots of cleanup 2025-04-27 17:45:25 -07:00
Lance Vick 18fa25b87e
feat: initial qemu-ga based netvm command to control guest 2025-04-24 23:10:49 -07:00
Lance Vick b64d76b60d
wip 2025-04-15 13:07:41 -07:00
Ryan Heywood f967c2db49
Merge remote-tracking branch 'origin/pull/43/head' 2025-03-27 14:43:35 -04:00
Anton Livaja a11d544723
Merge branch 'release/2025.02.0' 2025-02-28 17:22:00 -05:00
Anton Livaja 03621ded78
release: add signature 2025-02-28 17:21:17 -05:00
Lance Vick e66f69ac46
release: 2025.02.0 2025-02-28 04:46:23 -08:00
Lance Vick dca180550e
maint: update to latest stagex 2025-02-28 04:26:59 -08:00
Anton Livaja a5b695c2af
remove whitespace 2025-02-17 04:29:17 -05:00
Anton Livaja c350dec98f
fix logging by adding /var/log 2025-02-17 04:27:45 -05:00
Anton Livaja acc7d0c416
fix syslogd 2025-02-17 03:41:47 -05:00
Anton Livaja bd15a10d23
change kernel log level to 7 2025-02-17 03:41:36 -05:00
Ryan Heywood 9f93bebd6a
Merge branch 'anton/fix-containerfile' 2025-02-17 02:59:37 -05:00
Anton Livaja 7f5d3a6275
remove duplicate import and fix as casing 2025-02-17 02:54:38 -05:00
Ryan Heywood 89ada7e795
Merge branch 'anton/set-kernel-log-level' 2025-02-17 02:19:11 -05:00
Anton Livaja 4fa6761729
set kernel log level to 3 2025-02-17 00:36:38 -05:00
Anton Livaja a224d4114e
Merge branch 'lance/set-xdg-runtime' 2025-02-11 02:14:33 -05:00
Lance Vick 5897a2fa5d
fix: set xdg_runtime_dir required by keyfork 2025-02-10 23:01:02 -08:00
Anton Livaja 06de2117dc
Merge branch 'lance/sqlite3' 2025-02-11 01:27:34 -05:00
Lance Vick 15926d8ec3
fix: add sqlite3 to fix sq 2025-02-10 22:11:29 -08:00
Anton Livaja f23195d573
Merge branch 'lance/efi-kvm-boot' 2025-02-10 23:45:31 -05:00
Anton Livaja 08f367edc6
Merge branch 'lance/add-sdtool' 2025-02-10 23:42:33 -05:00
Lance Vick 110f64cf54
feat: optional boot with kvm or efi 2025-02-10 16:31:14 -08:00
Lance Vick ba16f1ea50
feat: add sdtool to image 2025-02-10 16:29:32 -08:00
Lance Vick aa5b04e8a0
Merge remote-tracking branch 'origin/anton/fix-gpg-key-id' 2025-02-09 22:28:51 -08:00
Anton Livaja 238ca2ce41
fix readme with make reproduce command 2025-02-10 00:37:48 -05:00
Anton Livaja dad6fe859b
fix pgp key fetching and indentation 2025-02-10 00:37:23 -05:00
Anton Livaja 5612c59b9a
Merge branch 'lance/stagex-updates' 2025-02-10 00:27:34 -05:00
Lance Vick e2a8d2b8cb
feat: stagex updates w/ canokey smartcard emulation 2025-02-09 20:17:44 -08:00
Anton Livaja 13bedb1e73
Merge branch 'feat/hardware-comp-readme-update' 2025-01-03 15:00:53 -05:00
Anton Livaja 3b039317c9
add librem14 to tested hardware list 2024-12-18 07:53:09 -05:00
Anton Livaja b78da5c22a
add hardware compatibility section to readme 2024-12-06 12:06:50 -05:00
Sam Ebstein f25615bc97
rootfs/etc: removed the extra ::respawn:-/bin/bash line from the inittab configuration to resolve an issue where stdin to the shell was not working properly due to multiple console shells being spawned. 2024-10-15 10:26:02 -07:00
Sam Ebstein bb76f61615
Merge branch 'lance/fix-determinism' 2024-10-05 07:42:49 -07:00
Lance Vick 934fb903dd
fix: determinism on appended fat32 partition 2024-10-03 04:37:17 -07:00
Sam Ebstein 575967e5b4
Merge remote-tracking branch 'origin/tpm2vm' 2024-10-02 13:19:35 -07:00
Lance Vick 8db8dfc2a1
fix: build order in release 2024-10-02 13:12:10 -07:00
Lance Vick e75ac046e0
fix: stagex dep strings 2024-10-02 12:54:57 -07:00
Lance Vick d480d0a809
fix: make dep on out directory 2024-10-02 12:51:23 -07:00
Lance Vick 23cf93a8c2
maint: update stagex 2024-10-01 13:43:42 -07:00
Lance Vick 1f2abbaee9
feat: tpm2.0 support in 'make vm' 2024-09-28 12:25:12 -07:00
Lance Vick 6fa36e4e74
feat: 'make vm' runs in container 2024-09-28 04:52:27 -07:00
Lance Vick cac8bc947d
Merge remote-tracking branch 'origin/sam/add-user-partition' 2024-09-28 03:53:35 -07:00
Sam Ebstein d8dd960dd5
rootfs/usr/local/bin/autorun: adding autorun checks on new fat32 formatted USER partition 2024-09-25 10:16:34 -07:00
Sam Ebstein 8308101a35
Containerfile: creating a fat32 formatted third partition on airgap.iso
to allow for arbitrary user data.
2024-09-25 10:16:27 -07:00
Ryan Heywood 1f26de8fc1
Merge branch '2024.8.1' 2024-08-08 04:20:22 -04:00
Ryan Heywood 4ad5be07db
sign 2024.8.1 2024-08-08 04:18:41 -04:00
Lance Vick 657a3ff611
release: 2024.8.1 2024-08-08 01:13:02 -07:00
Lance Vick ea623cc147
Merge remote-tracking branch 'origin/ryansquared/bump-keyfork-v0.2.3' 2024-08-08 00:34:41 -07:00
Ryan Heywood 95ccf80fe8
Containerfile: bump stagex to include new keyfork version 2024-08-08 01:14:24 -04:00
Ryan Heywood 5904a22c80
add signatures for 2024.8.0 2024-08-04 20:16:21 -04:00
Anton Livaja 485fc58bfb
feat: add sig 2024-08-04 18:15:11 -04:00
Lance Vick e1c677bc06
add signature 2024-08-04 14:19:33 -07:00
Lance Vick dc8515ea02
release: 2024.8.0 2024-08-04 14:17:11 -07:00
Lance Vick 3cb460b72e
GIT_KEY GIT_PUBKEY 2024-08-04 13:29:39 -07:00
Lance Vick f1c0f2f8b5
working reproduction 2024-08-04 13:11:28 -07:00
Lance Vick 1f2ce99275
ignore additional folders 2024-08-04 13:10:24 -07:00
Lance Vick 721ffad1f0
cache/determinism fixes and doc updates 2024-08-03 15:52:30 -07:00
Lance Vick 74bf27bc66
Merge branch 'main' into stagex-rewrite 2024-08-02 22:15:34 -07:00
Lance Vick 44e18ea21b
fix default VERSION arg 2024-08-02 22:05:27 -07:00
Lance Vick a2a3cce64c
fix previous env import on reproduce 2024-08-02 21:58:30 -07:00
Lance Vick f0270a2862
default VERSION to development 2024-08-02 21:44:19 -07:00
Lance Vick 24725ea630
add initial release/reproduction/signing targets 2024-08-02 21:39:15 -07:00
Lance Vick 96ea9054f9
track dist/airgap.iso in lfs 2024-08-02 21:38:46 -07:00
Lance Vick 4676d9f889
hash lock all the things 2024-08-02 18:22:16 -07:00
Lance Vick d1707c48f1
docs: first pass of stagex doc fixes 2024-06-27 00:35:06 -07:00
Lance Vick 51ec4ca719
feat: working sd card automounting with via udev 2024-06-27 00:14:34 -07:00
Lance Vick f735b7e3af
Virtual sd card support 2024-06-26 00:46:56 -07:00
Lance Vick c20dedcc35
pcscd, udevd, and yubikeys working at boot 2024-06-20 20:42:57 -07:00
Lance Vick d737fce6ea
Working EFI/Bios Stagex boot 2024-06-18 01:45:21 -07:00
Lance Vick e886bc51fa
working vm-bios and vm-efi targets 2024-06-17 11:56:18 -07:00
Lance Vick fbdb919b7f
Second pass w/ hybrid grub/syslinux for efi/bios boot 2024-06-11 14:07:13 -07:00
Anton Livaja df223e6deb
fix: typo 2024-03-28 19:55:28 -04:00
Anton Livaja 1578b3c76d
chore: sign 2024.03.13 2024-03-28 18:56:12 -04:00
Anton Livaja 0af9d294a7
chore: clean up build section 2024-03-28 11:38:56 -04:00
Anton Livaja dc60d53fca
fix: typo 2024-03-28 11:28:27 -04:00
Ryan Heywood 16479807f1
sign 2024.03.13 2024-03-13 17:10:07 -04:00
Spencer Judd 38689b24b2
Release 2024.03.13 2024-03-13 14:32:10 -04:00
Lance Vick de0a962876
Merge remote-tracking branch 'origin/refs/pull/2/head' 2024-03-09 22:12:58 -08:00
Spencer Judd 7d9f87c976
Enable kernel webcam support
These four kernel config changes are sufficient to get the webcam
working on the Librem 14.
2024-03-09 22:55:26 -05:00
54 changed files with 1935 additions and 144 deletions

1
.gitattributes vendored
View File

@ -1 +1,2 @@
dist/*.iso filter=lfs diff=lfs merge=lfs -text
dist/airgap.iso filter=lfs diff=lfs merge=lfs -text

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
cache/
out/
out*/
.*

View File

@ -1,69 +1,357 @@
FROM stagex/busybox AS busybox
FROM stagex/musl AS musl
FROM stagex/xorriso AS xorriso
FROM stagex/syslinux AS syslinux
FROM stagex/cpio AS cpio
FROM stagex/linux-airgap AS linux
FROM stagex/mtools AS mtools
FROM stagex/dosfstools AS dosfstools
FROM stagex/user-alsa-lib@sha256:eeaee84f8012865bb33d68287bccfddc6fd04e9082687b8c31008dd07b8e07b8 AS user-alsa-lib
FROM stagex/core-bash@sha256:ae47fcd4247bef0ca4af762a76cb8871a5c868472cab67eed829a55364a8f1fa AS core-bash
FROM stagex/core-bc@sha256:03e1c729223e9d45f087660f65034b4f6fac91aefb94fb7ccbc85d1ab7e88c1d AS core-bc
FROM stagex/core-busybox@sha256:cac5d773db1c69b832d022c469ccf5f52daf223b91166e6866d42d6983a3b374 AS core-busybox
FROM stagex/user-ccid@sha256:313259fb6b059179ff69f4189c57d98b8d468ebf17f14c6f431d7001c8801e1c AS user-ccid
FROM stagex/user-cpio@sha256:2695e1b42f93ec3ea0545e270f0fda4adca3cb48d0526da01954efae1bce95c4 AS user-cpio
FROM stagex/core-curl@sha256:63a5963a4e7852b5482824953d18ea73c7d192fed654eb1236f8b97a6f67cbcc AS core-curl
FROM stagex/user-dtc@sha256:3877063ca1068d48e0b92fcdf5083b707e009e96a6db4bd3536924c9f440cb08 AS user-dtc
FROM stagex/user-eudev@sha256:709f6f949e93a3a91770b7323fd87eec52714677e4bed88954cadd60506cbce3 AS user-eudev
FROM stagex/user-flashtools@sha256:f3524d889e9476acbe268b289a3e43f5766da9d3d999009b0bb8e6bddcd9dc5c AS user-flashtools
FROM stagex/core-gcc@sha256:125bd6306e7f37e57d377d5a189c0e499388aff42b22cc79acee6097357c617f AS core-gcc
FROM stagex/user-glib@sha256:41fb9409b0bea2421feaee788c88efcf2778f2008634dde00b50f2b6afd2ed11 AS user-glib
FROM stagex/core-gmp@sha256:4387f9389ef656ef2305719ac1dbcc3d92631deb816da4c7101c0bdc75e57564 AS core-gmp
FROM stagex/user-gpg@sha256:92946bb4143ecbd53999cd520fbcb958aecacbac7a85bd58a758be1b57086a9c AS user-gpg
FROM stagex/user-grub@sha256:f3c9ff298c02ee3349496c3b5520079bbd115af0a347525410ba6a34170d4b4c AS user-grub
FROM stagex/user-icepick@sha256:9d2e986a081fa7724dca2397dcd9b17fd2f6221d9c06d44f574625cb36038634 AS user-icepick
FROM stagex/user-ipxe@sha256:b98dea039f0a14a614f035d848d9cfa8b9ad472e6dc24b2e3099f2f8ae209abe AS user-ipxe
FROM stagex/user-jq@sha256:ced6213c21b570dde1077ef49966b64cbf83890859eff83f33c82620520b563e AS user-jq
FROM stagex/user-keyfork@sha256:2075687c9a060f5eee89b6a4b5eecec6727afe3d241648b42be225170df0f8e0 AS user-keyfork
FROM stagex/user-libaio@sha256:3e21cfd5dc07a7300546e4896a81628741c23c4728a68d36e0bb3d8a096f7742 AS user-libaio
FROM stagex/user-libassuan@sha256:dea35799659be7b85e523312c55621007b1918ff3590631155ecf2c699ca470f AS user-libassuan
FROM stagex/core-libffi@sha256:9acd18e59ca11fa727670725e69a976d96f85a00704dea6ad07870bff2bd4e8b AS core-libffi
FROM stagex/user-libgcrypt@sha256:384f0e703afad6f8885ec77fb814ef182a08600a2032183d231fee5c048a7d2d AS user-libgcrypt
FROM stagex/user-libgpg-error@sha256:6d7c09e3a7d055a6722910439c533f2babc8eda24b636bf4dfb2b29a3ed6327a AS user-libgpg-error
FROM stagex/user-libksba@sha256:c165fb5b7949473cb00b0fe59add90663346b33c6c682309ca0fcccdcf78d569 AS user-libksba
FROM stagex/user-libqrencode@sha256:e99d9a71dffb399dbe3af8c16c473f10368c3fb787d72623bdc42c7fa770a33a AS user-libqrencode
FROM stagex/user-libseccomp@sha256:7a397b5261c24aa745fe9158499e0db1ba21df415354bbbe77c90a6a3fd4c517 AS user-libseccomp
FROM stagex/user-libslirp@sha256:e72ebf587c366e1d0a9a42c74216dd2b9f560d52df3eb8148a2e31821415b082 AS user-libslirp
FROM stagex/user-libtpms@sha256:3fde6f85f3ce637b3d7b98e4fc74c2c57d31adf9c9ca068b3826eb7ebf16f5ba AS user-libtpms
FROM stagex/core-libunwind@sha256:4f3ead61255c1e58e7dc43a33043f297f8730ec88e068a4460e5fff09e503781 AS core-libunwind
FROM stagex/user-libusb@sha256:53d499555164f12d9e87118a6d44e1d07f0b1cc9081a29eb66975662be818a00 AS user-libusb
FROM stagex/user-libzbar@sha256:8b4ec291f772a10f372c538180f889a46837f2dd97756d1949c5c86111241fa9 AS user-libzbar
FROM stagex/core-libzstd@sha256:35ae8f0433cf1472f8fb25e74dc631723e9f458ca3e9544976beb724690adea8 AS core-libzstd
FROM stagex/user-lzo@sha256:9d141a7686fbb027366df80d4f254fb13f4c4524ba4d5cff6ea176b0b4c36cd5 AS user-lzo
FROM stagex/user-mtools@sha256:023169be123693e326d2fd97739fe0efa19638ce616cbcc52476e6f14f0a83cc AS user-mtools
FROM stagex/core-musl@sha256:d5f86324920cfc7fc34f0163502784b73161543ba0a312030a3ddff3ef8ab2f8 AS core-musl
FROM stagex/user-nettle@sha256:249bec1a4273f6461b39ef849d1d8b4ec2d4a3693930f9147cee6c37eef0794a AS user-nettle
FROM stagex/user-npth@sha256:6ac9a90ca714ba01911c1f617553a5b23b96e9e37ec4a21e5ba132c4886a70e9 AS user-npth
FROM stagex/user-numactl@sha256:4046b643293cf9e82f1d29e92c61f0b12210b65987711ddd7c6813f27f3c1bfd AS user-numactl
FROM stagex/user-openpgp-card-tools@sha256:369c13ba0a772b1aef31321c0ebbb2a6fcd512491ace003e48c6f18f258905cc AS user-openpgp-card-tools
FROM stagex/user-opensc@sha256:f8a1b5d07b6b594b964b63a2572fd10b44e79c3699efb97dfefc2f1dde054a6c AS user-opensc
FROM stagex/core-openssl@sha256:8670a22fb76965f31bda1b61cd75ae39a96e1008deffe289a5d94ee4337b1cb2 AS core-openssl
FROM stagex/user-pcsc-lite@sha256:0f06c2e73fabc6f9484bb39362d4084a45ffe88c862764813a62a75840b10cfc AS user-pcsc-lite
FROM stagex/user-pcsc-tools@sha256:366867b9c29664264224db7651b710cd70761b67c41ce9c27b9d2829e18b5a30 AS user-pcsc-tools
FROM stagex/user-qemu@sha256:45b6d58b55a4c7d616da985d29482f2892540d815a90ed175e53b1c1b172497e AS user-qemu
FROM stagex/user-canokey-qemu@sha256:3f949f099194d2b721914d9d308c699818f83833b07db1d2e504ee16bfdfa348 AS user-canokey-qemu
FROM stagex/user-sdtool@sha256:f4be5c2fe87fa3dd8742f91be5a368b6833ceb7156d33192e5339869629aa06a AS user-sdtool
FROM stagex/user-seabios@sha256:4adf4c3f70a6c69cb1c925a832363547cfb73ef5a7d75ff65885624916aace90 AS user-seabios
FROM stagex/user-sops@sha256:72b09ff439f422889af815f19a223b48b3b3fd0701d312a413069cbabcad7a12 AS user-sops
FROM stagex/core-zlib@sha256:b35b643642153b1620093cfe2963f5fa8e4d194fb2344a5786da5717018976c2 AS core-zlib
FROM stagex/user-sequoia-sq@sha256:b7197adb937e3ee0fc8e8edc041acb836da9b2958cbe4bb3b1797b73b50205f7 AS user-sequoia-sq
FROM stagex/user-sequoia-sq-wot@sha256:7e914c221d65a4cda9683591082e9f5c70d8d31d6a415c1b98e75f4d89f985c5 AS user-sequoia-sq-wot
FROM stagex/core-sqlite3@sha256:3c9318b8fae8471113a229f12cb8956cf8b0119177997ba69c4ead5e97efcdf4 AS core-sqlite3
FROM stagex/user-swtpm@sha256:fc72e5089c08476cfbfd863daf80b3ea86016c27f5c5cf8d497baf9aa0d23a78 AS user-swtpm
FROM stagex/user-syslinux@sha256:6a92128218d68d25d6e10a534776473d805923a318cccb303555f730c7b7410e AS user-syslinux
FROM stagex/user-tpm2-tools@sha256:f25049635ae36e17281c651e0fd6d949abc407185c1013887a0d4feab09ababf AS user-tpm2-tools
FROM stagex/user-tpm2-tss@sha256:58f4d393d6b51746a464ad4eb4a13867c8323c175e0798de9d27be171a088cfa AS user-tpm2-tss
FROM stagex/user-util-linux@sha256:ec5ec2dfd1803dc897a9c0589f12e7ccff3058be4048af3076ff33069f993dd8 AS user-util-linux
FROM stagex/user-xorriso@sha256:6649dab95928e8eeb0199f7bd27852e6fa2682949f3c8f2b7a03978a5ff15b10 AS user-xorriso
FROM stagex/core-xz@sha256:75b657032c8a47eabc3805bae944302c3eeab524e853d6d209285d4347cba0c7 AS core-xz
FROM stagex/user-yq@sha256:ce99f60d83a85fc6db249c141b39af68335bd45b066f2586d39fe111725c6730 AS user-yq
FROM stagex/user-edk2@sha256:db24be51d35117d264dccfc44f0ca331f59d738083170cd9bb86b49a5c06abff AS user-edk2
FROM stagex/core-ca-certificates@sha256:d6fca6c0080e8e5360cd85fc1c4bd3eab71ce626f40602e38488bfd61fd3e89d AS core-ca-certificates
FROM stagex/user-linux-guest-net@sha256:994b6fe49dd4331b32b0854055bff31b06db5eabdeafb32b2c0d55465b7ccf45 AS user-linux-guest-net
FROM stagex/user-linux-airgap@sha256:4f163e5f1f09f87d8f0fcf060193345f0b4dd8dbff2a2b2aec1cd4c254a628ca AS user-linux-airgap
FROM stagex/user-libimobiledevice-glue@sha256:3ce674285cbc04b694b7e400703868fcaac65401f2f2ca2aa2b720b3e0efee3c AS user-libimobiledevice-glue
FROM stagex/user-libimobiledevice@sha256:fcda68bdc397213fa76bd893472a304b093522aaac28e36f458275b93bb1af34 AS user-libimobiledevice
FROM stagex/user-libplist@sha256:2d776cb4eca3689a8bd6ac755a23f492850bf6c7b0c72e3525db6135e4d6e0bc AS user-libplist
FROM stagex/user-libusbmuxd@sha256:1e97f0a2ede0ee5fac9b056d0395e12b77c9f0bf550f9d0c20734ce0617eb51f AS user-libusbmuxd
FROM stagex/user-usbmuxd@sha256:90f687d2368328b76141badc382a21873a5b44d4ddccf851c017caf1e78af418 AS user-usbmuxd
FROM stagex/user-socat@sha256:990a70ae13462d8ba0a925fe959dd83070cbecdb3f91ff145caca5232171f3b8 AS user-socat
FROM stagex/user-dhcpcd@sha256:60bd86d9e2fcb6341c1efaeda5d786b63ff92e9d0c729cd8f634a20ff54ee71e AS user-dhcpcd
FROM stagex/user-guestctl@sha256:95ad9e34a003c7d1d01f5d427b5f79d2430f6e6634debde8e54f9a6f08749704 AS user-guestctl
FROM scratch AS base
COPY --from=busybox . /
COPY --from=musl . /
COPY --from=xorriso . /
COPY --from=cpio . /
COPY --from=mtools . /
COPY --from=linux . /
COPY --from=dosfstools . /
COPY --from=syslinux . /
ARG VERSION development
ARG GIT_TIMESTAMP null
ARG GIT_AUTHOR null
ARG GIT_REF null
ARG GIT_PUBKEY null
COPY --from=core-busybox . /
COPY --from=core-musl . /
COPY --from=core-xz . /
COPY --from=user-xorriso . /
COPY --from=user-cpio . /
COPY --from=user-mtools . /
COPY --from=user-grub . /
FROM base AS build
COPY --from=linux /bzImage /iso/boot/bzImage
COPY --from=stagex/busybox . initramfs
COPY --chmod=0755 <<-EOF initramfs/init
#!/bin/sh
/bin/sh
EOF
RUN cd initramfs && find . | cpio -o -H newc | gzip -9 > /iso/boot/init.gz
COPY <<-EOF iso/isolinux/isolinux.cfg
DEFAULT linux
LABEL linux
KERNEL boot/bzImage
APPEND initrd=boot/init.gz
EOF
COPY --from=syslinux /usr/share/syslinux/isolinux.bin iso/isolinux/
COPY --from=syslinux /usr/share/syslinux/ldlinux.c32 iso/isolinux/
FROM base AS dev
COPY --from=core-gcc . /
COPY --from=core-zlib . /
COPY --from=user-glib . /
COPY --from=user-alsa-lib . /
COPY --from=user-lzo . /
COPY --from=user-dtc . /
COPY --from=user-numactl . /
COPY --from=user-libaio . /
COPY --from=user-libseccomp . /
COPY --from=core-libffi . /
COPY --from=core-libzstd . /
COPY --from=user-libslirp . /
COPY --from=user-seabios . /
COPY --from=user-ipxe . /
COPY --from=user-qemu . /
COPY --from=user-canokey-qemu . /
COPY --from=user-swtpm . /
COPY --from=core-openssl . /
COPY --from=core-curl . /
COPY --from=user-libtpms . /
COPY --from=user-tpm2-tss . /
COPY --from=user-tpm2-tools . /
COPY --from=user-edk2 . /
FROM base AS build-guest
COPY --from=user-linux-guest-net /bzImage iso/boot/vmlinuz
COPY --from=core-busybox . initramfs
COPY --from=user-eudev . initramfs
COPY --from=core-musl . initramfs
COPY --from=core-zlib . initramfs
COPY --from=core-openssl . initramfs
COPY --from=core-ca-certificates . initramfs
COPY --from=user-linux-guest-net . initramfs
COPY --from=user-linux-airgap . initramfs
COPY --from=user-libimobiledevice-glue . initramfs
COPY --from=user-libimobiledevice . initramfs
COPY --from=user-libplist . initramfs
COPY --from=user-libusb . initramfs
COPY --from=user-libusbmuxd . initramfs
COPY --from=core-gcc /usr/lib/. initramfs/usr/lib/
COPY --from=user-usbmuxd . initramfs
COPY --from=user-glib . initramfs
COPY --from=user-numactl . initramfs
COPY --from=user-dhcpcd . initramfs
COPY --from=user-qemu /usr/bin/qemu-ga initramfs/usr/bin/
COPY --from=core-curl . initramfs
COPY src/guest/rootfs/ initramfs
RUN <<-EOF
set -eux
mkdir -p iso/efi
truncate -s $((10796+128+128))k iso/efi/esp.img
mkfs.fat -F 16 -f 1 -M 0xF0 -r 112 -R 1 iso/efi/esp.img
mmd -i iso/efi/esp.img ::boot
mcopy -i iso/efi/esp.img iso/boot/bzImage ::boot/bzImage
mcopy -i iso/efi/esp.img iso/boot/init.gz ::boot/init.gz
mmd -i iso/efi/esp.img ::syslinux
mcopy -i iso/efi/esp.img iso/isolinux/isolinux.cfg ::syslinux/syslinux.cfg
mcopy -i iso/efi/esp.img /usr/share/syslinux/efi64/ldlinux.e64 ::syslinux/ldlinux.e64
mmd -i iso/efi/esp.img ::efi
mmd -i iso/efi/esp.img ::efi/boot
mcopy -i iso/efi/esp.img /usr/share/syslinux/efi64/syslinux.efi ::efi/boot/boot64.efi
ls -Rlah iso
cd initramfs
mkdir -p home/git
chmod 755 home
chown -R 1000:1000 home/git
find . -exec touch -hcd "@0" "{}" +
find . -print0 \
| sort -z \
| cpio \
--null \
--create \
--verbose \
--reproducible \
--format=newc \
| gzip --best \
> ../iso/boot/initramfs
EOF
COPY src/guest/config/syslinux.cfg iso/boot/syslinux/
COPY --from=user-syslinux \
/usr/share/syslinux/isohdpfx.bin \
/usr/share/syslinux/isolinux.bin \
/usr/share/syslinux/ldlinux.c32 \
/usr/share/syslinux/libutil.c32 \
/usr/share/syslinux/libcom32.c32 \
/usr/share/syslinux/mboot.c32 \
iso/boot/syslinux/
ENV SOURCE_DATE_EPOCH=1
RUN <<-EOF
set -eux
find iso -exec touch -hcd "@0" "{}" +
xorrisofs \
-output guest.img \
-full-iso9660-filenames \
-joliet \
-rational-rock \
-sysid LINUX \
-volid "airgap-guest" \
-isohybrid-mbr iso/boot/syslinux/isohdpfx.bin \
-eltorito-boot boot/syslinux/isolinux.bin \
-eltorito-catalog boot/syslinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-no-emul-boot \
-isohybrid-gpt-basdat \
-follow-links \
iso/
EOF
FROM base AS build
COPY --from=user-linux-airgap /bzImage iso/boot/vmlinuz
COPY --from=build-guest /guest.img initramfs/
COPY --from=core-busybox . initramfs
COPY --from=user-eudev . initramfs
COPY --from=core-musl . initramfs
COPY --from=core-zlib . initramfs
COPY --from=user-npth . initramfs
COPY --from=user-libksba . initramfs
COPY --from=user-libgpg-error . initramfs
COPY --from=user-libassuan . initramfs
COPY --from=user-libgcrypt . initramfs
COPY --from=core-bash . initramfs
COPY --from=user-gpg . initramfs
COPY --from=user-jq . initramfs
COPY --from=user-yq . initramfs
COPY --from=core-bc . initramfs
COPY --from=user-flashtools . initramfs
COPY --from=core-curl . initramfs
COPY --from=user-tpm2-tools . initramfs
COPY --from=user-tpm2-tss . initramfs
COPY --from=core-openssl . initramfs
COPY --from=user-libusb . initramfs
COPY --from=user-ccid . initramfs
COPY --from=user-pcsc-lite . initramfs
COPY --from=user-pcsc-tools . initramfs
COPY --from=user-libqrencode . initramfs
COPY --from=core-gmp . initramfs
COPY --from=core-libunwind . initramfs
COPY --from=user-nettle . initramfs
COPY --from=user-opensc . initramfs
COPY --from=user-util-linux . initramfs
COPY --from=user-sops . initramfs
COPY --from=core-gcc /usr/lib/. initramfs/usr/lib/
COPY --from=core-sqlite3 . initramfs
COPY --from=user-sdtool . initramfs
RUN chmod +x initramfs/usr/bin/sdtool
COPY --from=user-openpgp-card-tools . initramfs
COPY --from=user-sequoia-sq . initramfs
COPY --from=user-sequoia-sq-wot . initramfs
COPY --from=user-libslirp . initramfs
COPY --from=user-seabios . initramfs
COPY --from=user-ipxe . initramfs
COPY --from=user-glib . initramfs
COPY --from=user-numactl . initramfs
COPY --from=core-libzstd . initramfs
COPY --from=user-alsa-lib . initramfs
COPY --from=user-lzo . initramfs
COPY --from=user-dtc . initramfs
COPY --from=user-libaio . initramfs
COPY --from=user-libseccomp . initramfs
COPY --from=core-libffi . initramfs
COPY --from=core-libzstd . initramfs
COPY --from=user-libslirp . initramfs
COPY --from=user-seabios . initramfs
COPY --from=user-canokey-qemu . initramfs
COPY --from=user-qemu . initramfs
COPY --from=user-socat . initramfs
COPY --from=user-libzbar . initramfs
COPY --from=user-keyfork . initramfs
COPY --from=user-icepick . initramfs
COPY --from=user-guestctl . initramfs
COPY src/host/rootfs/ initramfs
COPY <<-EOF initramfs/etc/environment
export VERSION="$VERSION"
export GIT_TIMESTAMP="$GIT_TIMESTAMP"
export GIT_AUTHOR="$GIT_AUTHOR"
export GIT_REF="$GIT_REF"
export GIT_PUBKEY="$GIT_PUBKEY"
EOF
RUN <<-EOF
set -eux
cd initramfs
find . -exec touch -hcd "@0" "{}" +
find . -print0 \
| sort -z \
| cpio \
--null \
--create \
--verbose \
--reproducible \
--format=newc \
| gzip --best \
> ../iso/boot/initramfs
EOF
## Grub (EFI Boot)
COPY src/host/config/grub.cfg iso/boot/grub/grub.cfg
COPY src/host/config/grub_early.cfg grub_early.cfg
RUN <<-EOF
set -eux
mkdir -p efi/boot
grub-mkimage \
--config="grub_early.cfg" \
--prefix="/boot/grub" \
--output="efi/boot/bootx64.efi" \
--format="x86_64-efi" \
--compression="xz" \
all_video \
disk \
part_gpt \
part_msdos \
linux \
normal \
configfile \
search \
search_label \
efi_gop \
fat \
iso9660 \
gzio \
serial \
terminal
find efi -exec touch -hcd "@0" "{}" +
mformat -i iso/boot/grub/efi.img -C -f 1440 -N 0 ::
mcopy -i iso/boot/grub/efi.img -ms efi ::
touch -md "@0" iso/boot/grub/efi.img
EOF
## Syslinux (BIOS Boot)
COPY src/host/config/syslinux.cfg iso/boot/syslinux/
COPY --from=user-syslinux \
/usr/share/syslinux/isohdpfx.bin \
/usr/share/syslinux/isolinux.bin \
/usr/share/syslinux/ldlinux.c32 \
/usr/share/syslinux/libutil.c32 \
/usr/share/syslinux/libcom32.c32 \
/usr/share/syslinux/mboot.c32 \
iso/boot/syslinux/
ENV SOURCE_DATE_EPOCH=1
RUN <<-EOF
set -eux
dd if=/dev/zero bs=1M count=10 >> user.img
mformat -v user -i user.img -N 0 ::
find iso -exec touch -hcd "@0" "{}" +
xorrisofs \
-output airgap.iso \
-full-iso9660-filenames \
-joliet \
-rational-rock \
-sysid LINUX \
-volid "airgap" \
-isohybrid-mbr iso/boot/syslinux/isohdpfx.bin \
-eltorito-boot boot/syslinux/isolinux.bin \
-eltorito-catalog boot/syslinux/boot.cat \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot \
-e boot/grub/efi.img \
-no-emul-boot \
-isohybrid-gpt-basdat \
-follow-links \
-append_partition 3 0xb user.img \
iso/
EOF
## Minimal Autorun SD card image
COPY sdcard sdcard
RUN <<-EOF
set -eux
dd if=/dev/zero of=sdcard.img bs=1M count=32
mformat -v external -i sdcard.img ::
mcopy -i sdcard.img -s sdcard/* ::
EOF
FROM build AS install
RUN xorriso \
-as mkisofs \
-output airgap.iso \
-eltorito-boot isolinux/isolinux.bin \
-no-emul-boot \
-boot-load-size 4 \
-boot-info-table \
-eltorito-alt-boot \
-eltorito-platform efi \
-eltorito-boot efi/esp.img \
-no-emul-boot \
-eltorito-catalog isolinux/boot.cat \
iso
#RUN isohybrid airgap.iso
FROM scratch AS package
COPY --from=install /airgap.iso /
COPY --from=build /sdcard.img /
COPY --from=build /airgap.iso /

157
Makefile
View File

@ -1,21 +1,150 @@
VERSION := development
GIT_REF := $(shell git log -1 --format=%H)
GIT_AUTHOR := $(shell git log -1 --format=%an)
GIT_PUBKEY := $(shell git log -1 --format=%GK)
GIT_TIMESTAMP := $(shell git log -1 --format=%cd --date=iso)
EFI := false
,:=,
export
## Use env vars from latest release when reproducing
ifdef REPRODUCE
include dist/release.env
export
endif
## Prevents use of caching when building docker image
ifdef NOCACHE
NO_CACHE := --no-cache
endif
.DEFAULT_GOAL :=
.PHONY: default
default: \
$(OUT_DIR)/airgap.iso
out/release.env \
out/manifest.txt \
out/airgap.iso
.PHONY: vm
vm:
$(call toolchain,$(USER)," \
qemu-system-i386 \
-M pc \
-nographic \
-cdrom "$(OUT_DIR)/airgap.iso"; \
")
## Primary targets
$(OUT_DIR)/airgap.iso: \
$(FETCH_DIR)/buildroot
out/airgap.iso: Containerfile $(shell git ls-files rootfs)
SOURCE_DATE_EPOCH=1 \
docker build \
--progress=plain \
--output type=oci,tar=false,force-compression=true,name=airgap,dest=airgap \
. \
-f Containerfile
--output type=local,rewrite-timestamp=true,dest=out \
--build-arg SOURCE_DATE_EPOCH=1 \
--build-arg VERSION="$(VERSION)" \
--build-arg GIT_REF="$(GIT_REF)" \
--build-arg GIT_AUTHOR="$(GIT_AUTHOR)" \
--build-arg GIT_PUBKEY="$(GIT_PUBKEY)" \
--build-arg GIT_TIMESTAMP="$(GIT_TIMESTAMP)" \
$(NO_CACHE) \
-f Containerfile \
.
## Development Targets
out/dev-shell.digest: Containerfile | out
docker build --target dev -f Containerfile -q . > $@
.PHONY: shell
shell: out/dev-shell.digest
docker run -it $(shell cat $<) /bin/sh
.PHONY: vm
vm: out/dev-shell.digest out/airgap.iso out/sdcard.img
docker run -it -v ./out:/out $(shell cat $<) sh -c "\
swtpm socket \
--tpmstate dir=. \
--ctrl type=unixio,path=vtpm-sock \
--tpm2 & \
qemu-system-x86_64 \
-m 4G \
-machine q35,kernel-irqchip=split \
-chardev socket,id=chrtpm,path=vtpm-sock \
-usb -device canokey,file=/out/canokey-file \
-tpmdev emulator,id=tpm0,chardev=chrtpm \
-device tpm-tis,tpmdev=tpm0 \
-usb \
-device sdhci-pci \
-device sd-card,drive=external \
-drive id=external,if=none,format=raw,file=out/sdcard.img \
-device usb-storage,drive=usbdrive \
-device intel-iommu,intremap=on \
-netdev user,id=net0 \
-device e1000,netdev=net0 \
-chardev socket,path=out/qga.sock,server=on,wait=off,id=qga0 \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 \
$(if $(filter $(EFI),true) ,\
-bios /usr/share/ovmf/OVMF.fd \
-drive id=boot$(,)if=virtio$(,)format=raw$(,)file=out/airgap.iso \
,\
-drive id=usbdrive,if=none,format=raw,file=out/airgap.iso \
-boot order=c \
) \
$(if (,$(wildcard /dev/kvm)),,-cpu host --accel kvm) \
-nographic; \
"
## Release, Signing, Verification, and Reproduction Targets
.PHONY: clean
clean:
rm -rf out
.PHONY: update
update:
python3 src/update.py
.PHONY: release
release: clean
$(MAKE) NOCACHE=1 VERSION=$(VERSION)
rm -rf dist/*
cp -R out/release.env out/airgap.iso out/manifest.txt dist/
.PHONY: sign
sign:
set -e; \
git config --get user.signingkey 2>&1 >/dev/null || { \
echo "Error: git user.signingkey is not defined"; \
exit 1; \
}; \
fingerprint=$$(\
git config --get user.signingkey \
| sed 's/.*\([A-Z0-9]\{16\}\).*/\1/g' \
); \
gpg --armor \
--detach-sig \
--output dist/manifest.$${fingerprint}.asc \
dist/manifest.txt
.PHONY: verify
verify: | dist/manifest.txt
set -e; \
for file in dist/manifest.*.asc; do \
echo "\nVerifying: $${file}\n"; \
gpg --verify $${file} dist/manifest.txt; \
done;
.PHONY: reproduce
reproduce: clean | out
$(MAKE) REPRODUCE=true NOCACHE=1
diff -q out/manifest.txt dist/manifest.txt;
out:
mkdir -p $@
out/release.env: $(shell git ls-files) | out
echo 'VERSION=$(VERSION)' > out/release.env
echo 'GIT_REF=$(GIT_REF)' >> out/release.env
echo 'GIT_AUTHOR=$(GIT_AUTHOR)' >> out/release.env
echo 'GIT_PUBKEY=$(GIT_PUBKEY)' >> out/release.env
echo 'GIT_TIMESTAMP=$(GIT_TIMESTAMP)' >> out/release.env
out/manifest.txt: out/airgap.iso out/release.env | out
openssl sha256 -r \
out/airgap.iso \
out/release.env \
| sed -e 's/ \*out\// /g' -e 's/ \.\// /g' \
> $@

100
README.md
View File

@ -1,24 +1,26 @@
# AirgapOS #
<https://github.com/distrust-foundation/airgap>
<https://git.distrust.co/public/airgap>
## About ##
A live buildroot based Liux distribution designed for managing secrets offline.
A full-source-bootstrapped, deterministic, minimal, immutable, and offline,
workstation linux distribution designed for creating and managing secrets
offline.
Built for those of us that want to be -really- sure our most important secrets
are managed in a clean environment with an "air gap" between us and the
internet with high integrity on the supply chain of the firmware and OS used.
## Uses ##
* Generate GPG keychain
* Generate PGP keychain
* Store/Restore gpg keychain to security token such as a Yubikey or Nitrokey
* Signing cryptocurrency transactions
* Generate/backup BIP39 universal cryptocurrency wallet seed
* Store/Restore BIP39 seed to a hardware wallet such as a Trezor or Ledger
## Features ##
* Determinsitic iso generation for multi-party code->binary verification
* Deterministic iso generation for multi-party code->binary verification
* Small footprint (< 100MB)
* Immutable and Diskless: runs from initramfs
* Network support and most drivers removed to minimize exfiltration vectors
@ -27,37 +29,54 @@ internet with high integrity on the supply chain of the firmware and OS used.
### Software ###
* docker 18+
* docker 26+
### Hardware ###
* Recommended: PC running coreboot-heads
* Allows for signed builds, and verification of signed sd card payloads
* Ensure any Wifi/Disk/Bluetooth/Audio devices are disabled/removed
* Supported remote attestation key (Librem Key, Nitrokey, etc)
* Supported GPG smartcard device (Yubikey, Ledger, Trezor, Librem Key, etc)
* x86_64 PC or laptop
* linuxboot/heads firmware supported and recommended for multi-use machine
* Allows for signed builds, and verification of signed sd card payloads
* Ensure any Wifi/Disk/Bluetooth/Audio devices are disabled/removed
* Blank flash drive
* Blank SD card
## Build ##
### Update git submodules
```
git submodule update --init --recursive
```
### Build a new release
```
make release
```
```
make release
```
### Reproduce an existing release
```
make attest
```
```
make reproduce
```
### Sign an existing release
```
make sign
```
```
make sign
```
## Provisioning ##
1. Write airgap.iso to CD-ROM or SD Card
a. `dd if=out/airgap.iso of=/dev/sda bs=1M conv=sync status=progress`
b. `cdrecord out/airgap.iso`
2. Verify media still produces expected hash
```
sha256sum out/airgap.iso
head -c $(stat -c '%s' airgap.iso) /dev/sda | sha256sum
```
## Setup ##
@ -109,3 +128,46 @@ make vm
```
make shell
```
## Hardware Compatibility ##
### Tested Models
* Purism Librem 14
* HP 13" Intel Celeron - 4GB Memory - 64GB eMMC, HP 14-dq0052dx, SKU: 6499749, UPC: 196548430192, DCS: 6.768.5321, ~USD $179.99
* Lenovo 14" Flex 5i FHD Touchscreen 2-in-1 Laptop - Intel Core i3-1215U - 8GB Memory - Intel UHD Graphics, SKU: 6571565, ~USD $379.99
### Disabling Secure Boot
AirgapOS can't be booted using secure boot. Therefore it has to be disabled. Alternative systems like Heads may be used.
#### Instructions to Disable Secure Boot in BIOS
1. Restart your computer
2. **Enter BIOS/UEFI Setup**:
- As your computer starts up, press the appropriate key to enter the BIOS/UEFI setup. Common keys include:
- **F2** (Dell, Acer, Lenovo)
- **Delete** (ASUS, MSI)
- **F10** (HP)
- **Esc** (Some systems)
- You may see a prompt on the screen indicating which key to press
3. **Navigate to the Secure Boot Option**:
- Once in the BIOS/UEFI setup, use the arrow keys to navigate through the menus. Look for a tab or section labeled **"Boot," "Security,"** or **"Authentication."**
- The exact location of the Secure Boot option can vary, so you may need to explore a bit
4. **Locate Secure Boot**:
- Find the **Secure Boot** option within the selected menu. It may be listed as **"Secure Boot Control"** or simply **"Secure Boot."**
5. **Disable Secure Boot**:
- Select the Secure Boot option and change its setting to **Disabled**. This is usually done by pressing **Enter** and then selecting **Disabled** from the options.
6. **Save Changes and Exit**:
- After disabling Secure Boot, navigate to the **Exit** tab or section.
- Choose the option to **Save Changes and Exit**. Confirm any prompts that appear to save your changes.
7. **Reboot Your Computer**:
- Your computer will restart. Secure Boot should now be disabled.

BIN
dist/airgap.iso (Stored with Git LFS) vendored Normal file

Binary file not shown.

16
dist/manifest.8E401478A3FBEF72.asc vendored Normal file
View File

@ -0,0 +1,16 @@
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEiII6deyqeGsP84sUjkAUeKP773IFAmglbi8ACgkQjkAUeKP7
73I7Rg/+MQ4yDhcnwBBtlN651Kcou5Z7EhAY5S9stg69yfqWL0MacNGRnEmNHYix
0J39xeYvP/dSsXYWgW04f0w4FS+msuqK9ML3YbB3Ei7GH4c+Bizhoj415chSMOlo
R97Gz2V+SZ83Ph51+ORA4DUZ3/PIoXfv5syTKmcrioUP9XhCou61TCqN4fMGgXpq
5F4awAZRrTtw+67dcEOmSQ7+TbNsMhJIei5Bg8FdPNS2VuMuUGTMrwsL7FBXIg1j
2J4tXUhZvLz7x3i0nuVlELfd6w1dDHW77e9rCmifGd4QRN+gqUGoOjp93HgnsUrJ
ASY0BKWfHeHcxpT2qtUuKZuBBjtGkGM9YQSUXYvuzhJp9XEZb9GHBMVo1TvX0sZr
jWyUVSBlcZuOlG5iGMF8D44nJOX4QikPuGLOJxmG2pOiFvh32qsTA50HV6/BEzZr
s5zm1IgsdF1SDPrxiqRPjZyvZYcF2kZtqxkzXEJzdPwcqCR9VXHo7InU7OrSg1D0
T/4wvsz50gsck1UvhEKukBVaWBmyzjHdnUPelOSbiUfn8xSKeL9RGGktV6tF3bUq
M1yBYp8Bpm3TteqGgeaUjJ5xSRGjynJrlFm+6YSJhf4AOVaex/Tysdlkg8ylQZLn
IrfZXgpmazBLKHtxQKyr4znWqN+DptMt6W7kPCwejQjiN5WH494=
=BFLb
-----END PGP SIGNATURE-----

2
dist/manifest.txt vendored Normal file
View File

@ -0,0 +1,2 @@
cafe1d794f8bb10e652da130e7f3f2f1a13e0ee89f54fdb6385b6fb191a22221 airgap.iso
eed8667982e86e41f2ebd1331f408e93ac5ef2a574ee23e7635cbb23506aec73 release.env

5
dist/release.env vendored Normal file
View File

@ -0,0 +1,5 @@
VERSION=development
GIT_REF=bdc971a931bf9fc51395beb5afd328d8b493a801
GIT_AUTHOR=Anton Livaja
GIT_PUBKEY=44A86CFF1FDF0E85
GIT_TIMESTAMP=2025-05-14 19:12:21 -0700

View File

@ -1 +0,0 @@
pinentry-mode loopback

View File

@ -1,12 +0,0 @@
KERNEL!="sd[a-z][0-9]", GOTO="sd_cards_auto_mount_end"
# Global mount options
ACTION=="add", ENV{mount_options}="relatime"
# Filesystem specific options
ACTION=="add", IMPORT{program}="/sbin/blkid -o udev -p %N"
ACTION=="add", ENV{ID_FS_TYPE}=="vfat|ntfs", ENV{mount_options}="$env{mount_options},utf8,flush,user,umask=0000"
ACTION=="add", RUN+="/bin/mkdir -p /media/sd-%k", RUN+="/bin/mount -o $env{mount_options} /dev/%k /media/sd-%k"
ACTION=="add", RUN+="/usr/local/bin/autorun /media/sd-%k"
ACTION=="remove", RUN+="/bin/umount -l /media/sd-%k", RUN+="/bin/rmdir /media/sd-%k"
LABEL="sd_cards_auto_mount_end"

View File

@ -1,18 +0,0 @@
#!/bin/bash
set -e
source /etc/profile
folder=${1?}
if [ -f "${folder}/autorun.sh.asc" ]; then
echo "" >/dev/console
echo "++ Autorun: Found ${folder}/autorun.sh" >/dev/console;
gpg --verify "${folder}/autorun.sh.asc" >/dev/null 2>&1 || {
echo "!! Autorun: Verification Failed for ${folder}/autorun.sh" \
>/dev/console;
exit 1;
}
echo "++ Autorun: Verified ${folder}/autorun.sh" >/dev/console
echo "** Autorun: Executing ${folder}/autorun.sh" >/dev/console
/bin/bash "${folder}/autorun.sh" >/dev/console
fi

3
sdcard/autorun.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
echo "Autorun.sh executed"

View File

@ -0,0 +1,8 @@
TIMEOUT 2
PROMPT -1
DEFAULT AirgapGuest
LABEL AirgapGuest
MENU LABEL Linux AirgapGuest
KERNEL /boot/vmlinuz
INITRD /boot/initramfs
APPEND init=/init vga=normal console=ttyAMA0,115200 console=tty highres=off console=ttyS0 console=tty0 ro

View File

@ -0,0 +1,47 @@
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:
tty:x:5:
disk:x:6:
lp:x:7:lp
mem:x:8:
kmem:x:9:
wheel:x:10:root
floppy:x:11:root
mail:x:12:mail
news:x:13:news
uucp:x:14:uucp
man:x:15:man
cron:x:16:cron
console:x:17:
audio:x:18:
cdrom:x:19:
dialout:x:20:root
ftp:x:21:
sshd:x:22:
input:x:23:
at:x:25:at
tape:x:26:root
video:x:27:root
netdev:x:28:
readproc:x:30:
squid:x:31:squid
xfs:x:33:xfs
kvm:x:34:kvm
games:x:35:
shadow:x:42:
cdrw:x:80:
www-data:x:82:
usb:x:85:
vpopmail:x:89:
users:x:100:games
ntp:x:123:
nofiles:x:200:
smmsp:x:209:smmsp
locate:x:245:
abuild:x:300:
utmp:x:406:
ping:x:999:
git:x:1000:

View File

@ -0,0 +1,4 @@
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback airgap-guest
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

View File

@ -0,0 +1,55 @@
#!/bin/sh
DAEMON="syslogd"
PIDFILE="/var/run/$DAEMON.pid"
SYSLOGD_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
# BusyBox' syslogd does not create a pidfile, so pass "-n" in the command line
# and use "-m" to instruct start-stop-daemon to create one.
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/bin/$DAEMON" \
-- -n $SYSLOGD_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -0,0 +1,55 @@
#!/bin/sh
DAEMON="klogd"
PIDFILE="/var/run/$DAEMON.pid"
KLOGD_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
# BusyBox' klogd does not create a pidfile, so pass "-n" in the command line
# and use "-m" to instruct start-stop-daemon to create one.
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/bin/$DAEMON" \
-- -n $KLOGD_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -0,0 +1,94 @@
#!/bin/sh
#
# This script is used by busybox and procps-ng.
#
# With procps-ng, the "--system" option of sysctl also enables "--ignore", so
# errors are not reported via syslog. Use the run_logger function to mimic the
# --system behavior, still reporting errors via syslog. Users not interested
# on error reports can add "-e" to SYSCTL_ARGS.
#
# busybox does not have a "--system" option neither reports errors via syslog,
# so the scripting provides a consistent behavior between the implementations.
# Testing the busybox sysctl exit code is fruitless, as at the moment, since
# its exit status is zero even if errors happen. Hopefully this will be fixed
# in a future busybox version.
PROGRAM="sysctl"
SYSCTL_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$PROGRAM" ] && . "/etc/default/$PROGRAM"
# Files are read from directories in the SYSCTL_SOURCES list, in the given
# order. A file may be used more than once, since there can be multiple
# symlinks to it. No attempt is made to prevent this.
SYSCTL_SOURCES="/etc/sysctl.d/ /usr/local/lib/sysctl.d/ /usr/lib/sysctl.d/ /lib/sysctl.d/ /etc/sysctl.conf"
# If the logger utility is available all messages are sent to syslog, except
# for the final status. The file redirections do the following:
#
# - stdout is redirected to syslog with facility.level "kern.info"
# - stderr is redirected to syslog with facility.level "kern.err"
# - file dscriptor 4 is used to pass the result to the "start" function.
#
run_logger() {
# shellcheck disable=SC2086 # we need the word splitting
find $SYSCTL_SOURCES -maxdepth 1 -name '*.conf' -print0 2> /dev/null | \
xargs -0 -r -n 1 readlink -f | {
prog_status="OK"
while :; do
read -r file || {
echo "$prog_status" >&4
break
}
echo "* Applying $file ..."
/sbin/sysctl -p "$file" $SYSCTL_ARGS || prog_status="FAIL"
done 2>&1 >&3 | /usr/bin/logger -t sysctl -p kern.err
} 3>&1 | /usr/bin/logger -t sysctl -p kern.info
}
# If logger is not available all messages are sent to stdout/stderr.
run_std() {
# shellcheck disable=SC2086 # we need the word splitting
find $SYSCTL_SOURCES -maxdepth 1 -name '*.conf' -print0 2> /dev/null | \
xargs -0 -r -n 1 readlink -f | {
prog_status="OK"
while :; do
read -r file || {
echo "$prog_status" >&4
break
}
echo "* Applying $file ..."
/sbin/sysctl -p "$file" $SYSCTL_ARGS || prog_status="FAIL"
done
}
}
if [ -x /usr/bin/logger ]; then
run_program="run_logger"
else
run_program="run_std"
fi
start() {
printf '%s %s: ' "$1" "$PROGRAM"
status=$("$run_program" 4>&1)
echo "$status"
if [ "$status" = "OK" ]; then
return 0
fi
return 1
}
case "$1" in
start)
start "Running";;
restart|reload)
start "Rerunning";;
stop)
:;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -0,0 +1,24 @@
#!/bin/sh
case "$1" in
start)
printf "Populating %s using udev: " "${udev_root:-/dev}"
[ -e /proc/sys/kernel/hotplug ] && printf '\000\000\000\000' > /proc/sys/kernel/hotplug
/sbin/udevd -d || { echo "FAIL"; exit 1; }
udevadm trigger --type=subsystems --action=add
udevadm trigger --type=devices --action=add
udevadm settle --timeout=30 || echo "udevadm settle failed"
echo "done"
;;
stop)
# Stop execution of events
udevadm control --stop-exec-queue
killall udevd
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,70 @@
#! /bin/sh
#
# Preserve the random seed between reboots. See urandom(4).
#
# Quietly do nothing if /dev/urandom does not exist
[ -c /dev/urandom ] || exit 0
URANDOM_SEED="/var/lib/random-seed"
# shellcheck source=/dev/null
[ -r "/etc/default/urandom" ] && . "/etc/default/urandom"
if pool_bits=$(cat /proc/sys/kernel/random/poolsize 2> /dev/null); then
pool_size=$((pool_bits/8))
else
pool_size=512
fi
init_rng() {
[ -f "$URANDOM_SEED" ] || return 0
printf 'Initializing random number generator: '
dd if="$URANDOM_SEED" bs="$pool_size" of=/dev/urandom count=1 2> /dev/null
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
save_random_seed() {
printf 'Saving random seed: '
status=1
if touch "$URANDOM_SEED.new" 2> /dev/null; then
old_umask=$(umask)
umask 077
dd if=/dev/urandom of="$URANDOM_SEED.tmp" bs="$pool_size" count=1 2> /dev/null
cat "$URANDOM_SEED" "$URANDOM_SEED.tmp" 2>/dev/null \
| sha256sum \
| cut -d ' ' -f 1 > "$URANDOM_SEED.new" && \
mv "$URANDOM_SEED.new" "$URANDOM_SEED" && status=0
rm -f "$URANDOM_SEED.tmp"
umask "$old_umask"
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
else
echo "SKIP (read-only file system detected)"
fi
return "$status"
}
case "$1" in
start|restart|reload)
# Carry a random seed from start-up to start-up
# Load and then save the whole entropy pool
init_rng && save_random_seed;;
stop)
# Carry a random seed from shut-down to start-up
# Save the whole entropy pool
save_random_seed;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -0,0 +1,30 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: qemu-ga
# Required-Start: $remote_fs $syslog
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Start QEMU Guest Agent
### END INIT INFO
case "$1" in
start)
echo "Starting QEMU Guest Agent"
cat /proc/cpuinfo | grep QEMU && qemu-ga &
;;
stop)
echo "Stopping QEMU Guest Agent"
killall qemu-ga
;;
restart)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
exit 0

27
src/guest/rootfs/etc/init.d/rcK Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
# Stop all init scripts in /etc/init.d
# executing them in reversed numerical order.
#
for i in $(ls -r /etc/init.d/S??*) ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set stop
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i stop
;;
esac
done

27
src/guest/rootfs/etc/init.d/rcS Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i start
;;
esac
done

View File

@ -0,0 +1,54 @@
# /etc/inittab
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console
# runlevels == ignored
# action == one of sysinit, respawn, askfirst, wait, and once
# process == program to run
# Startup the system
::sysinit:/bin/mount -t devtmpfs devtmpfs /dev
::sysinit:/bin/mkdir -p /proc /run /dev/pts /dev/shm /sys
::sysinit:/bin/mount -t sysfs sysfs /sys
::sysinit:/bin/mount -t devpts devpts /dev/pts
::sysinit:/bin/mount -t cgroup cgroup /sys/fs/cgroup
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mkdir /var/log
::sysinit:/bin/hostname -F /etc/hostname
null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
# Stuff to do for the 3-finger salute
::ctrlaltdel:/usr/bin/reboot
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Spawn shells on serial terminal and default console
::respawn:-/usr/bin/login -f root
ttyS0::respawn:-/usr/bin/login -f root
# Stuff to do before rebooting
::shutdown:/etc/init.d/rcK
::shutdown:/bin/umount -a -r
::sysinit:/bin/hostname -F /etc/hostname
null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Put a getty on the serial port
ttyS0::respawn:-/usr/bin/login -f root
# Stuff to do for the 3-finger salute
#::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
::shutdown:/etc/init.d/rcK
::shutdown:/bin/umount -a -r

View File

@ -0,0 +1,4 @@
root::0:0:root:/root:/bin/sh
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
git::1000:1000::/home/git:/bin/git-shell
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin

View File

@ -0,0 +1,5 @@
export EDITOR=/bin/vi
export PATH="/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin"
export PS1="[\h \t] \\$ "
export GNUPGHOME=/.gnupg
cd /root

View File

@ -0,0 +1,2 @@
nameserver 1.1.1.1
nameserver 8.8.8.8

2
src/guest/rootfs/init Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
exec /bin/init

5
src/host/config/grub.cfg Normal file
View File

@ -0,0 +1,5 @@
set timeout=1
menuentry "Linux Airgap" {
linux /boot/vmlinuz init=/init console=ttyS0 console=tty0 ro loglevel=3
initrd /boot/initramfs
}

View File

@ -0,0 +1,2 @@
search --no-floppy --set=root --label "airgap"
set prefix=($root)/boot/grub

View File

@ -0,0 +1,8 @@
TIMEOUT 2
PROMPT -1
DEFAULT Airgap
LABEL Airgap
MENU LABEL Linux Airgap
KERNEL /boot/vmlinuz
INITRD /boot/initramfs
APPEND init=/init console=ttyS0 console=tty0 ro

View File

@ -0,0 +1,55 @@
#!/bin/sh
DAEMON="syslogd"
PIDFILE="/var/run/$DAEMON.pid"
SYSLOGD_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
# BusyBox' syslogd does not create a pidfile, so pass "-n" in the command line
# and use "-m" to instruct start-stop-daemon to create one.
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/bin/$DAEMON" \
-- -n $SYSLOGD_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -0,0 +1,55 @@
#!/bin/sh
DAEMON="klogd"
PIDFILE="/var/run/$DAEMON.pid"
KLOGD_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
# BusyBox' klogd does not create a pidfile, so pass "-n" in the command line
# and use "-m" to instruct start-stop-daemon to create one.
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/bin/$DAEMON" \
-- -n $KLOGD_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -0,0 +1,94 @@
#!/bin/sh
#
# This script is used by busybox and procps-ng.
#
# With procps-ng, the "--system" option of sysctl also enables "--ignore", so
# errors are not reported via syslog. Use the run_logger function to mimic the
# --system behavior, still reporting errors via syslog. Users not interested
# on error reports can add "-e" to SYSCTL_ARGS.
#
# busybox does not have a "--system" option neither reports errors via syslog,
# so the scripting provides a consistent behavior between the implementations.
# Testing the busybox sysctl exit code is fruitless, as at the moment, since
# its exit status is zero even if errors happen. Hopefully this will be fixed
# in a future busybox version.
PROGRAM="sysctl"
SYSCTL_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$PROGRAM" ] && . "/etc/default/$PROGRAM"
# Files are read from directories in the SYSCTL_SOURCES list, in the given
# order. A file may be used more than once, since there can be multiple
# symlinks to it. No attempt is made to prevent this.
SYSCTL_SOURCES="/etc/sysctl.d/ /usr/local/lib/sysctl.d/ /usr/lib/sysctl.d/ /lib/sysctl.d/ /etc/sysctl.conf"
# If the logger utility is available all messages are sent to syslog, except
# for the final status. The file redirections do the following:
#
# - stdout is redirected to syslog with facility.level "kern.info"
# - stderr is redirected to syslog with facility.level "kern.err"
# - file dscriptor 4 is used to pass the result to the "start" function.
#
run_logger() {
# shellcheck disable=SC2086 # we need the word splitting
find $SYSCTL_SOURCES -maxdepth 1 -name '*.conf' -print0 2> /dev/null | \
xargs -0 -r -n 1 readlink -f | {
prog_status="OK"
while :; do
read -r file || {
echo "$prog_status" >&4
break
}
echo "* Applying $file ..."
/sbin/sysctl -p "$file" $SYSCTL_ARGS || prog_status="FAIL"
done 2>&1 >&3 | /usr/bin/logger -t sysctl -p kern.err
} 3>&1 | /usr/bin/logger -t sysctl -p kern.info
}
# If logger is not available all messages are sent to stdout/stderr.
run_std() {
# shellcheck disable=SC2086 # we need the word splitting
find $SYSCTL_SOURCES -maxdepth 1 -name '*.conf' -print0 2> /dev/null | \
xargs -0 -r -n 1 readlink -f | {
prog_status="OK"
while :; do
read -r file || {
echo "$prog_status" >&4
break
}
echo "* Applying $file ..."
/sbin/sysctl -p "$file" $SYSCTL_ARGS || prog_status="FAIL"
done
}
}
if [ -x /usr/bin/logger ]; then
run_program="run_logger"
else
run_program="run_std"
fi
start() {
printf '%s %s: ' "$1" "$PROGRAM"
status=$("$run_program" 4>&1)
echo "$status"
if [ "$status" = "OK" ]; then
return 0
fi
return 1
}
case "$1" in
start)
start "Running";;
restart|reload)
start "Rerunning";;
stop)
:;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -0,0 +1,22 @@
#!/bin/sh
case "${1}" in
start)
keymap="$( \
awk -F 'keymap=' '{sub(/ .*$/, "", $2); print $2}' /proc/cmdline \
)"
if [[ ! -z "$keymap" ]]; then
printf 'Loading Keymap %s: ' "${keymap}"
loadkeys "$keymap"
if [ $? -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
fi
;;
*)
echo "Usage: ${0} {start}"
exit 1
;;
esac

View File

@ -0,0 +1,24 @@
#!/bin/sh
case "$1" in
start)
printf "Populating %s using udev: " "${udev_root:-/dev}"
[ -e /proc/sys/kernel/hotplug ] && printf '\000\000\000\000' > /proc/sys/kernel/hotplug
/sbin/udevd -d || { echo "FAIL"; exit 1; }
udevadm trigger --type=subsystems --action=add
udevadm trigger --type=devices --action=add
udevadm settle --timeout=30 || echo "udevadm settle failed"
echo "done"
;;
stop)
# Stop execution of events
udevadm control --stop-exec-queue
killall udevd
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,20 @@
#!/bin/sh
case "$1" in
start)
/usr/sbin/pcscd -d || { echo "FAIL"; exit 1; }
killall pcscd
/usr/sbin/pcscd -d || { echo "FAIL"; exit 1; }
echo "done"
;;
stop)
# Stop execution of events
killall pcscd
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,70 @@
#! /bin/sh
#
# Preserve the random seed between reboots. See urandom(4).
#
# Quietly do nothing if /dev/urandom does not exist
[ -c /dev/urandom ] || exit 0
URANDOM_SEED="/var/lib/random-seed"
# shellcheck source=/dev/null
[ -r "/etc/default/urandom" ] && . "/etc/default/urandom"
if pool_bits=$(cat /proc/sys/kernel/random/poolsize 2> /dev/null); then
pool_size=$((pool_bits/8))
else
pool_size=512
fi
init_rng() {
[ -f "$URANDOM_SEED" ] || return 0
printf 'Initializing random number generator: '
dd if="$URANDOM_SEED" bs="$pool_size" of=/dev/urandom count=1 2> /dev/null
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
save_random_seed() {
printf 'Saving random seed: '
status=1
if touch "$URANDOM_SEED.new" 2> /dev/null; then
old_umask=$(umask)
umask 077
dd if=/dev/urandom of="$URANDOM_SEED.tmp" bs="$pool_size" count=1 2> /dev/null
cat "$URANDOM_SEED" "$URANDOM_SEED.tmp" 2>/dev/null \
| sha256sum \
| cut -d ' ' -f 1 > "$URANDOM_SEED.new" && \
mv "$URANDOM_SEED.new" "$URANDOM_SEED" && status=0
rm -f "$URANDOM_SEED.tmp"
umask "$old_umask"
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
else
echo "SKIP (read-only file system detected)"
fi
return "$status"
}
case "$1" in
start|restart|reload)
# Carry a random seed from start-up to start-up
# Load and then save the whole entropy pool
init_rng && save_random_seed;;
stop)
# Carry a random seed from shut-down to start-up
# Save the whole entropy pool
save_random_seed;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

View File

@ -0,0 +1,30 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: qemu-ga
# Required-Start: $remote_fs $syslog
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Start QEMU Guest Agent
### END INIT INFO
case "$1" in
start)
echo "Starting QEMU Guest Agent"
cat /proc/cpuinfo | grep QEMU && qemu-ga &
;;
stop)
echo "Stopping QEMU Guest Agent"
killall qemu-ga
;;
restart)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
exit 0

27
src/host/rootfs/etc/init.d/rcK Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
# Stop all init scripts in /etc/init.d
# executing them in reversed numerical order.
#
for i in $(ls -r /etc/init.d/S??*) ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set stop
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i stop
;;
esac
done

27
src/host/rootfs/etc/init.d/rcS Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i start
;;
esac
done

View File

@ -1,11 +1,5 @@
# /etc/inittab
#
# Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
#
# Note: BusyBox init doesn't support runlevels. The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use
# sysvinit.
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console
@ -14,27 +8,26 @@
# process == program to run
# Startup the system
::sysinit:/bin/mount -t devtmpfs devtmpfs /dev
::sysinit:/bin/mkdir -p /proc /run /dev/pts /dev/shm /sys
::sysinit:/bin/mount -t sysfs sysfs /sys
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mkdir -p /dev/pts /dev/shm
::sysinit:/bin/mount -a
::sysinit:/sbin/swapon -a
::sysinit:/bin/mkdir /var/log
null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
::sysinit:/bin/hostname -F /etc/hostname
# now run any rc scripts
::sysinit:/etc/init.d/rcS
# Put a getty on the serial port
#console::respawn:/sbin/getty -L console 0 vt100 # GENERIC_SERIAL
::respawn:-/bin/bash
# Put shells on the serial terminal and console
console::respawn:-/bin/bash
ttyS0::respawn:-/bin/bash
# Stuff to do for the 3-finger salute
#::ctrlaltdel:/sbin/reboot
::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting
::shutdown:/etc/init.d/rcK
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r

View File

@ -0,0 +1 @@
i915

View File

@ -2,9 +2,9 @@ export EDITOR=/bin/vi
export PATH="/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin"
export PS1="[\h \t] \\$ "
export GNUPGHOME=/.gnupg
export XDG_RUNTIME_DIR=/tmp
source /etc/environment
dmesg -n1
cd /root
clear
cat << "EOF"
_ _ ___ ____
@ -19,5 +19,5 @@ echo " - Version: $VERSION"
echo " - Date: $GIT_TIMESTAMP"
echo " - Committer: $GIT_AUTHOR"
echo " - Commit: $GIT_REF"
echo " - Key: $GIT_KEY"
echo " - Key: $GIT_PUBKEY"
echo ""

2
src/host/rootfs/init Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
exec /bin/init

View File

@ -0,0 +1,15 @@
KERNEL!="mmcblk[0-9]p[0-9]|sd[a-z][0-9]", GOTO="automount_end"
ACTION=="add", PROGRAM!="/sbin/blkid %N", GOTO="automount_end"
IMPORT{program}="/sbin/blkid -o udev -p %N"
ENV{ID_FS_LABEL}!="", ENV{dir_name}="%E{ID_FS_LABEL}"
ENV{ID_FS_LABEL}=="", ENV{dir_name}="%k"
ACTION=="add", IMPORT{program}="/sbin/blkid -o udev -p %N"
ACTION=="add", ENV{ID_FS_TYPE}=="vfat", ENV{mount_options}="relatime,utf8,flush,user,umask=0000"
ACTION=="add", RUN+="/bin/mkdir -p /media/%E{dir_name}", RUN+="/bin/mount -o $env{mount_options} /dev/%k /media/%E{dir_name}"
ACTION=="add", RUN+="/usr/local/bin/autorun /media/%E{dir_name}"
ACTION=="remove", ENV{dir_name}!="", RUN+="/bin/umount -l /media/%E{dir_name}", RUN+="/bin/rmdir /media/%E{dir_name}"
LABEL="automount_end"

View File

@ -0,0 +1,28 @@
#!/bin/bash
set -e
source /etc/profile
folder=${1?}
if [ "$folder" == "/media/USER" ] && [ -f "${folder}/autorun.sh" ]; then
if touch "${folder}/.write_test" 2>/dev/null; then
echo "!! Autorun: Read-only verification failed for /media/USER" >/dev/console
exit 1;
else
echo "" >/dev/console
echo "++ Autorun: Found /media/USER/autorun.sh" >/dev/console;
echo "** Autorun: Executing /media/USER/autorun.sh" >/dev/console
/bin/bash "/media/USER/autorun.sh" >/dev/console
fi
elif [ -f "${folder}/autorun.sh.asc" ]; then
echo "" >/dev/console
echo "++ Autorun: Found ${folder}/autorun.sh" >/dev/console;
gpg --verify "${folder}/autorun.sh.asc" >/dev/null 2>&1 || {
echo "!! Autorun: Verification Failed for ${folder}/autorun.sh" \
>/dev/console;
exit 1;
}
echo "++ Autorun: Verified ${folder}/autorun.sh" >/dev/console
echo "** Autorun: Executing ${folder}/autorun.sh" >/dev/console
/bin/bash "${folder}/autorun.sh" >/dev/console
fi

View File

@ -0,0 +1,291 @@
#!/bin/bash
set -eu
COMMAND=($@)
LOCKFILE=/var/run/netvm.pid
QGA_SOCK_PATH=/var/run/netvm_qga.sock
QMP_SOCK_PATH=/var/run/netvm_qmp.sock
QGA_SOCK_FDS=false
qga_connect() {
[[ -v "QGA_SOCK_FDS_PID" ]] && return 0
coproc QGA_SOCK_FDS (
exec socat - UNIX-CONNECT:"${QGA_SOCK_PATH}"
) || return 1
QGA_SOCK_IN=${QGA_SOCK_FDS[0]}
QGA_SOCK_OUT=${QGA_SOCK_FDS[1]}
}
qga_execute() {
local cmd args
cmd="$1"
args="${2-}"
GA_RETURN=""
jq \
-ncM \
--arg cmd "$cmd" \
--argjson args "$args" \
'{"execute": $cmd, "arguments": $args}' \
>&$QGA_SOCK_OUT
local LINE
read -t 5 -r -u $QGA_SOCK_IN LINE || return 1
local ERROR=$(jq -r '.error.desc // empty' <<< "$LINE")
if [[ -n "$ERROR" ]]; then
echo "$ERROR" >&2
return 1
fi
GA_RETURN=$(jq -cM .return <<< "$LINE")
}
qga_flush() {
#Docs say this should work, but it just get parse errors
#LC_ALL= LC_CTYPE=en_US.UTF-8 printf '%b' "\uff" >&$QGA_SOCK_OUT
#read -t 5 -r -u $QGA_SOCK_IN LINE
until ! read -t 1 -r -u $QGA_SOCK_IN LINE; do sleep 0.1; done
}
qga() {
local cmd args
cmd="$1"
args="$2"
qga_connect
local id=$((1 + $RANDOM % 10000000))
qga_execute guest-sync "$(jq -ncM --argjson id "$id" '{"id": $id}')";
[[ "$(jq -re . <<< "$GA_RETURN")" = "$id" ]] || (echo "Error: guest-sync mismatch" >&2 && return 1)
unset GA_RETURN
qga_execute "$cmd" "$args"
echo "$GA_RETURN" 2>&1
local RETURN
kill -INT "$QGA_SOCK_FDS_PID" 2>/dev/null
wait "$QGA_SOCK_FDS_PID" || RETURN=$?
if [[ $RETURN != 130 ]]; then
return $RETURN
fi
}
function cmd_shell(){
qemu-system-x86_64 \
-m 512M \
--machine q35 \
-nographic \
-net none \
-cdrom /guest.img \
-boot order=d \
-device qemu-xhci \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
}
function cmd_start(){
[ ! -f "${LOCKFILE}" ] || { echo "Error: Netvm already running"; exit 1; }
local net_args=""
while read line; do
[ -n "$line" ] || break
echo "Preparing PCI network device: $line"
bus=$(echo $line | awk '{ print $1 }')
id=$(echo $line | awk '{ print $4 }' | tr ':' ' ')
echo "$id" > /sys/bus/pci/drivers/vfio-pci/new_id 2>&1 || :
net_args="$net_args -device vfio-pci,host=${bus}"
done <<< "$(lspci | grep 0200 )"
if [[ -n "$net_args" ]]; then
echo Y > /sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts
fi
printf "Starting netvm...";
qemu-system-x86_64 \
-m 512M \
--machine q35 \
-nographic \
-serial none \
-monitor none \
-net none \
-cdrom /guest.img \
-boot order=d \
-chardev socket,path=${QGA_SOCK_PATH},server=on,wait=off,id=qga0 \
-qmp unix:${QMP_SOCK_PATH},server,nowait \
$net_args \
-device qemu-xhci,id=usb \
-device virtio-serial \
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 \
>/dev/null 2>&1 &!
pid=$!
printf "done\n"
echo "$pid" > "${LOCKFILE}"
printf "QGA Socket starting... "
until [ -S "${QGA_SOCK_PATH}" ]; do sleep 1; done
printf "done\n"
printf "Connecting to QGA socket... "
until qga_connect; do sleep 1; done
printf "done\n"
[ -f "/proc/${pid}/status" ] || {
echo "Error: netvm exited unexpectedly";
rm "${LOCKFILE}"
exit 1;
}
local id;
local spin='-\|/'
local i=0;
while true; do
i=$(( (i+1) %4 ));
printf "\rConnecting to QGA agent... ${spin:$i:1}"
qga_execute guest-ping "{}" > /dev/null || continue && break
sleep 1
done;
printf "\rConnecting to guest agent... done\n"
printf "Flushing buffers..."
qga_flush
printf "done\n"
local i=0;
while true; do
i=$(( (i+1) %4 ));
printf "\rSyncing with guest... ${spin:$i:1}"
id=$((1 + $RANDOM % 10000000))
qga_execute guest-sync "$(jq -ncM --argjson id "$id" '{"id": $id}')" || continue
if [[ "$(jq -re . <<< "$GA_RETURN")" = "$id" ]]; then
printf "\rSyncing with guest... done\n"
break
fi;
sleep 1
done;
echo "NetVM boot complete"
}
function cmd_stop(){
kill $(cat "${LOCKFILE}")
rm "${LOCKFILE}"
}
function cmd_status(){
qga guest-get-host-name "{}" | jq -r '."host-name"'
pid=$(qga guest-exec '{"path": "uptime", "capture-output": true}' | jq -r '.pid')
out=$(qga guest-exec-status "$(jq -n --argjson pid "$pid" '{pid: $pid }')" \
| jq -r '."out-data"' \
| base64 -d \
)
echo $out
}
function cmd_push(){
local source="${COMMAND[1]}"
local dest="${COMMAND[2]}"
fo_request=$(jq -n --arg dest "$dest" '{"path": $dest, "mode": "w" }')
handle=$(qga guest-file-open "$fo_request")
bufb64=$(base64 "$source")
count=$(cat "$source" | wc -c)
fw_request=$(jq -n \
--argjson handle $handle \
--argjson count $count \
--arg bufb64 "$bufb64" \
'{handle: $handle, "buf-b64": $bufb64, count: $count }' \
)
qga guest-file-write "$fw_request"
fh_request=$(jq -n --argjson handle $handle '{handle: $handle}' )
qga guest-file-flush "$fh_request"
qga guest-file-close "$fh_request"
}
function cmd_pull(){
local source="${COMMAND[1]}"
local dest="${COMMAND[2]}"
fo_request=$(jq -n --arg source "$source" '{"path": $source}')
handle=$(qga guest-file-open "$fo_request")
fr_request=$(jq -n \
--argjson handle $handle \
'{handle: $handle, count: 48000000 }' \
)
out=$(qga guest-file-read "$fr_request")
echo $out | jq -r '."buf-b64"' | base64 -d > $dest
}
function cmd_run(){
[ -z "${COMMAND[1]}" ] && { echo "Error: missing command"; exit 1; }
[ -f "${LOCKFILE}" ] || { echo "Error: Netvm is not running"; exit 1; }
[ -S "${QGA_SOCK_PATH}" ] || { echo "Error: Netvm QGA socket is missing"; exit 1; }
local cmd="${COMMAND[1]}"
local args="${COMMAND[@]:2}"
local args_json="[]"
if [[ -n "$args" ]]; then
args_json=$(printf '%s\n' "$args" | jq -R . | jq -s .)
fi
local request
request=$( \
jq -n \
--arg path "$cmd" \
--argjson args "$args_json" \
'{
path: $path,
arg: $args,
"capture-output": true
}' \
)
pid=$(qga guest-exec "$request" | jq -r '.pid')
local exited=false
until [ "$exited" == "true" ]; do \
out=$(qga guest-exec-status "$(jq -n --argjson pid "$pid" '{pid: $pid }')" )
exited=$(echo $out | jq -r '.exited')
if $exited && jq -r 'has("out-data")' >/dev/null < <(echo $out); then
echo "$out" | jq -r '."out-data"' | base64 -d
break
fi
sleep 1
done
}
function cmd_attach() {
local id="${COMMAND[1]}"
IFS=":" read vendorid_hex productid_hex <<< "$id"
vendorid=$(printf "%d\n" "0x$vendorid_hex")
productid=$(printf "%d\n" "0x$productid_hex")
(
echo '{"execute":"qmp_capabilities"}'
echo '{"execute":"device_add","arguments":{"driver":"usb-host","bus":"usb.0","vendorid":'$vendorid',"productid":'$productid'}}'
) | socat - UNIX-CONNECT:/var/run/netvm_qmp.sock
}
cmd_usage() {
cat <<-_EOF
netvm
Control network vm headlessly via QMP protocol
Usage:
netvm start
Start headless network vm in the background
netvm stop
Stop headless network vm
netvm shell
Start interactive network vm in the foreground
netvm status
Get hostname and uptime from running network vm
netvm attach <vendorid:deviceid>
Hot-plug a USB device to network VM
netvm push <local-path> <remote-path>
Push a local file to the network VM
netvm pull <remote-path> <local-path>
Pull a file from the network VM
netvm run "<command>"
Run a command in network vm and get stdout
_EOF
}
case "$1" in
status) shift; cmd_status $@ ;;
start) shift; cmd_start $@ ;;
stop) shift; cmd_stop $@ ;;
shell) shift; cmd_shell $@ ;;
attach) shift; cmd_attach $@ ;;
push) shift; cmd_push $@ ;;
pull) shift; cmd_pull $@ ;;
run) shift; cmd_run $@ ;;
help) shift; cmd_usage $@ ;;
*) cmd_usage $@ ;;
esac

35
src/update.py Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env python3
from requests import Session
from fileinput import FileInput
target = "Containerfile"
source = "https://codeberg.org/stagex/stagex/raw/branch/main/digests/"
stages = ["core","user","bootstrap"]
digests = {}
for stage in stages:
response = Session().get(f"{source}{stage}.txt")
for line in response.iter_lines():
if not line:
continue
(digest, name) = line.decode("utf-8").split(" ")
print(digest, name)
digests[name] = digest
with FileInput(target, inplace=True, backup='.bak') as f:
for line in f:
if line.startswith("FROM stagex/"):
# NOTE: split by '@' in case a tag is not provided
# Matches:
# stagex/tag:version@sha256:hash
# stagex/tag@sha256:hash
# stagex/tag:version
# stagex/tag
name = line.split("/")[1].split(":")[0].split('@')[0]
if name not in digests:
for stage in stages:
if f"{stage}-{name}" in digests:
name = f"{stage}-{name}"
print(f"FROM stagex/{name}@sha256:{digests[name]} AS {name}")
else:
print(line,end='')