fix: improvements across the board

* Update README.md, make sure the disclaimer is seen before install instructions.
* update ustorage to have temp readings on some samsung ssds (stupid samsung)
* Patch and support ulcmd relying on output from ubnteeprom
* Move away from ubnthal FINALLY now that we patched ulcmd (hacky but works!)
* added README.md to ubnteeprom, since I expect at somepoint folks will fork/use it for other projects.
* Added our own kernel module to force mtd's RO, which does a better job than ubnthal did :)
This commit is contained in:
Chris Blake 2024-06-16 13:50:44 -05:00
parent 7858593f11
commit 116b6591a9
11 changed files with 173 additions and 18 deletions

View file

@ -2,20 +2,26 @@
Firmware builder to convert your Unifi NVR/Unifi NVR Pro into an OpenMediaVault NAS appliance. Firmware builder to convert your Unifi NVR/Unifi NVR Pro into an OpenMediaVault NAS appliance.
**This repo is still under heavy development and should be considered early alpha!** **This repo is still under heavy development and should be considered alpha!**
## Supported Devices ## Supported Devices
* UNVR **(Currently Untested!)** * UNVR **(Currently Untested!)**
* UNVR Pro * UNVR Pro
## Disclaimer
Note that since prebuilt Ubiquiti software is currently required for this firmware, this repo doesn't have prebuilt images available. This is to prevent redistribution of Ubiquiti's IP, so please DO NOT ASK! Also, by using this repo you accept all risk associated with it including but not limited to voiding your warranty and releasing all parties from any liability associated with your device and this software. PROCEED AT YOUR OWN RISK!
## Usage ## Usage
1. Download the required UNVR firmware for your device, and place it in the unifi-firmware directory. Please see the README.md in that directory for more information. 1. Download the required UNVR firmware for your device, and place it in the unifi-firmware directory. Please see the README.md in that directory for more information.
2. Make sure your system has the required packages installed for this repo, which are: 2. Make sure your linux system has the required packages installed for this repo, which are:
`docker-ce losetup wget sudo make qemu-user-static squashfs-tools` `docker-ce losetup wget sudo make qemu-user-static squashfs-tools`
Note that building from OSX/Windows is not supported. A Linux host is **REQUIRED**.
3. Run make with your board name set, and sit back and wait for the firmware image to build. Depending on your computer, this may take around an hour or so. 3. Run make with your board name set, and sit back and wait for the firmware image to build. Depending on your computer, this may take around an hour or so.
For the UNVR: `BOARD=UNVR make` For the UNVR: `BOARD=UNVR make`
@ -139,7 +145,3 @@ To restore back to the factory UNVR/UNVR Pro firmware, you can do the following
* Need to simplify the install process, this should be much easier once I can get latest GPL kernel source (no more uboot env stuff) * Need to simplify the install process, this should be much easier once I can get latest GPL kernel source (no more uboot env stuff)
* Reset Button * Reset Button
* Only works to reboot the system, may wire this up to reset the WebUI password in OpenMediaVault down the road * Only works to reboot the system, may wire this up to reset the WebUI password in OpenMediaVault down the road
## Disclaimer
Note that since prebuild Ubiquiti software is required for this tool to work, this repo will never have prebuilt images available. This is to prevent redistribution of Ubiquiti's IP, so please DO NOT ASK! Also, by using this repo you accept all risk associated with it including but not limited to voiding your warranty and releasing all parties from any liability associated with your device and this software.

View file

@ -125,12 +125,22 @@ class UNVRDiskInfo:
def __parse_disk_temp(self): def __parse_disk_temp(self):
try: try:
return int( try:
self.__parse_smartctl( # First try the expected 194
self.__smartctl_output, return int(
r"^194 [\w-]+\s+0x\d+\s+\d+\s+\d+\s+\d+\s+[\w-]+\s+\w+\s+\S+\s+(\d+)(?:\s[\(][^)]*[\)])?$", self.__parse_smartctl(
self.__smartctl_output,
r"^194 [\w-]+\s+0x\d+\s+\d+\s+\d+\s+\d+\s+[\w-]+\s+\w+\s+\S+\s+(\d+)(?:\s[\(][^)]*[\)])?$",
)
)
except:
# Some other SSDs (cough, samsung) use 190 for airflow temp -_-
return int(
self.__parse_smartctl(
self.__smartctl_output,
r"^190 [\w-]+\s+0x\d+\s+\d+\s+\d+\s+\d+\s+[\w-]+\s+\w+\s+\S+\s+(\d+)(?:\s[\(][^)]*[\)])?$",
)
) )
)
except: except:
return None return None

