Abstract

NanoKVM Factory Image Comparison

EmbeddedIoT

A comparison of the factory pre-installed image on the Sipeed Lichee NanoKVM and the version available on GitHub.

1/1/2025

Banner image credit: FlyD via Unsplash.

Table of Contents

TL;DR

Flash the images available on GitHub to be safe, and you should be good to go, but it's probably not the end of the world if you didn't. The differences between the images are moderate (though strange), and there are no super overt signs of deliberate tampering/compromise.

Intro

NanoKVM family

Image credit: Sipeed. The left is the Lite Version, and the right is the Full Version.

The Lichee NanoKVM is a family of low-cost RISC-V-based Keyboard, Video, and Mouse (KVM) from Sipeed designed to compete with other low-cost KVMs, such as the PiKVM. For those unfamiliar, a KVM allows you to remotely connect to a computer (i.e., a server) and interact with it as if you were physically present. While this may sound redundant with the availability of SSH, VNC, RDP, etc., a KVM is still useful for tasks when the host OS is unable to run these services, such as if the computer is shut down, the OS is unresponsive, or if you misconfigured the network settings. For more information and a full review of the NanoKVM, please refer to Jeff Geerling's review.

This article will analyze and compare the image pre-installed on the micro SD card in the NanoKVM Full Version I purchased in October, 2024 and shipped in late November 2024 with the images available on the NanoKVM GitHub repository. I should note that the Lite Version does not come with a micro SD card. Because the NanoKVM was previously closed source (and is arguably still somewhat closed source), I will treat this as primarily a black box analysis.

The Image

The image comes on a 32 GB Kioxia Exceria micro SD HC I card. fdisk -l shows the following partitions:

Disk /dev/sda: 28.85 GiB, 30979129344 bytes, 60506112 sectors
Disk model: Storage Device
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xeaae1a17

Device     Boot    Start      End  Sectors  Size Id Type
/dev/sda1  *           1    32768    32768   16M  c W95 FAT32 (LBA)
/dev/sda2          32769 16000000 15967232  7.6G 83 Linux
/dev/sda3       16001024 60506111 44505088 21.2G 83 Linux

After cloning the drive, I mounted the cloned partitions and examined the first partition, particularly the ver file, which contains 2024-08-17-18-13-713161.img. I then downloaded several of the images from the NanoKVM GitHub repository, extracted them, mounted them, and compared the ver file in each one:

VersionImage File NameImage File SHA256Version File Content
V1.0.020240702_NanoKVM_Rev1_0_0.imgda1595cba13c6fa832612b259f8c1d22289ab7692b2c40d166a411d9d8a7f95f2024-06-23-20-59-2d2bfb.img
V1.1.020240702_NanoKVM_Rev1_1_0.imged4650dbbbdaac48448a3c670793e10ef17c808a906b43ba39581d9cdb4422332024-07-19-02-51-65b0a6.img
V1.2.020240809_NanoKVM_Rev1_2_0.imgd9053d59fa020b8a92802e65a3fbbe035b9e97ba745ea45ac184e17bbaaf1ce92024-08-08-19-44-bef2ca.img
V1.2.120240820_NanoKVM_Rev1_2_1.imgd6a13085f6bfd908011caa20e4d8777e5f84a6219a18fc4f2519e84d270e5f972024-08-17-18-13-713161.img
V1.3.020241120_NanoKVM_Rev1_3_0.imgae996d3502b6c166ec43ac9bcc561a5b298c9879dfaaa7d3646971708a7f17f42024-11-13-09-59-9c961a.img

Given this and when the NanoKVM was shipped, it appears that the image on the micro SD card is V1.2.1, which is what I will be comparing against.

Comparison

To compare the filesystems, I used the following command:

FILESYSTEM="/path/to/mounted/filesystem"
sudo find "${FILESYSTEM}" -type f -print0 | sort -z | sudo xargs -0 sha256sum -b | sed "s|*${FILESYSTEM}||g" --zero-terminated

The results of which can be found in the following files:

Type ↓ Partition →BootRoot
Factoryfactory-boot.txtfactory-rootfs.txt
GitHubgithub-boot.txtgithub-rootfs.txt

Boot Partition

The boot partitions are very similar:

--- github-boot.txt
+++ factory-boot.txt
+7386dca777a79e7e863f6e308d64675ce9203404260349531cd2d340cbe70f75 /hostname.prefix
+f64747a18007721c3c629bfc3d2da9cbc488940a2d8b0c41477c7b0b37c3d8e3 /System Volume Information/WPSettings.dat

The factory image adds a hostname.prefix file, which contains kvm, and a Windows-specific file /System Volume Information/WPSettings.dat, likely the result of the card being burned by a Windows machine at the factory.

Root

The root partitions are somewhat similar:

