Miscellaneous fixes (#22779)
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions

* block ffmpeg args in custom exports for non-admin users only

* prune expired reconnect timestamps periodically in watchdog loop

reconnect timestamps were only pruned when a new reconnect
occurred. This meant a single reconnect would persist in the count indefinitely instead of expiring after 1 hour

* formatting
This commit is contained in:
Josh Hawkins 2026-04-06 08:53:23 -05:00 committed by GitHub
parent e95e9b52f3
commit ed3bebc967
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 25 deletions

View File

@ -548,7 +548,11 @@ def export_recording_custom(
export_id = f"{camera_name}_{''.join(random.choices(string.ascii_lowercase + string.digits, k=6))}" export_id = f"{camera_name}_{''.join(random.choices(string.ascii_lowercase + string.digits, k=6))}"
# Validate user-provided ffmpeg args to prevent injection # Validate user-provided ffmpeg args to prevent injection.
# Admin users are trusted and skip validation.
is_admin = request.headers.get("remote-role", "") == "admin"
if not is_admin:
for args_label, args_value in [ for args_label, args_value in [
("input", ffmpeg_input_args), ("input", ffmpeg_input_args),
("output", ffmpeg_output_args), ("output", ffmpeg_output_args),

View File

@ -36,22 +36,20 @@ logger = logging.getLogger(__name__)
DEFAULT_TIME_LAPSE_FFMPEG_ARGS = "-vf setpts=0.04*PTS -r 30" DEFAULT_TIME_LAPSE_FFMPEG_ARGS = "-vf setpts=0.04*PTS -r 30"
TIMELAPSE_DATA_INPUT_ARGS = "-an -skip_frame nokey" TIMELAPSE_DATA_INPUT_ARGS = "-an -skip_frame nokey"
# ffmpeg flags that can read from or write to arbitrary files. # ffmpeg flags that can read from or write to arbitrary files
# filter flags are blocked because source filters like movie= and
# amovie= can read arbitrary files from the filesystem.
BLOCKED_FFMPEG_ARGS = frozenset( BLOCKED_FFMPEG_ARGS = frozenset(
{ {
"-i", "-i",
"-filter_script", "-filter_script",
"-vstats_file",
"-passlogfile",
"-sdp_file",
"-dump_attachment",
"-filter_complex", "-filter_complex",
"-lavfi", "-lavfi",
"-vf", "-vf",
"-af", "-af",
"-filter", "-filter",
"-vstats_file",
"-passlogfile",
"-sdp_file",
"-dump_attachment",
"-attach", "-attach",
} }
) )
@ -62,8 +60,11 @@ def validate_ffmpeg_args(args: str) -> tuple[bool, str]:
Blocks: Blocks:
- The -i flag and other flags that read/write arbitrary files - The -i flag and other flags that read/write arbitrary files
- Filter flags (can read files via movie=/amovie= source filters)
- Absolute/relative file paths (potential extra outputs) - Absolute/relative file paths (potential extra outputs)
- URLs and ffmpeg protocol references (data exfiltration) - URLs and ffmpeg protocol references (data exfiltration)
Admin users skip this validation entirely since they are trusted.
""" """
if not args or not args.strip(): if not args or not args.strip():
return True, "" return True, ""

View File

@ -471,8 +471,16 @@ class CameraWatchdog(threading.Thread):
p["cmd"], self.logger, p["logpipe"], ffmpeg_process=p["process"] p["cmd"], self.logger, p["logpipe"], ffmpeg_process=p["process"]
) )
# Update stall metrics based on last processed frame timestamp # Prune expired reconnect timestamps
now = datetime.now().timestamp() now = datetime.now().timestamp()
while (
self.reconnect_timestamps and self.reconnect_timestamps[0] < now - 3600
):
self.reconnect_timestamps.popleft()
if self.reconnects:
self.reconnects.value = len(self.reconnect_timestamps)
# Update stall metrics based on last processed frame timestamp
processed_ts = ( processed_ts = (
float(self.detection_frame.value) if self.detection_frame else 0.0 float(self.detection_frame.value) if self.detection_frame else 0.0
) )