Skip to content

Commit 53e140c

Browse files
committed
Harden --no-device mode with process-level isolation
- Force --no-device to skip loopback/device handling and use isolated temporary OBS config - Add sandboxed OBS launch path via systemd-run --user --scope with PrivateDevices when available - Keep safe fallback path when user-systemd sandbox is unavailable - Document updated no-device behaviour in README
1 parent b42b109 commit 53e140c

2 files changed

Lines changed: 49 additions & 5 deletions

File tree

docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ lsusb | grep -i "your-device"
199199
# Or for direct device mode (skip v4l2loopback relay)
200200
./scripts/obs-safe-launch.sh --no-loopback --device /dev/video0
201201

202-
# Launch OBS without device requirement (configure sources manually)
202+
# Launch OBS in isolation mode (no device handling, no loopback, clean OBS config)
203203
./scripts/obs-safe-launch.sh --no-device
204204

205205
# Disable auto-resume if you don't want stream to restart after crash
@@ -221,7 +221,7 @@ lsusb | grep -i "your-device"
221221
| `--device PATH` | Specify USB capture device |
222222
| `--vidpid VID:PID` | USB vendor:product ID for device reset |
223223
| `--no-loopback` | Skip v4l2loopback, use device directly in OBS |
224-
| `--no-device` | Launch OBS without device (configure manually) |
224+
| `--no-device` | Isolated safety mode: no device handling, no loopback, clean temporary OBS config, and process-level `/dev/video*` isolation when available |
225225
| `--auto-resume` | Auto-resume streaming after crash (default: enabled) |
226226
| `--no-auto-resume` | Disable auto-stream-resume |
227227
| `--obs-args "ARGS"` | Pass additional arguments to OBS |

scripts/obs-safe-launch.sh

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ CAP_FPS="${USB_CAPTURE_FPS:-30}"
3434
CAP_FMT="${USB_CAPTURE_FORMAT:-NV12}"
3535
HDR_MODE="${USB_CAPTURE_HDR_MODE:-2}"
3636
USE_LOOPBACK=1
37+
ISOLATED_CONFIG_DIR=""
3738

3839
# Colors
3940
RED='\033[0;31m'
@@ -76,7 +77,7 @@ Options:
7677
--obs-args "ARGS" Extra arguments passed to OBS
7778
--no-loopback Skip v4l2loopback/feed.sh and launch OBS direct
7879
--direct-device Alias for --no-loopback
79-
--no-device Launch OBS without device requirement (configure sources manually)
80+
--no-device Launch OBS in isolation mode (no device, no loopback, clean config)
8081
--auto-resume Enable automatic stream resumption after crash (default: enabled)
8182
--no-auto-resume Disable automatic stream resumption after crash
8283
--help Show this help
@@ -103,7 +104,10 @@ parse_args() {
103104
--no-loopback|--direct-device)
104105
USE_LOOPBACK=0; shift;;
105106
--no-device)
106-
SKIP_DEVICE_CHECK=1; shift;;
107+
SKIP_DEVICE_CHECK=1
108+
USE_LOOPBACK=0
109+
shift
110+
;;
107111
--auto-resume)
108112
AUTO_RESUME_ENABLED=1; shift;;
109113
--no-auto-resume)
@@ -122,6 +126,20 @@ parse_args() {
122126
done
123127
}
124128

129+
# In --no-device mode, launch OBS with a clean config path so old scenes
130+
# containing unstable capture sources are not auto-loaded.
131+
setup_isolated_obs_config() {
132+
if [ "$SKIP_DEVICE_CHECK" -ne 1 ]; then
133+
return 0
134+
fi
135+
136+
ISOLATED_CONFIG_DIR=$(mktemp -d /tmp/obs-safe-launch-config.XXXXXX)
137+
export XDG_CONFIG_HOME="$ISOLATED_CONFIG_DIR"
138+
139+
log_info "--no-device enabled: forcing no-loopback and isolated OBS config"
140+
log_info "Isolated config dir: $ISOLATED_CONFIG_DIR"
141+
}
142+
125143
# Create log directory
126144
setup_logging() {
127145
mkdir -p "$LOG_DIR"
@@ -393,6 +411,28 @@ load_driver_optimizations() {
393411
fi
394412
}
395413

414+
# Run OBS process. In --no-device mode, prefer a process-level device sandbox
415+
# so OBS cannot enumerate /dev/video* even if it probes hardware globally.
416+
run_obs() {
417+
if [ "$SKIP_DEVICE_CHECK" -eq 1 ]; then
418+
if command -v systemd-run >/dev/null 2>&1 && systemctl --user show-environment >/dev/null 2>&1; then
419+
log_info "--no-device: launching OBS with systemd PrivateDevices sandbox"
420+
systemd-run --user --scope --collect \
421+
-p PrivateDevices=yes \
422+
-p PrivateTmp=yes \
423+
-p ProtectControlGroups=yes \
424+
-p ProtectKernelTunables=yes \
425+
--quiet \
426+
obs $OBS_ARGS
427+
return $?
428+
fi
429+
430+
log_warn "--no-device: systemd user sandbox unavailable; using standard launch fallback"
431+
fi
432+
433+
obs $OBS_ARGS
434+
}
435+
396436
# Check if OBS was streaming via websocket or log file
397437
detect_streaming_state() {
398438
# Check recent log for streaming indicators
@@ -484,6 +524,7 @@ main() {
484524

485525
pre_flight_checks
486526
load_driver_optimizations
527+
setup_isolated_obs_config
487528

488529
# Set up cleanup trap early
489530
trap 'cleanup' EXIT INT TERM
@@ -520,7 +561,7 @@ main() {
520561
export GSETTINGS_SCHEMA_DIR=/usr/share/glib-2.0/schemas
521562

522563
set +e # Disable exit-on-error for OBS execution
523-
obs $OBS_ARGS 2>&1 | tee -a "$LOG_FILE"
564+
run_obs 2>&1 | tee -a "$LOG_FILE"
524565
EXIT_CODE=${PIPESTATUS[0]}
525566
set -e # Re-enable exit-on-error
526567

@@ -552,6 +593,9 @@ cleanup() {
552593
log_info "Cleaning up..."
553594
stop_feed
554595
stop_auto_reconnect
596+
if [ -n "${ISOLATED_CONFIG_DIR:-}" ] && [ -d "$ISOLATED_CONFIG_DIR" ]; then
597+
rm -rf "$ISOLATED_CONFIG_DIR" || true
598+
fi
555599
rm -f "$PID_FILE" "$STREAM_STATE_FILE"
556600
log_info "Shutdown complete"
557601
}

0 commit comments

Comments
 (0)