--- github-rootfs.txt
+++ factory-rootfs.txt
[REDACTED] /device_key
+e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /etc/factory
-f913870447cd2573857ff61caaf85408c1d41b3be0ef43cb65c77cc631f78b08 /etc/hostname
-337b2aae0215fb38e887a05d2850ae357de5dc585594e073dd42a3255be34f6c /etc/hosts
+1eb2639045c6d30b7f0f7433bfb091cb9d433d6834401ffafaf5ee841c84d3c6 /etc/hostname
+6250509dde63046d91a9a3951ed606b427451ad45b43a5049422a7e52344c966 /etc/hosts
-1cac066909be7e82ba5729974bc600a35da2929f9d36dfc8385a13f997d8f2c9 /etc/init.d/S01fs
+fbf5467c5c2de55982dfe47f78906018cd59d59a0dd9ef9d6b6edb9e82cddf86 /etc/init.d/S01fs
-5c8c642ad30f67130c08d03229fb2182fab82d6a3cf645b9f7b463f0ee843cba /etc/init.d/S03usbdev
-2eb549c186bfa40de4b0761db35cf0b76cdaa9170382c8a109d1f76ef275d87c /etc/init.d/S04backlight
+d46f57d16f6ebdce7ba583c4ab38a041f59e4aabde2cc87ce8f17c6b9dcc2203 /etc/init.d/S03usbdev
-ea7521bcf7b20f527fb4eacda036f8fa92256c77a9b96a8828a08b2ee21c9f74 /etc/init.d/S05tp
-d8d0c4e589c2b2cd841a032c0fa30e97daeb524f5624eae097bb901b31a51fa7 /etc/init.d/S15kvmhwd
+7ef70f9f3be680725f984d72919890e649fd38138506b2f2fb62ee6bf86dab42 /etc/init.d/S15kvmhwd
-476c4f513faac267b6a9ef7482e47d1406bec2885fa1f8c843ac6275d79916d8 /etc/init.d/S25wifimod
-b1e5800620fac9b18d488eaf0edf4d2f46b486c33beff3027a6434af6da41d46 /etc/init.d/S30eth
+a8301de6d3bb5d46948771a6aabdceeba2327d04c4f54b59813e6109a9a0a145 /etc/init.d/S30eth
-f3923a9f7903986356add88e058325fc8d82b0ce67ec47de2465a2829d08e910 /etc/init.d/S30wifi
-c34d227a3f7919da97f10e3282d3205494dc06f8e8e7148f2979c3da67473c8d /etc/init.d/S40bluetoothd
-8a99dcf1c82529a47606478649215799e7d2222d90a65e23ee5657906a385758 /etc/init.d/S95nanokvm
+51c4fe058dc555aac79562b8ce1eb8ff09bb3e160442dcf654f1fa4142d7b49b /etc/init.d/S95nanokvm
-96cb2a4dbceb2ba1a1ff34d5dc1be61f4b6662df38cbc5e4ec1fe48b41193098 /etc/init.d/S99audtest
-576ac7d411d026cd41a3079a1f6be891cddce5ef9c258e569b5b785574f0add7 /etc/init.d/S99camtest
-94916470027c38a233bbfb68183dc97953cd03bf567d4c07dec731c5288454eb /etc/init.d/S99ednctest
-60fdeffb175d42b2b0df9409d85161a43032ffb5310af4839896f057ed7d80a3 /etc/init.d/S99input-event-daemon
-35a3d6a6a5e568683a53699543f5585cb93d16e953615fc6ab7790c1177c7db0 /etc/init.d/S99ivetest
-2860a7ce7f925065c8f059f365798de08e4b8ecdbd6430136a4a9cffa67f25a6 /etc/init.d/S99kvmtest
-a0c8d103601f46c284cff9e2259e4633e67052814b16fe46ebdcbc3fef27e7b9 /etc/init.d/S99lcdtest
-88ec74653ee6549ebcc8cf565e34f72b6c6ca21a4b49ba3f71a8ce6c8d41d64c /etc/init.d/S99loadtest
-5bcdfc4db1dccae40357bdcc04974db8b71bd3ac720419fffc117e8f87437e7f /etc/init.d/S99local
-ebbed0b8387d655ce6b5f994f8e913b7356cdded48fe2d9d40f8e958b41ee084 /etc/init.d/S99modeltest
-d2d1994aa9c1246cc6a0ecb2b18086cffaecd5744cb4af99ec5b7b94d589a7ca /etc/init.d/S99nettest
-a95d55dcaa5f15978b1c1ca6f0c1d6c2f82a6bc7e711ba82211a2210b4e905f9 /etc/init.d/S99nntest
-6d5b7ab455433adff91da7449f87933435810bd4f0bbbda06d6d87914500a08f /etc/init.d/S99pinmux
-4071d67596e15d39972b9b60ed49c33aed962b884209301bc7141f3a1ec40a84 /etc/init.d/S99resizefs
-fe1e80fa658f7b7c249e955e9351b4e8ba2968cee0caada69f197eb311b01657 /etc/init.d/S99temptest
-3f57f166456bc68902e54d82111be1eaf0578235c7392ffca7d81e2882469d84 /etc/input-event-daemon.conf
+3f57f166456bc68902e54d82111be1eaf0578235c7392ffca7d81e2882469d84 /etc/input-event-daemon.conf.bak
+e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /etc/kvm.disk0
+e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /etc/kvm/frame_detact
+a3a5e715f0cc574a73c3f9bebb6bc24f32ffd5b67b387244c2c909da779a1478 /etc/kvm/hdmi_version
+f2c82decdd7181cf98945929a62598db7e6b477e11f6e0eb0ae97020eff151ad /etc/kvm/hw
+ca10a2746c1d40e3bca95b5072cc5f260a3c927a280828b7b240dd2b3fd5b3c8 /etc/kvm/server.yaml
+e840218f70dac0ddc1391cc1a0e84733c7f36ad90da61cd3e90e1d9c10ac9057 /etc/kvm/update-nanokvm.py
+4418e38aa5845ad57f21be6f9c37653ce01ec4797d4cd52ec432caa1ce63f293 /etc/ssh/ssh_host_ecdsa_key
+e62f0fdfe4336f5b67a040dafaab96aca39e37462dce86acabfa69b678d0a331 /etc/ssh/ssh_host_ecdsa_key.pub
+d0b33adc9954b6e55e850cce2658735efcbd4ccea45080eda8b4ce1d9024579d /etc/ssh/ssh_host_ed25519_key
+4f232ccb3af9bb1eb48aee7392fb1f2a021d1e33719ab07e20fe83101fa32bb7 /etc/ssh/ssh_host_ed25519_key.pub
+31a2c8029ea491e5dc529b0fbc6ce8a752b8db77e19468de01ed137369b8a8a8 /etc/ssh/ssh_host_rsa_key
+ebe12d50bf8208cef5fcc5fbb90a3c4919497768c1bc457ddf42d292d3d6a85b /etc/ssh/ssh_host_rsa_key.pub
+cf5bdce2ce87b5054042a70d8630f40a0f991c64c42786824f660245b943d2be /etc/sysctl.d/99-tailscale.conf
+ed1e0b0556b8e846793cf81059c86b41ea3c43292e382519a9b28d380f8267b0 /etc/udhcpd.usb0.conf
-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /kvmapp/kvm_new_img
-37f8f739b8b672e3af5f4d5216bbbee87c84da55f916f7c8bf22031188f116cf /kvmapp/kvm_system/dl_lib/libaaccomm2.so
-849f83607e546916cfbb72a2768670faa93fba7f4aded94428da0f25c5d13c1f /kvmapp/kvm_system/dl_lib/libaacdec2.so
-efc799954cb8e3a7f70d21ce04ff2c0cbf5371373fc0b2b881c8fac523b6b402 /kvmapp/kvm_system/dl_lib/libaacenc2.so
-93f33208e8f7d1a7e11fad400e74ef70bce6f64924db8b1cbbdaa2a09306fb37 /kvmapp/kvm_system/dl_lib/libaacsbrdec2.so
-da9beaad3606a0d37993f9145ac15a453cfc22a98254981c7a854aac7c1cb2bb /kvmapp/kvm_system/dl_lib/libaacsbrenc2.so
-5e75b98a9313b8d0f39c4daca4ed4671472701b386d707eb4baed2a24631ee60 /kvmapp/kvm_system/dl_lib/libae.so
-eec4150e44bcfe36002c979baae85bdb4de35ad6884fdbb333c7be71869203e7 /kvmapp/kvm_system/dl_lib/libaf.so
-b43ddce40fb9779cdabebf1e778fbaef096facb74bdbecabf4531dc5223f48c9 /kvmapp/kvm_system/dl_lib/libawb.so
-f2b91c8ce221b04a8566b0c3d1716cf79961a82fb63d45cf54d71274935e154c /kvmapp/kvm_system/dl_lib/libcli.so
-3595d4d7c831190b19c6d0e511cc1c90ed2429d565b2476dcce83980996f68c6 /kvmapp/kvm_system/dl_lib/libcvi_audio.so
-c415a68235596bc404d14294d8be0152b119ebdd4efc64481cc0b0d0f3ff2b95 /kvmapp/kvm_system/dl_lib/libcvi_bin_isp.so
-619c75697eec3ddebeb32c010ab0ffd79bdc5ab40d6df8c8eca8decfcb9a72c0 /kvmapp/kvm_system/dl_lib/libcvi_bin.so
-406a291162d4e2f3aaebab0340f68c3fb3f42610cd2ed64bafea85bfd4409007 /kvmapp/kvm_system/dl_lib/libcvi_ispd2.so
-70ef11381f90786e47ed939dfef20310872b71434fab02c02efb33bdc943cd0d /kvmapp/kvm_system/dl_lib/libcvi_ive.so
-3c13c4ec1168ef334d532e853ed9bed80c63c0a8379675e5139938aa30873e1b /kvmapp/kvm_system/dl_lib/libcvi_RES1.so
-279cd351a5ef860d19f6eb44d640a335916063795658c6b5965937a2d2fa60e2 /kvmapp/kvm_system/dl_lib/libcvi_ssp.so
-8320815d2c42601461302556ed1707501b91e2ba6cf487a67edfe07a1ba91d06 /kvmapp/kvm_system/dl_lib/libcvi_VoiceEngine.so
-ab55102c0c32916168467c58e64e0bb03ccfb0fd9a0392baf8bdfc8762fc219e /kvmapp/kvm_system/dl_lib/libcvi_vqe.so
-2a7e3a6bffc103eb4738be34f62bcbd3dce01793b6ceabd5f4af635e97aab118 /kvmapp/kvm_system/dl_lib/libdnvqe.so
-40733d994c0fd557a7f50274e69594a366eeaeef519bfb160468e14ed7b79f93 /kvmapp/kvm_system/dl_lib/libini.so
-f544fe04a760a13b21d9c34c31110e21bc73ba46f09f686e78bdcfa9c49b0373 /kvmapp/kvm_system/dl_lib/libisp_algo.so
-ffcfcbb950d58839eea36249509bdce31ea580816bdff238b2939ef8991eaa20 /kvmapp/kvm_system/dl_lib/libisp.so
-7078bd892ed052d449f1d71b871c0f0d7916dc37a6c80bd1e47378e397d970f5 /kvmapp/kvm_system/dl_lib/libjson-c.so.5
-977a88a0f581a50c59535a1e92e847fa2402f14c0f2fa7914ef0a71846006146 /kvmapp/kvm_system/dl_lib/libmaixcam_lib.so
-65f362e1a567025091039b6b30327a92a86da8f0cea464c32f8dc5c14be7bf42 /kvmapp/kvm_system/dl_lib/libmipi_tx.so
-c78d2d3cc1dc04da04ea7ef82a4656a1d0911e0784a4c0476b40475ea59cc8fe /kvmapp/kvm_system/dl_lib/libmisc.so
-d257c858a4c897530a0ddf3800b4d4207f59d530b15c2980c76b3ae5f6725014 /kvmapp/kvm_system/dl_lib/libosdc.so
-8364a3889a9e4a0cb039fd5dc5ed5d096af23e5d34366b5915291cf5cec81e36 /kvmapp/kvm_system/dl_lib/libraw_dump.so
-c1faab8e19593aa5cca7050c9c89d64846e16a4a207784b0e12de81587c31ffe /kvmapp/kvm_system/dl_lib/libsys.so
-bb6224946f6b58c3e2c2be7f42c713d48eb1edee7263665013660355e4a45601 /kvmapp/kvm_system/dl_lib/libtinyalsa.so
-f9c3bb7668d3074704d5159ab47436323d14569fc1c0557b526efa2829145d9b /kvmapp/kvm_system/dl_lib/libvdec.so
-427bac7c499c226b249c6fb6e4b380f9d3929c3daf5d660503ec377ba5fe1395 /kvmapp/kvm_system/dl_lib/libvenc.so
-e1dacd043d39196df5310d94d5e67f60009248314b28bf25cd60db22a86ae922 /kvmapp/kvm_system/dl_lib/libvpu.so
-2d0b5ee999b56437b80da779ee7e8d0aceb39b9460964a39ff05ff024d93c249 /kvmapp/kvm_system/kvm_system
-5cd62202f1e382b84995ff2adbe5237b7c2d1297edfa03256eb7b1bab001b73b /kvmapp/server/.DS_Store
-1f2a0b7a9f40ceffc9a2c93e1189135598f150fc1321c735127d85c98fbd29e6 /kvmapp/server/NanoKVM-Server
-2980804d69c6d89291f09be2da9dd3ba6b0a5dc3c7b45cee096630a9bd2e39bd /kvmapp/server/web/assets/auth-Dp7nO6B1.js
-3c6494c81059048acfbc2ad482860e22a23fa0017edb358eb77c2cb2bfcec39e /kvmapp/server/web/assets/encrypt-BrE29Rwk.js
-5b31141220f2ef3b18986be8f6b68bda028fa87705d29be0cd1cf4ade76ef537 /kvmapp/server/web/assets/head-Dm4gnfbF.js
-1038981208ed15830feec5152b280a52f77dbc36b7846a1256eebc4ac8eb211f /kvmapp/server/web/assets/http-DYeZYrT9.js
-8661d2aca00e00bba2daa8c2bf9991a5df1b8c9bfea4ce972e639d506b94f3ae /kvmapp/server/web/assets/index-B_b2izJx.js
-2ac40339af949d0649163b2acb538d3da25071c28cc6ee4f752b90608ba34d35 /kvmapp/server/web/assets/index-B_guo0tA.js
+f4ccd05b3271c386ee55d9876c7450012a3b361e5065c09dc22075e38b3cc35c /kvmapp/kvm/fps
+181d2608d80915d816b94a813c42b07610ede844ade7923402074921d4f04433 /kvmapp/kvm/height
+9a271f2a916b0b6ee6cecb2426f0b3206ef074578be55d9bc94f6f3fe3ab86aa /kvmapp/kvm/now_fps
+1d8fa3c8ab49d50b30fccbbd901735d5896a5d7959a5ad7ccecb79c1c849cc66 /kvmapp/kvm/qlty
+140154083d726867f5e43282aeaf021f9300ec6287d4d2c874493ee655a766e7 /kvmapp/kvm/res
+9a271f2a916b0b6ee6cecb2426f0b3206ef074578be55d9bc94f6f3fe3ab86aa /kvmapp/kvm/state
+d919256858470b9baa23f476db21a60cf7a439a7d6eee806442279f002050cf2 /kvmapp/kvm_system/dl_lib/libmaixcam_lib.so
+9f9396462e3e9f1c43e19c8b606ac7c40b3a468851362c90287d5e37c695da90 /kvmapp/kvm_system/kvm_system
+2fc8eeea7453205ef9f45c5a75f4308b295978696baa11da0c392275bec799ea /kvmapp/kvm/type
+98d8e9f74d312189e4c6c76fa98c708bc45a109df4bd5f51fbe16638ddbdbbc0 /kvmapp/kvm/width
+37f8f739b8b672e3af5f4d5216bbbee87c84da55f916f7c8bf22031188f116cf /kvmapp/server/dl_lib/libaaccomm2.so
+849f83607e546916cfbb72a2768670faa93fba7f4aded94428da0f25c5d13c1f /kvmapp/server/dl_lib/libaacdec2.so
+efc799954cb8e3a7f70d21ce04ff2c0cbf5371373fc0b2b881c8fac523b6b402 /kvmapp/server/dl_lib/libaacenc2.so
+93f33208e8f7d1a7e11fad400e74ef70bce6f64924db8b1cbbdaa2a09306fb37 /kvmapp/server/dl_lib/libaacsbrdec2.so
+da9beaad3606a0d37993f9145ac15a453cfc22a98254981c7a854aac7c1cb2bb /kvmapp/server/dl_lib/libaacsbrenc2.so
+5e75b98a9313b8d0f39c4daca4ed4671472701b386d707eb4baed2a24631ee60 /kvmapp/server/dl_lib/libae.so
+eec4150e44bcfe36002c979baae85bdb4de35ad6884fdbb333c7be71869203e7 /kvmapp/server/dl_lib/libaf.so
+b43ddce40fb9779cdabebf1e778fbaef096facb74bdbecabf4531dc5223f48c9 /kvmapp/server/dl_lib/libawb.so
+f2b91c8ce221b04a8566b0c3d1716cf79961a82fb63d45cf54d71274935e154c /kvmapp/server/dl_lib/libcli.so
+3595d4d7c831190b19c6d0e511cc1c90ed2429d565b2476dcce83980996f68c6 /kvmapp/server/dl_lib/libcvi_audio.so
+c415a68235596bc404d14294d8be0152b119ebdd4efc64481cc0b0d0f3ff2b95 /kvmapp/server/dl_lib/libcvi_bin_isp.so
+619c75697eec3ddebeb32c010ab0ffd79bdc5ab40d6df8c8eca8decfcb9a72c0 /kvmapp/server/dl_lib/libcvi_bin.so
+406a291162d4e2f3aaebab0340f68c3fb3f42610cd2ed64bafea85bfd4409007 /kvmapp/server/dl_lib/libcvi_ispd2.so
+70ef11381f90786e47ed939dfef20310872b71434fab02c02efb33bdc943cd0d /kvmapp/server/dl_lib/libcvi_ive.so
+3c13c4ec1168ef334d532e853ed9bed80c63c0a8379675e5139938aa30873e1b /kvmapp/server/dl_lib/libcvi_RES1.so
+279cd351a5ef860d19f6eb44d640a335916063795658c6b5965937a2d2fa60e2 /kvmapp/server/dl_lib/libcvi_ssp.so
+8320815d2c42601461302556ed1707501b91e2ba6cf487a67edfe07a1ba91d06 /kvmapp/server/dl_lib/libcvi_VoiceEngine.so
+ab55102c0c32916168467c58e64e0bb03ccfb0fd9a0392baf8bdfc8762fc219e /kvmapp/server/dl_lib/libcvi_vqe.so
+2a7e3a6bffc103eb4738be34f62bcbd3dce01793b6ceabd5f4af635e97aab118 /kvmapp/server/dl_lib/libdnvqe.so
+40733d994c0fd557a7f50274e69594a366eeaeef519bfb160468e14ed7b79f93 /kvmapp/server/dl_lib/libini.so
+f544fe04a760a13b21d9c34c31110e21bc73ba46f09f686e78bdcfa9c49b0373 /kvmapp/server/dl_lib/libisp_algo.so
+ffcfcbb950d58839eea36249509bdce31ea580816bdff238b2939ef8991eaa20 /kvmapp/server/dl_lib/libisp.so
+7078bd892ed052d449f1d71b871c0f0d7916dc37a6c80bd1e47378e397d970f5 /kvmapp/server/dl_lib/libjson-c.so.5
+85f4d03ca4a0e842c4a06185c53a48325c04c584dd1f2b565994fb9d8bf23179 /kvmapp/server/dl_lib/libkvm.so
+d919256858470b9baa23f476db21a60cf7a439a7d6eee806442279f002050cf2 /kvmapp/server/dl_lib/libmaixcam_lib.so
+65f362e1a567025091039b6b30327a92a86da8f0cea464c32f8dc5c14be7bf42 /kvmapp/server/dl_lib/libmipi_tx.so
+c78d2d3cc1dc04da04ea7ef82a4656a1d0911e0784a4c0476b40475ea59cc8fe /kvmapp/server/dl_lib/libmisc.so
+d257c858a4c897530a0ddf3800b4d4207f59d530b15c2980c76b3ae5f6725014 /kvmapp/server/dl_lib/libosdc.so
+8364a3889a9e4a0cb039fd5dc5ed5d096af23e5d34366b5915291cf5cec81e36 /kvmapp/server/dl_lib/libraw_dump.so
+c1faab8e19593aa5cca7050c9c89d64846e16a4a207784b0e12de81587c31ffe /kvmapp/server/dl_lib/libsys.so
+bb6224946f6b58c3e2c2be7f42c713d48eb1edee7263665013660355e4a45601 /kvmapp/server/dl_lib/libtinyalsa.so
+f9c3bb7668d3074704d5159ab47436323d14569fc1c0557b526efa2829145d9b /kvmapp/server/dl_lib/libvdec.so
+427bac7c499c226b249c6fb6e4b380f9d3929c3daf5d660503ec377ba5fe1395 /kvmapp/server/dl_lib/libvenc.so
+5375da35aebc62a0554cbde8f08bf2ff50959661871a809e2629c8c92d1d5ba9 /kvmapp/server/dl_lib/libvpu.so
+296f4c0ba32dc66ecc635e47c6675e04e788ed62ec1b05becddef8d5b4177f3d /kvmapp/server/NanoKVM-Server
+812d5d41e76ad3a789c2c4e432bc81cac29258fc6ba53852ed599a7e5edff521 /kvmapp/server/web/assets/auth-K_uPa-EP.js
+e1482c9dfb2d6f642d88084833b922e893e5bd8b1e58c30793fb92d08bd21dbd /kvmapp/server/web/assets/encrypt-DeSTkaMV.js
+f66521426caec0615445d433ff79f0d8bf7a63aa9e25d83827ecdb231ba9b039 /kvmapp/server/web/assets/head-ODJ_welb.js
+be72ea47e53378a6955deb22c4e1e6c45984adf7fef11724582af5147fa76bb0 /kvmapp/server/web/assets/index-B4bVQUcw.js
+7769f529953e61d9577091f15aacf68b62f30d1ced783f1a0f183ded88e5cd96 /kvmapp/server/web/assets/index-Bl_2VLkA.css
+440a7272d3da2ded0bca75a7491926c75411677ff75c164fec3cc0872a727937 /kvmapp/server/web/assets/index-BUn-WgOW.js
-e68b0731a9cc3696a00ad1389d17ba9ccdadc0121b14bcd10a7167f82f9cd661 /kvmapp/server/web/assets/index-CJS5-vSY.js
-120b828cff0c7300981cfeb0b20985e0c6b67193a0853c57ef3f7ee7be04bac3 /kvmapp/server/web/assets/index-D_Fu7P2y.css
-7d72707aa7651a42ffa4b6de93a370507910bc8a67aeb07d1e28ea405f80eb20 /kvmapp/server/web/assets/index-DGWJClpJ.js
-1f381e7490dfa3e0e6932fba0ddad049dc45f7251222c305207275fa129d3d3f /kvmapp/server/web/assets/index-DrXHD3oy.js
-1a1bbb3de835b595bff1b27500635e357864816e75ed74d17aad8fc95e5e9744 /kvmapp/server/web/assets/index-hge731-N.js
-d38a51ac0cf5c47337b08ebc339e917069154d2f5779baaf5e58b047192d7ebf /kvmapp/server/web/assets/index-u2n1Wr7j.css
-e7d3df4ef27a006e716f8d33c0827b68d6f2031bbf947ad72a20e67be77cb163 /kvmapp/server/web/index.html
+754f2ca4bbbbb024c1ed3d0d777ff709103159a7693d0b68f9eb04cfa63410c4 /kvmapp/server/web/assets/index-DRIQFk0N.js
+08bb46ce310ed16fc45f0d3fd0151d72192c9ad5b9e3184e22831dafc4483a16 /kvmapp/server/web/assets/index-DszERfC0.js
+96d22c5e4c6d897f49aff7dfa967c9957b25ee6961070b87b1ee88805f400c77 /kvmapp/server/web/assets/index-L7H6lV1d.css
+b5852a4d35720c3318ea8dca3541748d75deacd25f4ebbcd25f4677250ace0d9 /kvmapp/server/web/assets/index-PuU3XSNw.js
+de560e55e58ea0aaca6f37f2d0dc488ec169732fee112a76cd507d91707b1f11 /kvmapp/server/web/assets/index-yG9y9dy_.js
+ab241782d2cbbbce8bb27a573fa4ce670925586124dab3dca5c169c67d7a4741 /kvmapp/server/web/index.html
+fbf5467c5c2de55982dfe47f78906018cd59d59a0dd9ef9d6b6edb9e82cddf86 /kvmapp/system/init.d/S01fs
+d46f57d16f6ebdce7ba583c4ab38a041f59e4aabde2cc87ce8f17c6b9dcc2203 /kvmapp/system/init.d/S03usbdev
+7ef70f9f3be680725f984d72919890e649fd38138506b2f2fb62ee6bf86dab42 /kvmapp/system/init.d/S15kvmhwd
+b8bf9834399b3a8f92248dd9ded9e4653b2c2b720f18b0772d4feee0ca45d4f1 /kvmapp/system/init.d/S15kvmhwd copy
+a8301de6d3bb5d46948771a6aabdceeba2327d04c4f54b59813e6109a9a0a145 /kvmapp/system/init.d/S30eth
+51c4fe058dc555aac79562b8ce1eb8ff09bb3e160442dcf654f1fa4142d7b49b /kvmapp/system/init.d/S95nanokvm
+5ecc17f49d2ee7d178ef69d2f043b31eb7ec7427f324678c3f392353ea9ff13c /kvmapp/system/init.d/S98tailscaled
+d40419159a4065de8b7693e0de59c477de36373f24fe164e50afb37d674ed755 /kvmapp/system/ko/soph_mipi_rx.ko
+e840218f70dac0ddc1391cc1a0e84733c7f36ad90da61cd3e90e1d9c10ac9057 /kvmapp/system/update-nanokvm.py
+7b3ff271f1373cfb97e9e53349794e1450f3794e4c0788c54a2060c7596da821 /kvmapp/version
-42ac55f6ad8ce1f615448dd9862480c5cc329bdd7212bce7d71b381859428750 /mnt/system/ko/soph_mipi_rx.ko
+08f1b430740524987440e4e1c8464e0365e729b39b6a845b695ce7774d450009 /mnt/system/ko/soph_mipi_rx.ko
+3de65149406ccfdfa4336433d3ecd5177edce85ba388046467d94341334107ff /var/lib/seedrng/seed.no-credit
+e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /var/lib/tailscale/tailscaled.log1.txt
+e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 /var/lib/tailscale/tailscaled.log2.txt
+9a3d337f79bea85da6eca840928a5f2567cd0de30547b0b8e95f924dcaa5ff81 /var/lib/tailscale/tailscaled.log.conf
+44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a /var/lib/tailscale/tailscaled.state

