Add ModSecurity compatibility handling for custom OLS binaries
Implement automatic detection and update of ModSecurity when upgrading to custom OpenLiteSpeed binaries. Problem: - Stock ModSecurity modules are NOT ABI-compatible with custom OLS binaries - Using stock ModSecurity with custom OLS causes server crashes (segfaults) - Custom OLS has different memory layout and function signatures - ModSecurity must be rebuilt against custom OLS headers Solution: - Detect if custom OLS binary is installed (check for PHPConfig markers) - Detect if ModSecurity is currently installed - Automatically download and install ABI-compatible ModSecurity - Verify checksums before installation - Backup existing ModSecurity before replacing Implementation: - isCustomOLSBinaryInstalled(): Detects custom OLS by scanning binary for markers - installCompatibleModSecurity(): Downloads OS-specific compatible ModSecurity - handleModSecurityCompatibility(): Orchestrates the compatibility check and update - Integrated into upgrade process after custom binary installation Binary URLs: - RHEL/AlmaLinux: https://cyberpanel.net/mod_security-compatible-rhel.so - Ubuntu/Debian: https://cyberpanel.net/mod_security-compatible-ubuntu.so Checksums: - RHEL SHA256: db580afc431fda40d46bdae2249ac74690d9175ff6d8b1843f2837d86f8d602f - Ubuntu SHA256: 115971fcd44b74bc7c7b097b9cec33ddcfb0fb07bb9b562ec9f4f0691c388a6b Safety features: - Checksum verification before installation - Automatic backup of existing ModSecurity - Graceful OLS restart with timeout handling - Non-fatal errors allow upgrade to continue This prevents server crashes for existing CyberPanel users who have ModSecurity installed when they upgrade to custom OpenLiteSpeed binaries.
This commit is contained in:
parent
120dcd3d20
commit
44bc736ee7
|
|
@ -882,6 +882,141 @@ class Upgrade:
|
|||
Upgrade.stdOut("Continuing with standard OLS", 0)
|
||||
return True # Non-fatal error, continue
|
||||
|
||||
@staticmethod
|
||||
def isCustomOLSBinaryInstalled():
|
||||
"""Detect if custom OpenLiteSpeed binary is installed"""
|
||||
try:
|
||||
OLS_BINARY_PATH = "/usr/local/lsws/bin/openlitespeed"
|
||||
|
||||
if not os.path.exists(OLS_BINARY_PATH):
|
||||
return False
|
||||
|
||||
# Check for PHPConfig function signature in binary
|
||||
command = f'strings {OLS_BINARY_PATH}'
|
||||
result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=10)
|
||||
|
||||
if result.returncode == 0:
|
||||
# Look for custom binary markers
|
||||
return 'set_php_config_value' in result.stdout or 'PHPConfig LSIAPI' in result.stdout
|
||||
|
||||
return False
|
||||
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"WARNING: Could not detect OLS binary type: {msg}", 0)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def installCompatibleModSecurity():
|
||||
"""Install ModSecurity compatible with custom OpenLiteSpeed binary"""
|
||||
try:
|
||||
Upgrade.stdOut("Installing ModSecurity compatible with custom OpenLiteSpeed binary...", 0)
|
||||
|
||||
MODSEC_PATH = "/usr/local/lsws/modules/mod_security.so"
|
||||
|
||||
# Detect OS and select appropriate ModSecurity binary
|
||||
binary_suffix = Upgrade.detectBinarySuffix()
|
||||
|
||||
if binary_suffix == 'rhel':
|
||||
MODSEC_URL = "https://cyberpanel.net/mod_security-compatible-rhel.so"
|
||||
EXPECTED_SHA256 = "db580afc431fda40d46bdae2249ac74690d9175ff6d8b1843f2837d86f8d602f"
|
||||
EXPECTED_MD5 = "1efa1e442fe8eedf4705584ac194fc95"
|
||||
else: # ubuntu
|
||||
MODSEC_URL = "https://cyberpanel.net/mod_security-compatible-ubuntu.so"
|
||||
EXPECTED_SHA256 = "115971fcd44b74bc7c7b097b9cec33ddcfb0fb07bb9b562ec9f4f0691c388a6b"
|
||||
EXPECTED_MD5 = "c3987c41182355c1290530b6553658db"
|
||||
|
||||
# Download to temp location
|
||||
tmp_modsec = "/tmp/mod_security_custom.so"
|
||||
|
||||
Upgrade.stdOut(f"Downloading compatible ModSecurity for {binary_suffix}...", 0)
|
||||
command = f'wget -q --show-progress {MODSEC_URL} -O {tmp_modsec}'
|
||||
result = subprocess.call(shlex.split(command))
|
||||
|
||||
if result != 0 or not os.path.exists(tmp_modsec):
|
||||
Upgrade.stdOut("ERROR: Failed to download ModSecurity", 0)
|
||||
return False
|
||||
|
||||
# Verify checksum
|
||||
Upgrade.stdOut("Verifying checksum...", 0)
|
||||
result = subprocess.run(f'sha256sum {tmp_modsec}', shell=True, capture_output=True, text=True)
|
||||
actual_sha256 = result.stdout.split()[0]
|
||||
|
||||
if actual_sha256 != EXPECTED_SHA256:
|
||||
Upgrade.stdOut(f"ERROR: Checksum verification failed", 0)
|
||||
Upgrade.stdOut(f" Expected: {EXPECTED_SHA256}", 0)
|
||||
Upgrade.stdOut(f" Got: {actual_sha256}", 0)
|
||||
os.remove(tmp_modsec)
|
||||
return False
|
||||
|
||||
Upgrade.stdOut("Checksum verified successfully", 0)
|
||||
|
||||
# Backup existing ModSecurity if present
|
||||
if os.path.exists(MODSEC_PATH):
|
||||
backup_path = f"{MODSEC_PATH}.backup.{int(time.time())}"
|
||||
shutil.copy2(MODSEC_PATH, backup_path)
|
||||
Upgrade.stdOut(f"Backed up existing ModSecurity to: {backup_path}", 0)
|
||||
|
||||
# Stop OpenLiteSpeed
|
||||
Upgrade.stdOut("Stopping OpenLiteSpeed...", 0)
|
||||
subprocess.run(['/usr/local/lsws/bin/lswsctrl', 'stop'], timeout=30)
|
||||
time.sleep(2)
|
||||
|
||||
# Install compatible ModSecurity
|
||||
os.makedirs(os.path.dirname(MODSEC_PATH), exist_ok=True)
|
||||
shutil.copy2(tmp_modsec, MODSEC_PATH)
|
||||
os.chmod(MODSEC_PATH, 0o755)
|
||||
os.remove(tmp_modsec)
|
||||
|
||||
Upgrade.stdOut("Compatible ModSecurity installed successfully", 0)
|
||||
|
||||
# Start OpenLiteSpeed
|
||||
Upgrade.stdOut("Starting OpenLiteSpeed...", 0)
|
||||
subprocess.run(['/usr/local/lsws/bin/lswsctrl', 'start'], timeout=30)
|
||||
|
||||
Upgrade.stdOut("✓ ModSecurity updated to compatible version", 0)
|
||||
return True
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
Upgrade.stdOut("ERROR: Timeout during OpenLiteSpeed restart", 0)
|
||||
return False
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"ERROR: ModSecurity installation failed: {msg}", 0)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def handleModSecurityCompatibility():
|
||||
"""Check and update ModSecurity if custom OLS binary is installed"""
|
||||
try:
|
||||
MODSEC_PATH = "/usr/local/lsws/modules/mod_security.so"
|
||||
|
||||
# Check if ModSecurity is installed
|
||||
if not os.path.exists(MODSEC_PATH):
|
||||
Upgrade.stdOut("ModSecurity not installed, skipping compatibility check", 0)
|
||||
return True
|
||||
|
||||
# Check if custom OLS binary is installed
|
||||
if not Upgrade.isCustomOLSBinaryInstalled():
|
||||
Upgrade.stdOut("Stock OLS binary detected, ModSecurity compatibility check not needed", 0)
|
||||
return True
|
||||
|
||||
Upgrade.stdOut("=" * 50, 0)
|
||||
Upgrade.stdOut("Detected ModSecurity with custom OpenLiteSpeed binary", 0)
|
||||
Upgrade.stdOut("Updating to ABI-compatible ModSecurity version...", 0)
|
||||
Upgrade.stdOut("=" * 50, 0)
|
||||
|
||||
# Install compatible version
|
||||
if Upgrade.installCompatibleModSecurity():
|
||||
Upgrade.stdOut("ModSecurity compatibility update completed", 0)
|
||||
return True
|
||||
else:
|
||||
Upgrade.stdOut("WARNING: ModSecurity compatibility update failed", 0)
|
||||
Upgrade.stdOut("Server may experience crashes. Please contact support.", 0)
|
||||
return False
|
||||
|
||||
except Exception as msg:
|
||||
Upgrade.stdOut(f"ERROR in ModSecurity compatibility check: {msg}", 0)
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def configureCustomModule():
|
||||
"""Configure CyberPanel module in OpenLiteSpeed config"""
|
||||
|
|
@ -4420,6 +4555,9 @@ pm.max_spare_servers = 3
|
|||
# Configure the custom module
|
||||
Upgrade.configureCustomModule()
|
||||
|
||||
# Check and update ModSecurity compatibility if needed
|
||||
Upgrade.handleModSecurityCompatibility()
|
||||
|
||||
# Restart OpenLiteSpeed to apply changes
|
||||
Upgrade.stdOut("Restarting OpenLiteSpeed...", 0)
|
||||
command = '/usr/local/lsws/bin/lswsctrl restart'
|
||||
|
|
|
|||
Loading…
Reference in New Issue