View file

@ -3,7 +3,8 @@
case "$1" in case "$1" in
start) start)
# Load our kernel modules # Load our kernel modules
/usr/sbin/modprobe ubnthal # /usr/sbin/modprobe ubnthal # No longer needed, ubnteeprom replaced it in userspace
/usr/sbin/modprobe ubnt-mtd-lock # Force our /dev/mtd* as RO
/usr/sbin/modprobe btrfs /usr/sbin/modprobe btrfs
# Set our kernel panic timeout SUPER short so we reboot on crash # Set our kernel panic timeout SUPER short so we reboot on crash

View file

@ -4,10 +4,12 @@
case "$(ubnteeprom -systeminfo -key shortname)" in case "$(ubnteeprom -systeminfo -key shortname)" in
"UNVRPRO") "UNVRPRO")
# Ensure our tmp file with info is generated
ubnteeprom -systeminfo > /tmp/.ubnthal_system_info
# Is ulcmd running already? if so, assume it was not done via systemd so let's # Is ulcmd running already? if so, assume it was not done via systemd so let's
# kill and respawn as this is our systemd entry script for the service, and we # kill and respawn as this is our systemd entry script for the service, and we
# need to have it foregrounded as we act as the "daemon" here. # need to have it foregrounded as we act as the "daemon" here.
if ! pidof -q ulcmd; then if pidof -q ulcmd; then
killall ulcmd killall ulcmd
fi fi
# Restart ulcmd # Restart ulcmd

View file