To organize the changes, I've categorized them into the following groups:

  • New files
  • Altered files
  • Moved files
  • Deleted files
  • Web asset files

New files

  • /device_key: 8 byte (16 lowercase hex characters) device key. Appears to be used to identify the model when phoning home based on this, as well as updating the device based on update-nanokvm.py (Below).
  • /etc/factory: factory image indicator? (empty; no reference to this in the source code).
  • /etc/kvm.disk0: KVM disk image? (empty; no reference to this in the source code).
  • /etc/kvm/frame_detact: enables KVM frame detection? (empty).
  • /etc/kvm/hdmi_version: HDMI version. Contains: c.
  • /etc/kvm/hw: hardware revision. Contains: beta.
  • /etc/kvm/server.yaml: NanoKVM server configuration. Contains:
proto: http
port:
  http: 80
  https: 443
cert:
  crt: server.crt
  key: server.key
logger:
  level: info
  file: stdout
authentication: enable
secretKey: ""
  • /etc/kvm/update-nanokvm.py: NanoKVM update script. Contains:
import os
import shutil
import time
import zipfile

import requests

temporary = "/root/.kvm-cache/"


def mkdir():
    is_exists = os.path.exists(temporary)
    if is_exists:
        shutil.rmtree(temporary)
    os.mkdir(temporary)
    print(f"create temporary directory {temporary}")


