fix: TrueNAS agent binary now runs from /usr/local/bin to avoid noexec

TrueNAS SCALE's /data partition may have exec=off, preventing binaries
from executing. The installer now:
- Stores the binary in /data/pulse-agent/ for persistence
- Copies it to /usr/local/bin (tmpfs, allows exec) for runtime
- Updates the bootstrap script to copy on each boot

Related to #801
This commit is contained in:
rcourtman 2025-12-03 20:14:48 +00:00
parent bc501df4e8
commit 86d303b94a

View file

@ -582,6 +582,8 @@ fi
# 4. TrueNAS SCALE (immutable root, uses systemd but needs special persistence) # 4. TrueNAS SCALE (immutable root, uses systemd but needs special persistence)
# TrueNAS SCALE wipes /etc/systemd/system on upgrades, so we store the service # TrueNAS SCALE wipes /etc/systemd/system on upgrades, so we store the service
# in /data and create an Init/Shutdown task to recreate the symlink on boot. # in /data and create an Init/Shutdown task to recreate the symlink on boot.
# Note: /data may have exec=off on some TrueNAS systems, so we copy the binary
# to /usr/local/bin (tmpfs, allows exec) at runtime while storing in /data for persistence.
if [[ "$TRUENAS" == true ]]; then if [[ "$TRUENAS" == true ]]; then
log_info "Configuring TrueNAS SCALE installation..." log_info "Configuring TrueNAS SCALE installation..."
@ -589,10 +591,29 @@ if [[ "$TRUENAS" == true ]]; then
mkdir -p "$TRUENAS_STATE_DIR" mkdir -p "$TRUENAS_STATE_DIR"
mkdir -p "$TRUENAS_LOG_DIR" mkdir -p "$TRUENAS_LOG_DIR"
# TrueNAS stores binary in /data for persistence, but runs from /usr/local/bin
# because /data may have exec=off. The bootstrap script copies on each boot.
TRUENAS_STORED_BINARY="$TRUENAS_STATE_DIR/${BINARY_NAME}"
TRUENAS_RUNTIME_BINARY="/usr/local/bin/${BINARY_NAME}"
# Move binary to persistent storage location
if [[ -f "${INSTALL_DIR}/${BINARY_NAME}" ]] && [[ "$INSTALL_DIR" == "$TRUENAS_STATE_DIR" ]]; then
# Binary already in the right place from earlier mv
:
else
mv "${INSTALL_DIR}/${BINARY_NAME}" "$TRUENAS_STORED_BINARY"
fi
chmod +x "$TRUENAS_STORED_BINARY"
# Copy to runtime location (tmpfs, allows exec)
cp "$TRUENAS_STORED_BINARY" "$TRUENAS_RUNTIME_BINARY"
chmod +x "$TRUENAS_RUNTIME_BINARY"
# Build command line args # Build command line args
build_exec_args build_exec_args
# Store service file in /data (persists across upgrades) # Store service file in /data (persists across upgrades)
# Service uses /usr/local/bin path (runtime location)
TRUENAS_SERVICE_STORAGE="$TRUENAS_STATE_DIR/${AGENT_NAME}.service" TRUENAS_SERVICE_STORAGE="$TRUENAS_STATE_DIR/${AGENT_NAME}.service"
cat > "$TRUENAS_SERVICE_STORAGE" <<EOF cat > "$TRUENAS_SERVICE_STORAGE" <<EOF
[Unit] [Unit]
@ -603,7 +624,7 @@ StartLimitIntervalSec=0
[Service] [Service]
Type=simple Type=simple
ExecStart=${INSTALL_DIR}/${BINARY_NAME} ${EXEC_ARGS} ExecStart=${TRUENAS_RUNTIME_BINARY} ${EXEC_ARGS}
Restart=always Restart=always
RestartSec=5s RestartSec=5s
User=root User=root
@ -626,23 +647,37 @@ EOF
chmod 600 "$TRUENAS_ENV_FILE" chmod 600 "$TRUENAS_ENV_FILE"
# Create bootstrap script that runs on boot # Create bootstrap script that runs on boot
# This copies the binary from /data to /usr/local/bin and recreates the systemd symlink
cat > "$TRUENAS_BOOTSTRAP_SCRIPT" <<'BOOTSTRAP' cat > "$TRUENAS_BOOTSTRAP_SCRIPT" <<'BOOTSTRAP'
#!/bin/bash #!/bin/bash
# Pulse Agent Bootstrap for TrueNAS SCALE # Pulse Agent Bootstrap for TrueNAS SCALE
# This script is called by TrueNAS Init/Shutdown task on boot. # This script is called by TrueNAS Init/Shutdown task on boot.
# It recreates the systemd symlink (which is wiped on TrueNAS upgrades). # It copies the binary from /data to /usr/local/bin (tmpfs, allows exec)
# and recreates the systemd symlink (which is wiped on TrueNAS upgrades).
set -e set -e
SERVICE_NAME="pulse-agent" SERVICE_NAME="pulse-agent"
SERVICE_STORAGE="STATE_DIR_PLACEHOLDER/pulse-agent.service" STATE_DIR="STATE_DIR_PLACEHOLDER"
STORED_BINARY="${STATE_DIR}/pulse-agent"
RUNTIME_BINARY="/usr/local/bin/pulse-agent"
SERVICE_STORAGE="${STATE_DIR}/pulse-agent.service"
SYSTEMD_LINK="/etc/systemd/system/${SERVICE_NAME}.service" SYSTEMD_LINK="/etc/systemd/system/${SERVICE_NAME}.service"
if [[ ! -f "$STORED_BINARY" ]]; then
echo "ERROR: Binary not found at $STORED_BINARY"
exit 1
fi
if [[ ! -f "$SERVICE_STORAGE" ]]; then if [[ ! -f "$SERVICE_STORAGE" ]]; then
echo "ERROR: Service file not found at $SERVICE_STORAGE" echo "ERROR: Service file not found at $SERVICE_STORAGE"
exit 1 exit 1
fi fi
# Copy binary from persistent storage to runtime location (tmpfs allows exec)
cp "$STORED_BINARY" "$RUNTIME_BINARY"
chmod +x "$RUNTIME_BINARY"
# Create symlink (or update if exists) # Create symlink (or update if exists)
ln -sf "$SERVICE_STORAGE" "$SYSTEMD_LINK" ln -sf "$SERVICE_STORAGE" "$SYSTEMD_LINK"
@ -688,7 +723,8 @@ BOOTSTRAP
systemctl restart "${AGENT_NAME}" systemctl restart "${AGENT_NAME}"
log_info "Installation complete!" log_info "Installation complete!"
log_info "Binary: ${INSTALL_DIR}/${BINARY_NAME}" log_info "Binary: $TRUENAS_STORED_BINARY (persistent)"
log_info "Runtime: $TRUENAS_RUNTIME_BINARY (for execution)"
log_info "Service: $TRUENAS_SERVICE_STORAGE (symlinked to systemd)" log_info "Service: $TRUENAS_SERVICE_STORAGE (symlinked to systemd)"
log_info "Logs: tail -f ${LOG_FILE}" log_info "Logs: tail -f ${LOG_FILE}"
log_info "" log_info ""