Stop the madness! Run as a user (not root) (#6718)

* Stop the madness! Run as a user (not root)

* Trigger fsdir migration for < 2.6.9

---------

Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
Austin 2025-05-15 07:40:46 -04:00 committed by GitHub
parent c2d5862161
commit 7d8f9c7f6d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 225 additions and 23 deletions

View File

@ -13,7 +13,6 @@ lint:
- trufflehog@3.88.29
- yamllint@1.37.1
- bandit@1.8.3
- terrascan@1.19.9
- trivy@0.62.1
- taplo@0.9.3
- ruff@0.11.9

View File

@ -1,4 +1,3 @@
# trunk-ignore-all(terrascan/AC_DOCKER_0002): Known terrascan issue
# trunk-ignore-all(trivy/DS002): We must run as root for this container
# trunk-ignore-all(hadolint/DL3002): We must run as root for this container
# trunk-ignore-all(hadolint/DL3008): Do not pin apt package versions
@ -38,6 +37,13 @@ RUN curl -L "https://github.com/meshtastic/web/releases/download/v$(cat /tmp/fir
##### PRODUCTION BUILD #############
FROM debian:bookworm-slim
LABEL org.opencontainers.image.title="Meshtastic" \
org.opencontainers.image.description="Debian Meshtastic daemon and web interface" \
org.opencontainers.image.url="https://meshtastic.org" \
org.opencontainers.image.documentation="https://meshtastic.org/docs/" \
org.opencontainers.image.authors="Meshtastic" \
org.opencontainers.image.licenses="GPL-3.0-or-later" \
org.opencontainers.image.source="https://github.com/meshtastic/firmware/"
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Etc/UTC
@ -54,7 +60,7 @@ RUN apt-get update && apt-get --no-install-recommends -y install \
&& mkdir -p /etc/meshtasticd/ssl
# Fetch compiled binary from the builder
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/sbin/
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/bin/
COPY --from=builder /tmp/web /usr/share/meshtasticd/
# Copy config templates
COPY ./bin/config.d /etc/meshtasticd/available.d
@ -65,8 +71,8 @@ VOLUME /var/lib/meshtasticd
# Expose Meshtastic TCP API port from the host
EXPOSE 4403
# Expose Meshtastic Web UI port from the host
EXPOSE 443
EXPOSE 9443
CMD [ "sh", "-cx", "meshtasticd -d /var/lib/meshtasticd" ]
CMD [ "sh", "-cx", "meshtasticd --fsdir=/var/lib/meshtasticd" ]
HEALTHCHECK NONE

View File

@ -28,12 +28,19 @@ RUN bash ./bin/build-native.sh "$PIO_ENV" && \
# ##### PRODUCTION BUILD #############
FROM alpine:3.21
LABEL org.opencontainers.image.title="Meshtastic" \
org.opencontainers.image.description="Alpine Meshtastic daemon" \
org.opencontainers.image.url="https://meshtastic.org" \
org.opencontainers.image.documentation="https://meshtastic.org/docs/" \
org.opencontainers.image.authors="Meshtastic" \
org.opencontainers.image.licenses="GPL-3.0-or-later" \
org.opencontainers.image.source="https://github.com/meshtastic/firmware/"
# nosemgrep: dockerfile.security.last-user-is-root.last-user-is-root
USER root
RUN apk --no-cache add \
libstdc++ libgpiod yaml-cpp libusb i2c-tools libuv \
shadow libstdc++ libgpiod yaml-cpp libusb i2c-tools libuv \
libx11 libinput libxkbcommon \
&& rm -rf /var/cache/apk/* \
&& mkdir -p /var/lib/meshtasticd \
@ -41,7 +48,7 @@ RUN apk --no-cache add \
&& mkdir -p /etc/meshtasticd/ssl
# Fetch compiled binary from the builder
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/sbin/
COPY --from=builder /tmp/firmware/release/meshtasticd /usr/bin/
# Copy config templates
COPY ./bin/config.d /etc/meshtasticd/available.d

View File

@ -0,0 +1,4 @@
# Set spidev ownership to 'spi' group.
SUBSYSTEM=="spidev", KERNEL=="spidev*", GROUP="spi", MODE="0660"
# Allow access to USB CH341 devices
SUBSYSTEM=="usb", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="5512", MODE="0666"

View File

@ -188,7 +188,7 @@ Logging:
# AsciiLogs: true # default if not specified is !isatty() on stdout
Webserver:
# Port: 443 # Port for Webserver & Webservices
# Port: 9443 # Port for Webserver & Webservices
# RootPath: /usr/share/meshtasticd/web # Root Dir of WebServer
# SSLKey: /etc/meshtasticd/ssl/private_key.pem # Path to SSL Key, generated if not present
# SSLCert: /etc/meshtasticd/ssl/certificate.pem # Path to SSL Certificate, generated if not present

View File

@ -5,10 +5,11 @@ StartLimitInterval=200
StartLimitBurst=5
[Service]
User=root
Group=root
AmbientCapabilities=CAP_NET_BIND_SERVICE
User=meshtasticd
Group=meshtasticd
Type=simple
ExecStart=/usr/sbin/meshtasticd
ExecStart=/usr/bin/meshtasticd
Restart=always
RestartSec=3

View File

@ -1,6 +1,6 @@
#!/usr/bin/env bash
cp "release/meshtasticd_linux_$(uname -m)" /usr/sbin/meshtasticd
cp "release/meshtasticd_linux_$(uname -m)" /usr/bin/meshtasticd
mkdir -p /etc/meshtasticd
if [[ -f "/etc/meshtasticd/config.yaml" ]]; then
cp bin/config-dist.yaml /etc/meshtasticd/config-upgrade.yaml

4
debian/control vendored
View File

@ -31,7 +31,9 @@ Rules-Requires-Root: no
Package: meshtasticd
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}
Depends: adduser,
${misc:Depends},
${shlibs:Depends}
Description: Meshtastic daemon for communicating with Meshtastic devices
Meshtastic is an off-grid text communication platform that uses inexpensive
LoRa radios.

View File

@ -1,3 +1,4 @@
var/lib/meshtasticd
etc/meshtasticd
etc/meshtasticd/config.d
etc/meshtasticd/available.d

View File

@ -1,4 +1,4 @@
.pio/build/native-tft/meshtasticd usr/sbin
.pio/build/native-tft/meshtasticd usr/bin
bin/config.yaml etc/meshtasticd
bin/config.d/* etc/meshtasticd/available.d

79
debian/meshtasticd.postinst vendored Executable file
View File

@ -0,0 +1,79 @@
#!/bin/sh
# postinst script for meshtasticd
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postinst> `configure' <most-recently-configured-version>
# * <old-postinst> `abort-upgrade' <new version>
# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
# <new-version>
# * <postinst> `abort-remove'
# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
# <failed-install-package> <version> `removing'
# <conflicting-package> <version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
configure|reconfigure)
# create spi group (for udev rules)
# this group already exists on Raspberry Pi OS
getent group spi >/dev/null 2>/dev/null || addgroup --system spi
# create a meshtasticd group and user
getent passwd meshtasticd >/dev/null 2>/dev/null || adduser --system --home /var/lib/meshtasticd --no-create-home meshtasticd
getent group meshtasticd >/dev/null 2>/dev/null || addgroup --system meshtasticd
adduser meshtasticd meshtasticd >/dev/null 2>/dev/null
adduser meshtasticd spi >/dev/null 2>/dev/null
# add meshtasticd user to appropriate groups (if they exist)
getent group gpio >/dev/null 2>/dev/null && adduser meshtasticd gpio >/dev/null 2>/dev/null
getent group plugdev >/dev/null 2>/dev/null && adduser meshtasticd plugdev >/dev/null 2>/dev/null
getent group dialout >/dev/null 2>/dev/null && adduser meshtasticd dialout >/dev/null 2>/dev/null
getent group i2c >/dev/null 2>/dev/null && adduser meshtasticd i2c >/dev/null 2>/dev/null
getent group video >/dev/null 2>/dev/null && adduser meshtasticd video >/dev/null 2>/dev/null
getent group audio >/dev/null 2>/dev/null && adduser meshtasticd audio >/dev/null 2>/dev/null
getent group input >/dev/null 2>/dev/null && adduser meshtasticd input >/dev/null 2>/dev/null
# migrate /root/.portduino to /var/lib/meshtasticd/.portduino
# should only run once, upon upgrade from < 2.6.9
if [ -n "$2" ] && dpkg --compare-versions "$2" lt 2.6.9; then
if [ -d /root/.portduino ] && [ ! -e /var/lib/meshtasticd/.portduino ]; then
cp -r /root/.portduino /var/lib/meshtasticd/.portduino
echo "Migrated meshtasticd VFS from /root/.portduino to /var/lib/meshtasticd/.portduino"
echo "meshtasticd now runs as the 'meshtasticd' user, not 'root'."
echo "See https://github.com/meshtastic/firmware/pull/6718 for details"
fi
fi
if [ -d /var/lib/meshtasticd ]; then
chown -R meshtasticd:meshtasticd /var/lib/meshtasticd
fi
if [ -d /etc/meshtasticd ]; then
chown -R meshtasticd:meshtasticd /etc/meshtasticd
fi
if [ -d /usr/share/meshtasticd ]; then
chown -R meshtasticd:meshtasticd /usr/share/meshtasticd
fi
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

41
debian/meshtasticd.postrm vendored Executable file
View File

@ -0,0 +1,41 @@
#!/bin/sh
# postrm script for meshtasticd
#
# see: dh_installdeb(1)
set -e
# summary of how this script can be called:
# * <postrm> `remove'
# * <postrm> `purge'
# * <old-postrm> `upgrade' <new-version>
# * <new-postrm> `failed-upgrade' <old-version>
# * <new-postrm> `abort-install'
# * <new-postrm> `abort-install' <old-version>
# * <new-postrm> `abort-upgrade' <old-version>
# * <disappearer's-postrm> `disappear' <overwriter>
# <overwriter-version>
# for details, see http://www.debian.org/doc/debian-policy/ or
# the debian-policy package
case "$1" in
purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
# Only remove /var/lib/meshtasticd on purge
if [ "${1}" = "purge" ] ; then
rm -rf /var/lib/meshtasticd
fi
;;
*)
echo "postrm called with unknown argument \`$1'" >&2
exit 1
;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.
#DEBHELPER#
exit 0

4
debian/meshtasticd.udev vendored Normal file
View File

@ -0,0 +1,4 @@
# Set spidev ownership to 'spi' group.
SUBSYSTEM=="spidev", KERNEL=="spidev*", GROUP="spi", MODE="0660"
# Allow access to USB CH341 devices
SUBSYSTEM=="usb", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="5512", MODE="0666"

View File

@ -10,6 +10,8 @@
# - https://docs.pagure.org/rpkg-util/v3/index.html
# - https://docs.fedoraproject.org/en-US/packaging-guidelines/Versioning/
%global meshtasticd_user meshtasticd
Name: meshtasticd
# Version Ex: 2.5.19
Version: {{{ meshtastic_version }}}
@ -47,6 +49,8 @@ BuildRequires: pkgconfig(x11)
BuildRequires: pkgconfig(libinput)
BuildRequires: pkgconfig(xkbcommon-x11)
Requires: systemd-udev
%description
Meshtastic daemon for controlling Meshtastic devices. Meshtastic is an off-grid
text communication platform that uses inexpensive LoRa radios.
@ -63,15 +67,25 @@ gzip -dr web
platformio run -e native-tft
%install
mkdir -p %{buildroot}%{_sbindir}
install -m 0755 .pio/build/native-tft/program %{buildroot}%{_sbindir}/meshtasticd
# Install meshtasticd binary
mkdir -p %{buildroot}%{_bindir}
install -m 0755 .pio/build/native-tft/program %{buildroot}%{_bindir}/meshtasticd
# Install portduino VFS dir
install -p -d -m 0770 %{buildroot}%{_localstatedir}/lib/meshtasticd
# Install udev rules
mkdir -p %{buildroot}%{_udevrulesdir}
install -m 0644 bin/99-meshtasticd-udev.rules %{buildroot}%{_udevrulesdir}/99-meshtasticd-udev.rules
# Install config dirs
mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd
install -m 0644 bin/config-dist.yaml %{buildroot}%{_sysconfdir}/meshtasticd/config.yaml
mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd/config.d
mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd/available.d
cp -r bin/config.d/* %{buildroot}%{_sysconfdir}/meshtasticd/available.d
# Install systemd service
install -D -m 0644 bin/meshtasticd.service %{buildroot}%{_unitdir}/meshtasticd.service
# Install the web files under /usr/share/meshtasticd/web
@ -80,10 +94,54 @@ cp -r web/* %{buildroot}%{_datadir}/meshtasticd/web
# Install default SSL storage directory (for web)
mkdir -p %{buildroot}%{_sysconfdir}/meshtasticd/ssl
%pre
# create spi group (for udev rules)
getent group spi > /dev/null || groupadd -r spi
# create a meshtasticd group and user
getent group %{meshtasticd_user} > /dev/null || groupadd -r %{meshtasticd_user}
getent passwd %{meshtasticd_user} > /dev/null || \
useradd -r -d %{_localstatedir}/lib/meshtasticd -g %{meshtasticd_user} -G spi \
-s /sbin/nologin -c "Meshtastic Daemon" %{meshtasticd_user}
# add meshtasticd user to appropriate groups (if they exist)
getent group gpio > /dev/null && usermod -a -G gpio %{meshtasticd_user} > /dev/null
getent group plugdev > /dev/null && usermod -a -G plugdev %{meshtasticd_user} > /dev/null
getent group dialout > /dev/null && usermod -a -G dialout %{meshtasticd_user} > /dev/null
getent group i2c > /dev/null && usermod -a -G i2c %{meshtasticd_user} > /dev/null
getent group video > /dev/null && usermod -a -G video %{meshtasticd_user} > /dev/null
getent group audio > /dev/null && usermod -a -G audio %{meshtasticd_user} > /dev/null
getent group input > /dev/null && usermod -a -G input %{meshtasticd_user} > /dev/null
exit 0
%triggerin -- meshtasticd < 2.6.9
# migrate .portduino (if it exists and hasnt already been copied)
if [ -d /root/.portduino ] && [ ! -e /var/lib/meshtasticd/.portduino ]; then
mkdir -p /var/lib/meshtasticd
cp -r /root/.portduino /var/lib/meshtasticd/.portduino
chown -R %{meshtasticd_user}:%{meshtasticd_user} \
%{_localstatedir}/lib/meshtasticd || :
# Fix SELinux labels if present (no-op on non-SELinux systems)
restorecon -R /var/lib/meshtasticd/.portduino 2>/dev/null || :
echo "Migrated meshtasticd VFS from /root/.portduino to /var/lib/meshtasticd/.portduino"
echo "meshtasticd now runs as the 'meshtasticd' user, not 'root'."
echo "See https://github.com/meshtastic/firmware/pull/6718 for details"
fi
%post
%systemd_post meshtasticd.service
%preun
%systemd_preun meshtasticd.service
%postun
%systemd_postun_with_restart meshtasticd.service
%files
%defattr(-,%{meshtasticd_user},%{meshtasticd_user})
%license LICENSE
%doc README.md
%{_sbindir}/meshtasticd
%{_bindir}/meshtasticd
%dir %{_localstatedir}/lib/meshtasticd
%{_udevrulesdir}/99-meshtasticd-udev.rules
%dir %{_sysconfdir}/meshtasticd
%dir %{_sysconfdir}/meshtasticd/config.d
%dir %{_sysconfdir}/meshtasticd/available.d

View File

@ -462,8 +462,8 @@ PiWebServerThread::PiWebServerThread()
webservport = settingsMap[webserverport];
LOG_INFO("Use webserver port from yaml config %i ", webservport);
} else {
LOG_INFO("Webserver port in yaml config set to 0, defaulting to port 443");
webservport = 443;
LOG_INFO("Webserver port in yaml config set to 0, defaulting to port 9443");
webservport = 9443;
}
// Web Content Service Instance