def read(file):
    with open(file, "r") as f:
        content = f.read()
        return content.replace("\n", "")


def download_firmware():
    print("download firmware...")

    now = int(time.time())
    url = f"https://cdn.sipeed.com/nanokvm/latest.zip?n={now}"
    print(f"download from {url}")

    response = requests.get(url)

    if response.status_code != 200:
        raise Exception(f"download firmware failed, status: {response.status_code}")

    content_type = response.headers.get("content-type")
    if content_type != "application/zip":
        raise Exception(f"download firmware failed, content_type: {content_type}")

    zip_file = f"{temporary}/latest.zip"
    with open(zip_file, "wb") as f:
        for chunk in response.iter_content(chunk_size=1024):
            f.write(chunk)

    with zipfile.ZipFile(zip_file, "r") as f:
        f.extractall(temporary)

    print("download firmware done")


def download_lib():
    print("download lib...")

    device_key = read("/device_key")

    url = f"https://maixvision.sipeed.com/api/v1/nanokvm/encryption?uid={device_key}"
    headers = {"token": "MaixVision2024"}
    response = requests.get(url, headers=headers, stream=True)

    if response.status_code != 200:
        raise Exception(f"download lib failed, status: {response.status_code}")

    content_type = response.headers.get("content-type")
    if content_type != "application/octet-stream":
        raise Exception(f"download lib failed, content_type: {content_type}")

    lib_file = f"{temporary}/libmaixcam_lib.so"
    with open(lib_file, "wb") as f:
        f.write(response.content)

    lib_dir = f"{temporary}/latest/kvm_system/dl_lib/"
    shutil.copy(lib_file, lib_dir)

    print("download lib done")


