Remediate the 2026-09-03 feature-test findings

This commit is contained in:
2026-09-03 17:15:03 -04:00
parent cf95daf3bb
commit fd513c08eb
112 changed files with 5182 additions and 857 deletions

View File

@@ -10,6 +10,7 @@ Kept out of the CLI and routes so both share one implementation:
import hashlib
import json
import os
import re
import tempfile
from datetime import datetime, timezone
@@ -532,6 +533,30 @@ def store_inline_payload(entry, filename, contenttype, rawbytes):
return payload
# A scope name becomes a DIRECTORY on the imaging share, so it has to be a
# single safe path segment. It was validated only as "not empty", which meant a
# name like "../escape" or an absolute path wrote the manifest outside the
# share root - proven by writing /tmp/manifest.json and files one and two
# levels above it. The real exposure is the permission split: geenforce.manage
# creates the scope, geenforce.publish writes the file, so a manage-only author
# could aim a publisher's write anywhere that process can reach.
#
# Allowed: letters, digits, dot, dash, underscore. Not '.' or '..', and no
# separator of either platform - the share is written from Linux and read by
# Windows, so a backslash is a separator too.
SCOPENAME_PATTERN = re.compile(r'^[A-Za-z0-9][A-Za-z0-9._-]*$')
def valid_scopename(scopename):
"""True when this name is safe to use as a directory on the share."""
name = (scopename or '').strip()
if not name or name in ('.', '..') or len(name) > 100:
return False
if '/' in name or '\\' in name or '\x00' in name:
return False
return bool(SCOPENAME_PATTERN.match(name))
def export_scope_to_share(scopename, phase, shareroot):
"""Write a scope's current published JSON to the share, backing up the old
file to _meta/history first. Returns the written path."""
@@ -546,7 +571,21 @@ def export_scope_to_share(scopename, phase, shareroot):
if phase == 'preinstall':
target = os.path.join(shareroot, 'preinstall.json')
else:
# Checked again here, not only at creation: rows predating the
# validation exist, and this is the line that actually writes.
if not valid_scopename(scopename):
raise ValueError(
f'Refusing to export scope {scopename!r}: the name is not a '
f'safe directory name')
target = os.path.join(shareroot, scopename, 'manifest.json')
# Belt and braces: whatever the name, the resolved target must sit inside
# the share root.
root = os.path.realpath(shareroot)
if os.path.commonpath([root, os.path.realpath(os.path.dirname(target))]) != root:
raise ValueError(
f'Refusing to export scope {scopename!r}: it resolves outside the '
f'share root')
os.makedirs(os.path.dirname(target), exist_ok=True)
if os.path.isfile(target):