@ -6,10 +6,10 @@ scripts_path="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
# Make our temp builddir outside of the world of mounts for SPEEDS # Make our temp builddir outside of the world of mounts for SPEEDS
kernel_builddir=$(mktemp -d) kernel_builddir=$(mktemp -d)
tar -xzf ${root_path}/downloads/${kernel_filename} -C ${kernel_builddir} tar -xzf "${root_path}/downloads/${kernel_filename}" -C ${kernel_builddir}
# Exports baby # Exports baby
export PATH=${build_path}/toolchain/${toolchain_bin_path}:${PATH} export PATH="${build_path}/toolchain/${toolchain_bin_path}":${PATH}
export GCC_COLORS=auto export GCC_COLORS=auto
export CROSS_COMPILE=${toolchain_cross_compile} export CROSS_COMPILE=${toolchain_cross_compile}
export ARCH=arm64 export ARCH=arm64
@ -18,7 +18,7 @@ export ARCH=arm64
cd ${kernel_builddir}/${kernel_filename%.tar.gz} cd ${kernel_builddir}/${kernel_filename%.tar.gz}
# If we have patches, apply them # If we have patches, apply them
if [[ -d ${root_path}/patches/kernel/ ]]; then if [[ -d "${root_path}/patches/kernel/" ]]; then
for file in ${root_path}/patches/kernel/*.patch; do for file in ${root_path}/patches/kernel/*.patch; do
echo "Applying kernel patch ${file}" echo "Applying kernel patch ${file}"
patch -p1 < ${file} patch -p1 < ${file}
@ -26,7 +26,7 @@ if [[ -d ${root_path}/patches/kernel/ ]]; then
fi fi
# Apply overlay if it exists # Apply overlay if it exists
if [[ -d ${root_path}/overlay/${kernel_overlay_dir}/ ]]; then if [[ -d "${root_path}/overlay/${kernel_overlay_dir}/" ]]; then
echo "Applying ${kernel_overlay_dir} overlay" echo "Applying ${kernel_overlay_dir} overlay"
cp -R ${root_path}/overlay/${kernel_overlay_dir}/* ./ cp -R ${root_path}/overlay/${kernel_overlay_dir}/* ./
fi fi
@ -52,3 +52,10 @@ mv defconfig ${build_path}/kernel/kernel_config
#cp ./arch/arm64/boot/Image.gz ${build_path}/kernel #cp ./arch/arm64/boot/Image.gz ${build_path}/kernel
#mv uImage ${build_path}/kernel #mv uImage ${build_path}/kernel
mv ./modules-dir ${build_path}/kernel/kernel-modules mv ./modules-dir ${build_path}/kernel/kernel-modules
# Now that the kernel is done, build our out of tree modules! :)
module_builddir=$(mktemp -d)
cp ${root_path}/tools/mtd-lock/* "${module_builddir}"
cd "${module_builddir}"
make -C ${kernel_builddir}/${kernel_filename%.tar.gz} M=$PWD
cp "${module_builddir}/ubnt-mtd-lock.ko" ${build_path}/kernel

View file

@ -24,9 +24,10 @@ chroot "${build_path}/rootfs" /debootstrap/debootstrap --second-stage
mv -f "${build_path}/fw-extract/${BOARD}-rootfs/lib/modules" "${build_path}/rootfs/lib" mv -f "${build_path}/fw-extract/${BOARD}-rootfs/lib/modules" "${build_path}/rootfs/lib"
cp "${build_path}/fw-extract/${firmware_filename%.bin}/kernel.bin" "${build_path}/rootfs/boot/uImage" cp "${build_path}/fw-extract/${firmware_filename%.bin}/kernel.bin" "${build_path}/rootfs/boot/uImage"
# Now, for the old kernel we built, pull in btrfs + depends modules (we do depmod in bootstrap) # Now, for the old kernel we built, pull in our extra modules we need! (depmod is done in bootstrap)
cp "${build_path}/kernel/kernel-modules/lib/modules/4.19.152-alpine-unvr/kernel/lib/zstd/zstd_compress.ko" "${build_path}/rootfs/lib/modules/4.19.152-alpine-unvr/extra/" cp "${build_path}/kernel/kernel-modules/lib/modules/4.19.152-alpine-unvr/kernel/lib/zstd/zstd_compress.ko" "${build_path}/rootfs/lib/modules/4.19.152-alpine-unvr/extra/"
cp "${build_path}/kernel/kernel-modules/lib/modules/4.19.152-alpine-unvr/kernel/fs/btrfs/btrfs.ko" "${build_path}/rootfs/lib/modules/4.19.152-alpine-unvr/extra/" cp "${build_path}/kernel/kernel-modules/lib/modules/4.19.152-alpine-unvr/kernel/fs/btrfs/btrfs.ko" "${build_path}/rootfs/lib/modules/4.19.152-alpine-unvr/extra/"
cp "${build_path}/kernel/ubnt-mtd-lock.ko" "${build_path}/rootfs/lib/modules/4.19.152-alpine-unvr/extra/"
# Copy over our overlay if we have one # Copy over our overlay if we have one
if [[ -d ${root_path}/overlay/${fs_overlay_dir}/ ]]; then if [[ -d ${root_path}/overlay/${fs_overlay_dir}/ ]]; then
@ -52,6 +53,8 @@ if [ "${BOARD}" == "UNVRPRO" ]; then
libssl.so.1.1 libcrypto.so.1.1 libabsl*.so.20200923 libatomic.so.1; do libssl.so.1.1 libcrypto.so.1.1 libabsl*.so.20200923 libatomic.so.1; do
cp -H ${build_path}/fw-extract/${BOARD}-rootfs/usr/lib/aarch64-linux-gnu/${file} "${build_path}/rootfs/usr/lib/ubnt-fw/" cp -H ${build_path}/fw-extract/${BOARD}-rootfs/usr/lib/aarch64-linux-gnu/${file} "${build_path}/rootfs/usr/lib/ubnt-fw/"
done done
# Now for the REAL JANK! patch ulcmd so it doesn't rely on /proc/ubnthal, so we can use our userspace tool ubnteeprom
sed -i 's|/proc/ubnthal/system.info|/tmp/.ubnthal_system_info|g' "${build_path}/rootfs/usr/bin/ulcmd"
else else
# Remove our ld.so.conf.d as it's not needed for UVNR # Remove our ld.so.conf.d as it's not needed for UVNR
rm "${build_path}/rootfs/etc/ld.so.conf.d/ubnt.conf" rm "${build_path}/rootfs/etc/ld.so.conf.d/ubnt.conf"

1
tools/mtd-lock/Kbuild Normal file
View file

@ -0,0 +1 @@
obj-m := ubnt-mtd-lock.o

11
tools/mtd-lock/README.md Normal file
View file

@ -0,0 +1,11 @@
# mtd-lock
A stupid basic kernel module to ensure we set /dev/mtd as RO (fully) in our firmware. This is done to prevent users/bad actors from wiping your bootloader/Unifi EEPROM, which are required for your device to function!
## Building
make -C ${kernel_source_dir} M=$PWD
## License
This code is licensed under the GNU General Public License, version 2. A copy of said license can be found at [https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html#SEC1](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html#SEC1)

View file

@ -0,0 +1,78 @@
/*
* Copyright (C) 2024 Chris Blake <chrisrblake93@gmail.com>
*
* Inspired by mtd-rw: https://github.com/jclehner/mtd-rw/tree/master
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/err.h>
#ifndef MODULE
#error "uvnt-mtd-lock must be compiled as a module."
#endif
#define MOD_INFO KERN_INFO "ubnt-mtd-lock: "
#define MOD_ERR KERN_ERR "ubnt-mtd-lock: "
static int set_readonly(unsigned n)
{
struct mtd_info *mtd = get_mtd_device(NULL, n);
int err;
if (IS_ERR(mtd)) {
if (PTR_ERR(mtd) != -ENODEV) {
printk(MOD_ERR "error probing mtd%d %ld\n", n, PTR_ERR(mtd));
}
return PTR_ERR(mtd);
}
err = -EEXIST;
if (mtd->flags & MTD_WRITEABLE) {
printk(MOD_INFO "setting mtd%d \"%s\" readonly\n", n, mtd->name);
mtd->flags &= ~MTD_WRITEABLE;
err = 0;
}
put_mtd_device(mtd);
return err;
}
int ubnt_mtd_lock_init(void)
{
int i, err;
/* For all MTD partitions, go RO. Assume <10 for UNVR/UNVRPRO */
for (i = 0; i < 10; ++i) {
err = set_readonly(i);
if (err == -ENODEV) {
break;
}
}
return 0;
}
void ubnt_mtd_lock_exit(void)
{
/* Do nothing, we wanna keep mtd locked!!! */
}
module_init(ubnt_mtd_lock_init);
module_exit(ubnt_mtd_lock_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Chris Blake <chrisrblake93@gmail.com>");
MODULE_DESCRIPTION("Unifi UNVR/UNVRPRO driver to force MTD partitions RO");
MODULE_VERSION("1");

View file

@ -0,0 +1,37 @@
# ubnteeprom
A userspace tool to parse/read/render the EEPROM MTD partition on Unifi UNVR/UNVR Pro, and possibly other Dream Machine devices in the future.
## Purpose
This tool was created as a userspace replacement for the functions Unifi's ubnthal proprietary kernel module provides, by reporting most of the same information out as `/proc/ubnthal/*` as well as some output from `ubnt-tools id`.
The idea behind this is so we can get this repo off of using proprietary Unifi code as much as possible, so replacements for things are required. All code for this was reverse engineered and no unifi proprietary code was copied/used in the creation of this tool.
## Usage
Get similar output to `/proc/ubnthal/board`:
ubnteeprom -board
Get similar output to `/proc/ubnthal/system.info`:
ubnteeprom -systeminfo
Get similar output to `ubnt-tools id`:
ubnteeprom -tools
Get a specfic value for a selected key in output, for example, `boardid`:
ubnteeprom -board -key boardid
## Building
```
env GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o ubnteeprom main.go
```
## License
This code is licensed under the GNU General Public License, version 2. A copy of said license can be found at [https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html#SEC1](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html#SEC1)

View file

@ -1,5 +1,8 @@
package main package main
// Copyright (C) 2024 Chris Blake <chrisrblake93@gmail.com>
// Licensed under the GNU Public License, version 2
import ( import (
"encoding/hex" "encoding/hex"
"flag" "flag"