def update():
    backup_dir = "/root/old"
    firmware_dir = "/kvmapp"

    if os.path.exists(backup_dir):
        shutil.rmtree(backup_dir)

    if os.path.exists(firmware_dir):
        shutil.move(firmware_dir, backup_dir)

    shutil.move(f"{temporary}/latest", firmware_dir)


def change_permissions():
    for root, dirs, files in os.walk("/kvmapp"):
        os.chmod(root, 0o755)

        for file in files:
            file_path = os.path.join(root, file)
            os.chmod(file_path, 0o755)

    print("change permissions done")


def main():
    try:
        print("stop service...")
        os.system("/etc/init.d/S95nanokvm stop")

        print("start update......")

        mkdir()
        download_firmware()
        download_lib()
        update()
        change_permissions()

        version = read("/kvmapp/version")
        print(f"update to {version} success.")
        print("restart service\nthe nanokvm will reboot")
    except Exception as e:
        print(f"update failed\n{e}")
    finally:
        shutil.rmtree(temporary)
        os.system("/etc/init.d/S95nanokvm restart")


if __name__ == "__main__":
    main()
  • /etc/sysctl.d/99-tailscale.conf: Tailscale system configuration. Contains:
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
  • /etc/udhcpd.usb0.conf: udhcpd DHCP server over USB configuration. Contains:
start 10.161.81.100
end 10.161.81.200
interface usb0
pidfile /var/run/udhcpd.usb0.pid
lease_file /var/lib/misc/udhcpd.usb0.leases
option subnet 255.255.255.0
option lease 864000
  • /etc/ssh/ssh_host_ecdsa_key: OpenSSH server ECDSA private key.
  • /etc/ssh/ssh_host_ecdsa_key.pub: OpenSSH server ECDSA public key.
  • /etc/ssh/ssh_host_ed25519_key: OpenSSH server Ed25519 private key.
  • /etc/ssh/ssh_host_ed25519_key.pub: OpenSSH server Ed25519 public key.
  • /etc/ssh/ssh_host_rsa_key: OpenSSH server RSA private key.
  • /etc/ssh/ssh_host_rsa_key.pub: OpenSSH server RSA public key.
  • /kvmapp/kvm/fps: KVM FPS. Contains: 30.
  • /kvmapp/kvm/height: KVM height. Contains: 1080.
  • /kvmapp/kvm/now_fps: KVM current FPS. Contains: 0.
  • /kvmapp/kvm/qlty: KVM quality. Contains: 2000.
  • /kvmapp/kvm/res: KVM resolution. Contains: 720.
  • /kvmapp/kvm/state: KVM state. Contains: 0.
  • /kvmapp/kvm/type: KVM encode type. Contains: h264.
  • /kvmapp/kvm/width: KVM width. Contains: 1920.
  • /kvmapp/server/dl_lib/libkvm.so: KVM library.
  • /kvmapp/system/init.d/S01fs: same as /etc/init.d/S01fs.
  • /kvmapp/system/init.d/S03usbdev: same as /etc/init.d/S03usbdev.
  • /kvmapp/system/init.d/S15kvmhwd: same as /etc/init.d/S15kvmhwd.
  • /kvmapp/system/init.d/S15kvmhwd copy: newer version (2.1) of /etc/init.d/S15kvmhwd:
#!/bin/sh
# kvmhwd Rev2.1

Alpha_OLED_RST_Pin=371
Beta_OLED_RST_Pin=502
Beta_OLED_SCL=595
Beta_OLED_SDA=507
WiFi_EN_Pin=506
Alpha_PWR_LED_Pin=504
Alpha_HDD_LED_Pin=505
Alpha_PWR_KEY_Pin=503
Alpha_RST_KEY_Pin=507
Beta_PWR_LED_Pin=504
Beta_PWR_KEY_Pin=503
Beta_RST_KEY_Pin=505

init_alpha_hw(){
  devmem 0x030010D0 32 0x2  # I2C1_SCL
  devmem 0x030010DC 32 0x2  # I2C1_SDA
  devmem 0x030010D4 32 0x3  # OLED_RST
  devmem 0x0300103C 32 0x3  # GPIOA15
  devmem 0x03001050 32 0x3  # GPIOA22
  devmem 0x0300105C 32 0x3  # GPIOA23
  devmem 0x03001060 32 0x3  # GPIOA24
  devmem 0x03001054 32 0x3  # GPIOA25
  devmem 0x03001058 32 0x3  # GPIOA27

  echo ${Alpha_OLED_RST_Pin} > /sys/class/gpio/export  # OLED_RST
  echo out > /sys/class/gpio/gpio${Alpha_OLED_RST_Pin}/direction
  echo 1 > /sys/class/gpio/gpio${Alpha_OLED_RST_Pin}/value

  echo ${Alpha_PWR_LED_Pin} > /sys/class/gpio/export   # pwr led
  echo ${Alpha_HDD_LED_Pin} > /sys/class/gpio/export   # hdd led
  echo ${Alpha_PWR_KEY_Pin} > /sys/class/gpio/export   # pwr key
  echo ${Alpha_RST_KEY_Pin} > /sys/class/gpio/export   # rst key

  echo in > /sys/class/gpio/gpio${Alpha_PWR_LED_Pin}/direction     # pwr led
  echo in > /sys/class/gpio/gpio${Alpha_HDD_LED_Pin}/direction     # hdd led
  echo out > /sys/class/gpio/gpio${Alpha_PWR_KEY_Pin}/direction    # pwr key
  echo out > /sys/class/gpio/gpio${Alpha_RST_KEY_Pin}/direction    # rst key

  rmmod /mnt/system/ko/i2c-gpio.ko
  rmmod /mnt/system/ko/i2c-algo-bit.ko

  # rm /etc/init.d/S25wifimod
  # rm /etc/init.d/S30wifi
}

init_beta_pcie_hw(){
  devmem 0x0300103C 32 0x3  # GPIOA15
  devmem 0x03001050 32 0x3  # GPIOA22
  devmem 0x0300105C 32 0x3  # GPIOA23
  devmem 0x03001060 32 0x3  # GPIOA24
  devmem 0x03001054 32 0x3  # GPIOA25
  devmem 0x03001058 32 0x3  # GPIOA27

  devmem 0x030010E4 32 0x0  # SDIO CLK
  devmem 0x030010E0 32 0x0  # SDIO CMD
  devmem 0x030010DC 32 0x0  # SDIO D0
  devmem 0x030010D8 32 0x0  # SDIO D1
  devmem 0x030010D4 32 0x0  # SDIO D2
  devmem 0x030010D0 32 0x0  # SDIO D3

  echo ${Beta_OLED_RST_Pin} > /sys/class/gpio/export  # Beta OLED_RST
  echo out > /sys/class/gpio/gpio${Beta_OLED_RST_Pin}/direction
  echo 1 > /sys/class/gpio/gpio${Beta_OLED_RST_Pin}/value

  echo ${Beta_PWR_LED_Pin} > /sys/class/gpio/export   # pwr led
  echo ${Beta_PWR_KEY_Pin} > /sys/class/gpio/export   # pwr key
  echo ${Beta_RST_KEY_Pin} > /sys/class/gpio/export   # rst key

  echo in > /sys/class/gpio/gpio${Beta_PWR_LED_Pin}/direction     # pwr led
  echo out > /sys/class/gpio/gpio${Beta_PWR_KEY_Pin}/direction    # pwr key
  echo out > /sys/class/gpio/gpio${Beta_RST_KEY_Pin}/direction    # rst key

  rmmod /mnt/system/ko/i2c-gpio.ko
  rmmod /mnt/system/ko/i2c-algo-bit.ko
  insmod /mnt/system/ko/i2c-algo-bit.ko
  insmod /mnt/system/ko/i2c-gpio.ko
}

kvm_hw_detect(){
  if [ -e /etc/kvm/hw ]
  then
    echo "/etc/kvm/hw exist"
  else
    echo "/etc/kvm/hw not exist"
    if [ -d "/etc/kvm/" ]
    then
      echo "/etc/kvm/ exist"
    else
      mkdir /etc/kvm/
    fi
    devmem 0x0300104C 32 0x3  # GPIOA26 / WiFi_EN
    echo ${WiFi_EN_Pin} > /sys/class/gpio/export  # WiFi_EN
    echo out > /sys/class/gpio/gpio${WiFi_EN_Pin}/direction
    echo 0 > /sys/class/gpio/gpio${WiFi_EN_Pin}/value

    devmem 0x0300103C 32 0x3  # GPIOA15
    devmem 0x03001050 32 0x3  # GPIOA22
    devmem 0x0300105C 32 0x3  # GPIOA23
    devmem 0x03001060 32 0x3  # GPIOA24
    devmem 0x03001054 32 0x3  # GPIOA25
    devmem 0x03001058 32 0x3  # GPIOA27

    devmem 0x030010D0 32 0x2  # I2C1_SCL
    devmem 0x030010DC 32 0x2  # I2C1_SDA
    devmem 0x030010D4 32 0x3  # OLED_RST
    echo ${Alpha_OLED_RST_Pin} > /sys/class/gpio/export  # OLED_RST
    echo out > /sys/class/gpio/gpio${Alpha_OLED_RST_Pin}/direction
    echo 1 > /sys/class/gpio/gpio${Alpha_OLED_RST_Pin}/value

    kvm_tmp=$(i2cdetect -ry 1 0x3d 0x3d | grep 3d)
    if [ -n "$kvm_tmp" ]
    then
      # alpha hw
      echo "alpha" > /etc/kvm/hw
    else
      # beta/pcie hw
      echo ${Alpha_OLED_RST_Pin} > /sys/class/gpio/unexport  # OLED_RST
      echo ${Beta_OLED_RST_Pin} > /sys/class/gpio/export  # Beta_OLED_RST_Pin
      echo out > /sys/class/gpio/gpio${Beta_OLED_RST_Pin}/direction
      echo 1 > /sys/class/gpio/gpio${Beta_OLED_RST_Pin}/value

      rmmod /mnt/system/ko/i2c-gpio.ko
      rmmod /mnt/system/ko/i2c-algo-bit.ko
      insmod /mnt/system/ko/i2c-algo-bit.ko
      insmod /mnt/system/ko/i2c-gpio.ko

      kvm_tmp=$(i2cdetect -ry 4 0x2c 0x2c | grep 2c)
      if [ -n "$kvm_tmp" ]
      then
        echo "c" > /etc/kvm/hdmi_version
      else
        echo "u" > /etc/kvm/hdmi_version
      fi

      kvm_tmp=$(i2cdetect -ry 5 0x3c 0x3c | grep 3c)
      if [ -n "$kvm_tmp" ]
      then
        echo "pcie" > /etc/kvm/hw
        sync
        reboot
      else
        echo "beta" > /etc/kvm/hw
        # rm /etc/init.d/S25wifimod
        # rm /etc/init.d/S30wifi
        sync
      fi

      echo 1 > /sys/class/gpio/gpio${WiFi_EN_Pin}/value
      echo ${WiFi_EN_Pin} > /sys/class/gpio/unexport  # WiFi_EN
    fi
  fi
  sync
}

kvm_hw_init(){
    FIND_FILE="/etc/kvm/hw"
    if [ `grep -c "alpha" $FIND_FILE` -ne '0' ]
    then
        echo "hw = alpha!"
        init_alpha_hw
    fi
    if [ `grep -c "beta" $FIND_FILE` -ne '0' ]
    then
        echo "hw = beta!"
        init_beta_pcie_hw
    fi
    if [ `grep -c "pcie" $FIND_FILE` -ne '0' ]
    then
        echo "hw = pcie!"
        init_beta_pcie_hw
    fi
}

case "$1" in
  start)
    kvm_hw_detect
    kvm_hw_init
  ;;
  re-detect)
    rm /etc/kvm/hw
    kvm_hw_detect
    kvm_hw_init
  ;;
  re-init)
    kvm_hw_init
  ;;
esac
  • /kvmapp/system/init.d/S30eth: same as /etc/init.d/S30eth.
  • /kvmapp/system/init.d/S95nanokvm: same as /etc/init.d/S95nanokvm.
  • /kvmapp/system/init.d/S98tailscaled: Tailscale daemon initialization. Contains:
#!/bin/sh

DAEMON="tailscaled"
PIDFILE="/var/run/$DAEMON.pid"

# Set the port to listen on for incoming VPN packets.
# Remote nodes will automatically be informed about the new port number,
# but you might want to configure this in order to set external firewall
# settings.
PORT="41641"

# Extra flags you might want to pass to tailscaled.
FLAGS=""

# You need tailscaled at /usr/sbin to server, and tailscale at /usr/bin to operate
# STATIC version needed. Download page at https://pkgs.tailscale.com/stable/#static
PKG_URL_LATEST="https://pkgs.tailscale.com/stable/tailscale_latest_riscv64.tgz"
[ ! -x /usr/sbin/$DAEMON ] &&
    echo "/usr/sbin/$DAEMON not found, please download it from $PKG_URL_LATEST" &&
    echo "Then unpack it, copy $DAEMON to /usr/sbin and copy tailscale to /usr/bin" &&
    exit 1
VERSION=$(/usr/sbin/$DAEMON --version|sed -n '1p'|xargs echo -n)

[ -x /usr/bin/tailscale ] || echo "/usr/bin/tailscale not found, your installation of tailscale may be broken"

# just for those need forwarding
[ ! -f /etc/sysctl.d/99-tailscale.conf ] &&
    mkdir -p /etc/sysctl.d/ &&
    echo "missing /etc/sysctl.d/99-tailscale.conf, try make it below:" &&
    (tee /etc/sysctl.d/99-tailscale.conf <<EOF
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1
EOF
    ) &&
    echo "if this message repeats showing, please look at $0 if you need forwarding"

case "$1" in
        start)
                printf "Starting $DAEMON[$VERSION]: "
                start-stop-daemon -S -bmq -p "$PIDFILE" -x "/usr/sbin/$DAEMON" -- \
                    --state=/var/lib/tailscale/tailscaled.state \
                    --socket=/var/run/tailscale/tailscaled.sock \
                    --port=${PORT} \
                    $FLAGS
                [ $? = 0 ] && echo "OK" || echo "FAIL"
                ;;
        stop)
                printf "Stopping $DAEMON: "
                start-stop-daemon -K -p "$PIDFILE"
                [ $? = 0 ]  && (echo "OK"; rm -f "$PIDFILE") || echo "FAIL"
                printf "cleaning tailscaled: "
                /usr/sbin/$DAEMON --cleanup &>/dev/null
                [ $? = 0 ] && echo "OK" || echo "FAIL"
                ;;
        restart|reload)
                $0 stop
                $0 start
                ;;
        doc)
                cat <<EOF
To use tailscale, you need to meet these conditions below:
  1. Both tailscale and tailscaled were installed.
  2. At least one tailscale's account were registered.
     (https://login.tailscale.com/start)
  3. Your NanoKVM device must keep online.

Then, follow the steps below:
  1. Login in https://login.tailscale.com on your PC
     to enter into yout admin console.
  2. Run 'tailscale login' on your device, and copy the link showed
     to open on your PC, and confirm the auth.
  3. Congratulations, your NanoKVM device is now on the tailnet, try to
     visit it from all your device which on the same tailnet.
  4. run 'tailscale set --webclient' and manage your device
     on the web interface from localnet and tailenet.

Added: no more action to be repeat after your device reboot.
EOF
                echo ""
                cat <<EOF
为了正常使用 tailscale, 你需要满足以下几个条件:
  1. tailscale 和 tailscaled 这两个静态链接的二进制程序
     都已经正确安装在系统上。
  2. 至少注册一个 tailscale 的帐号才能使用其服务。
     (https://login.tailscale.com/start)
  3. 你的 NanoKVM 设备必须保持在线。

然后,跟着以下步骤操作:
  1. 在你的电脑上登录 https://login.tailscale.com 以进入控制台。
  2. 在你的 NanoKVM ssh 终端上执行 'tailscale login', 然后复制
     出现的链接到浏览器上,登录并通过验证。
  3. 祝贺,你的 NanoKVM 现在已经加入了 tailnet 然后你可以从任意
     同样已加入同一 tailnet 的设备去访问你的 NanoKVM。
  4. 执行 'tailscale set --webclient' 然后你就可以从 '局域网' 和
     'tailnet' 来访问特定网页,用来管理你的设备。

补充: 不需要重复上面的操作,哪怕你的设备重启过。
EOF
                ;;
        *)
                echo "Usage: $0 {start|stop|restart}"
                exit 1
esac

exit 0
  • /kvmapp/system/ko/soph_mipi_rx.ko: SOPHON MIPI RX driver (Different from /mnt/system/ko/soph_mipi_rx.ko).
  • /kvmapp/system/update-nanokvm.py: same as /etc/kvm/update-nanokvm.py.
  • /kvmapp/version: NanoKVM version. Contains: 2.1.1.
  • /var/lib/seedrng/seed.no-credit: SeedRNG seed file.
  • /var/lib/tailscale/tailscaled.log1.txt: Tailscale log file (empty).
  • /var/lib/tailscale/tailscaled.log2.txt: Tailscale log file (empty).
  • /var/lib/tailscale/tailscaled.log.conf: Tailscale log configuration file. Contains:
{
  "Collection": "tailnode.log.tailscale.io",
  "PrivateID": "[REDACTED]",
  "PublicID": "[REDACTED]"
}
  • /var/lib/tailscale/tailscaled.state: Tailscale state. Contains: {}.

Altered files

  • /etc/hostname: Hostname (Changed from licheervnano to kvm-a151 with the factory image).
  • /etc/hosts: Hard-coded hosts (Same change as /etc/hostname).
  • /etc/init.d/S01fs: mount filesystems (Bug fix?).
  • /etc/init.d/S03usbdev: USB device initialization (Bug fix?).
  • /etc/init.d/S15kvmhwd: GPIO and I2C initialization (Bug fix?).
  • /etc/init.d/S30eth: Ethernet initialization (Bug fix?).
  • /etc/init.d/S95nanokvm: NanoKVM server and iptables initialization (Bug fix?).
  • /kvmapp/kvm_system/dl_lib/libmaixcam_lib.so: MaixVision camera library (Updated)*.
  • /kvmapp/kvm_system/dl_lib/libvpu.so / /kvmapp/server/dl_lib/libvpu.so: VPU library (Updated and moved)*.
  • /kvmapp/server/NanoKVM-Server: NanoKVM server binary (Updated)*.
  • /mnt/system/ko/soph_mipi_rx.ko: SOPHON MIPI RX driver (Updated)* (Different from /kvmapp/system/ko/soph_mipi_rx.ko).

Moved files

Old pathNew pathDescription
/etc/input-event-daemon.conf.bak/etc/input-event-daemon.confInput event daemon configuration
/kvmapp/kvm_system/dl_lib/libaaccomm2.so/kvmapp/server/dl_lib/libaaccomm2.soUnknown library (Audio?)
/kvmapp/kvm_system/dl_lib/libaacdec2.so/kvmapp/server/dl_lib/libaacdec2.soCvitek AAC decoder library
/kvmapp/kvm_system/dl_lib/libaacenc2.so/kvmapp/server/dl_lib/libaacenc2.soCvitek AAC encoder library
/kvmapp/kvm_system/dl_lib/libaacsbrdec2.so/kvmapp/server/dl_lib/libaacsbrdec2.soUnknown library (Audio?)
/kvmapp/kvm_system/dl_lib/libaacsbrenc2.so/kvmapp/server/dl_lib/libaacsbrenc2.soUnknown library (Audio?)
/kvmapp/kvm_system/dl_lib/libae.so/kvmapp/server/dl_lib/libae.soUnknown library (Auto Exposure?)
/kvmapp/kvm_system/dl_lib/libaf.so/kvmapp/server/dl_lib/libaf.soUnknown library (Auto Focus?)
/kvmapp/kvm_system/dl_lib/libawb.so/kvmapp/server/dl_lib/libawb.soUnknown library (Auto White Balance?)
/kvmapp/kvm_system/dl_lib/libcli.so/kvmapp/server/dl_lib/libcli.solibcli
/kvmapp/kvm_system/dl_lib/libcvi_audio.so/kvmapp/server/dl_lib/libcvi_audio.soCvitek audio library
/kvmapp/kvm_system/dl_lib/libcvi_bin_isp.so/kvmapp/server/dl_lib/libcvi_bin_isp.soCvitek Image Signal Processor (ISP) library
/kvmapp/kvm_system/dl_lib/libcvi_bin.so/kvmapp/server/dl_lib/libcvi_bin.soUnknown Cvitek library
/kvmapp/kvm_system/dl_lib/libcvi_ispd2.so/kvmapp/server/dl_lib/libcvi_ispd2.soCvitek Image Signal Processor library
/kvmapp/kvm_system/dl_lib/libcvi_ive.so/kvmapp/server/dl_lib/libcvi_ive.soCvitek Intelligent Vision Engine (IVE) library
/kvmapp/kvm_system/dl_lib/libcvi_RES1.so/kvmapp/server/dl_lib/libcvi_RES1.soUnknown Cvitek library (Audio?)
/kvmapp/kvm_system/dl_lib/libcvi_ssp.so/kvmapp/server/dl_lib/libcvi_ssp.soUnknown Cvitek library (Audio?)
/kvmapp/kvm_system/dl_lib/libcvi_VoiceEngine.so/kvmapp/server/dl_lib/libcvi_VoiceEngine.soUnknown Cvitek library (Voice recognition?)
/kvmapp/kvm_system/dl_lib/libcvi_vqe.so/kvmapp/server/dl_lib/libcvi_vqe.soCvitek Voice Quality Enhancement (VQE) library
/kvmapp/kvm_system/dl_lib/libdnvqe.so/kvmapp/server/dl_lib/libdnvqe.soUnknown Cvitek library (Audio?)
/kvmapp/kvm_system/dl_lib/libini.so/kvmapp/server/dl_lib/libini.solibini
/kvmapp/kvm_system/dl_lib/libisp_algo.so/kvmapp/server/dl_lib/libisp_algo.soUnknown library (Image Signal Processor?)
/kvmapp/kvm_system/dl_lib/libisp.so/kvmapp/server/dl_lib/libisp.soUnknown library (Image Signal Processor?)
/kvmapp/kvm_system/dl_lib/libjson-c.so.5/kvmapp/server/dl_lib/libjson-c.so.5json-c
/kvmapp/kvm_system/dl_lib/libmipi_tx.so/kvmapp/server/dl_lib/libmipi_tx.soMIPI transmitter library
/kvmapp/kvm_system/dl_lib/libmisc.so/kvmapp/server/dl_lib/libmisc.soMiscellaneous library
/kvmapp/kvm_system/dl_lib/libosdc.so/kvmapp/server/dl_lib/libosdc.soOn-Screen Display Controller library
/kvmapp/kvm_system/dl_lib/libraw_dump.so/kvmapp/server/dl_lib/libraw_dump.soUnknown library (Image Signal Processor?)
/kvmapp/kvm_system/dl_lib/libsys.so/kvmapp/server/dl_lib/libsys.soSystem library
/kvmapp/kvm_system/dl_lib/libtinyalsa.so/kvmapp/server/dl_lib/libtinyalsa.soTinyALSA
/kvmapp/kvm_system/dl_lib/libvdec.so/kvmapp/server/dl_lib/libvdec.soVideo decoder library
/kvmapp/kvm_system/dl_lib/libvenc.so/kvmapp/server/dl_lib/libvenc.soVideo encoder library

Deleted files

  • /etc/init.d/S04backlight: backlight initialization.
  • /etc/init.d/S05tp: touchscreen initialization.
  • /etc/init.d/S25wifimod: WiFi module initialization.
  • /etc/init.d/S30wifi: WiFi hostapd/wpa_supplicant initialization.
  • /etc/init.d/S40bluetoothd: Bluetooth daemon initialization.
  • /etc/init.d/S99audtest: audio test.
  • /etc/init.d/S99camtest: camera test.
  • /etc/init.d/S99ednctest: encoder/decoder test.
  • /etc/init.d/S99input-event-daemon: input event daemon.
  • /etc/init.d/S99ivetest: Cvitek Intelligent Vision Engine (IVE) NPU test?
  • /etc/init.d/S99kvmtest: MultiMedia Framework (MMF) test.
  • /etc/init.d/S99lcdtest: LCD screen test.
  • /etc/init.d/S99loadtest: CPU load test?
  • /etc/init.d/S99local: tests if /etc/rc.local can be executed?
  • /etc/init.d/S99modeltest: machine learning model (resize_net_3_int8.cvimodel) test.
  • /etc/init.d/S99nettest: network test.
  • /etc/init.d/S99nntest: neural network (mobilenet_v2_rgb_224_int8.mud) test.
  • /etc/init.d/S99pinmux: GPIO UART initialization.
  • /etc/init.d/S99resizefs: resize data partition (Commented out).
  • /etc/init.d/S99temptest: CPU temperature test.
  • /kvmapp/kvm_new_img: new KVM image indicator? (empty; no reference to this in the source code).
  • /kvmapp/server/.DS_Store: macOS directory metadata file. Possible artifact of development machine.

Web asset files

Because of minification and Vite (the build tool used by Sipeed), it's harder to categorize the changes to the web assets.

  • /kvmapp/server/web/assets/http-DYeZYrT9.js: deleted in the factory image.
  • /kvmapp/server/web/assets/auth-Dp7nO6B1.js -> /kvmapp/server/web/assets/auth-K_uPa-EP.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/encrypt-BrE29Rwk.js -> /kvmapp/server/web/assets/encrypt-DeSTkaMV.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/head-Dm4gnfbF.js -> /kvmapp/server/web/assets/head-ODJ_welb.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/index-B_b2izJx.js -> /kvmapp/server/web/assets/index-yG9y9dy_.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/index-B_guo0tA.js -> /kvmapp/server/web/assets/index-B4bVQUcw.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/index-CJS5-vSY.js -> /kvmapp/server/web/assets/index-BUn-WgOW.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/index-DrXHD3oy.js -> /kvmapp/server/web/assets/index-PuU3XSNw.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/index-DGWJClpJ.js -> /kvmapp/server/web/assets/index-DRIQFk0N.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/index-hge731-N.js -> /kvmapp/server/web/assets/index-DszERfC0.js: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/index-D_Fu7P2y.css -> /kvmapp/server/web/assets/index-Bl_2VLkA.css: renamed in the factory image, altered.
  • /kvmapp/server/web/assets/index-u2n1Wr7j.css -> /kvmapp/server/web/assets/index-L7H6lV1d.css: renamed in the factory image, altered.
  • /kvmapp/server/web/index.html: altered in the factory image (to account for the different asset names).

VirusTotal

I ran all the changed binary files through VirusTotal and got no hits. While this is a good sign that the changes are benign, this is no guarantee of the image's integrity.

Conclusion

While it seems some of the differences between the GitHub and factory images are artifacts from development (i.e., the .DS_store file) or testing (i.e., the Tailscale artifacts), some of the changes are more puzzling (i.e., to the NanoKVM-Server binary) given that it should be running the same version. This hints that either version numbers are not bumped correctly and/or the factory image is moderately different. I also briefly checked the other GitHub releases; none had the same NanoKVM-Server binary as the factory image 😕.

I also don't love that the SSH keys are pre-initialized from the factory, but this is possibly from a power-on test. Anyone could've copied these keys off the SD card before it got to me and could MiTM my SSH connections if I didn't change them. Nevertheless, at the time of writing, this would appear minor compared to using root as the default username/password for SSH. The Tailscale log state containing the private and public IDs is a bit concerning in principle; in practice, it doesn't seem to be a significant security risk given that it appears to be used only for logging purposes. Nevertheless, the fix to these concerns is simple: just flash the GitHub image.

Wishlist

For anyone at Sipeed who might be reading this, here are some things I'd love to see in the future:

  1. Use accurate versioning of all images (Perhaps include the commit hash in the VER file in addition to the semantic version).
  2. (Re)initialize SSH keys on the first boot.
  3. Include a Software Bill of Materials (SBOM) in all images to identify vulnerable dependencies.
  4. Cryptographically sign all images.

© 2025 Wakeful Cloud, all rights reserved.