mirror of
https://github.com/unraid/webgui.git
synced 2026-01-06 09:39:58 -06:00
Merge pull request #2421 from Squidly271/POC/safeeval
Refactor: Protect GUI from fatal PHP errors
This commit is contained in:
1
emhttp/plugins/dynamix.docker.manager/AddContainer.page
Normal file → Executable file
1
emhttp/plugins/dynamix.docker.manager/AddContainer.page
Normal file → Executable file
@@ -1,6 +1,7 @@
|
||||
Title="Add Container"
|
||||
Cond="(pgrep('dockerd')!==false)"
|
||||
Markdown="false"
|
||||
Eval="true"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2023, Lime Technology
|
||||
|
||||
@@ -89,6 +89,7 @@ if (count($pages)) {
|
||||
@unlink($nchan_pid);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html <?= $display['rtl'] ?>lang="<?= strtok($locale, '_') ?: 'en' ?>" class="<?= $themeHelper->getThemeHtmlClass() ?>">
|
||||
@@ -143,16 +144,23 @@ if (count($pages)) {
|
||||
|
||||
<?php require_once "$docroot/webGui/include/DefaultPageLayout/HeadInlineJS.php"; ?>
|
||||
<?php
|
||||
foreach ($buttonPages as $button) {
|
||||
annotate($button['file']);
|
||||
includePageStylesheets($button);
|
||||
eval('?>' . parse_text($button['text']));
|
||||
}
|
||||
foreach ($buttonPages as $button) {
|
||||
annotate($button['file']);
|
||||
includePageStylesheets($button);
|
||||
$evalContent = '?>' . parse_text($button['text']);
|
||||
$evalFile = $button['file'];
|
||||
if ( filter_var($button['Eval']??false, FILTER_VALIDATE_BOOLEAN) ) {
|
||||
eval($evalContent);
|
||||
} else {
|
||||
include "$docroot/webGui/include/DefaultPageLayout/evalContent.php";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach ($pages as $page) {
|
||||
annotate($page['file']);
|
||||
includePageStylesheets($page);
|
||||
}
|
||||
foreach ($pages as $page) {
|
||||
annotate($page['file']);
|
||||
includePageStylesheets($page);
|
||||
}
|
||||
?>
|
||||
|
||||
<?php include "$docroot/plugins/dynamix.my.servers/include/myservers1.php" ?>
|
||||
@@ -169,4 +177,4 @@ foreach ($pages as $page) {
|
||||
<?php include "$docroot/webGui/include/DefaultPageLayout/ToastSetup.php"; ?>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
18
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php
Normal file → Executable file
18
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabbed.php
Normal file → Executable file
@@ -46,7 +46,13 @@
|
||||
if (isset($page['text'])) {
|
||||
$skipIndexIncrement = true;
|
||||
annotate($page['file']);
|
||||
eval('?>'.generateContent($page));
|
||||
$evalContent = '?>'.generateContent($page);
|
||||
$evalFile = $page['file'];
|
||||
if ( filter_var($page['Eval']??false, FILTER_VALIDATE_BOOLEAN) ) {
|
||||
eval($evalContent);
|
||||
} else {
|
||||
include "$docroot/webGui/include/DefaultPageLayout/evalContent.php";
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -63,7 +69,15 @@
|
||||
>
|
||||
<?= generatePanels($page, $path, $defaultIcon, $docroot) ?>
|
||||
|
||||
<? eval('?>'.generateContent($page)); ?>
|
||||
<?
|
||||
$evalContent = '?>'.generateContent($page);
|
||||
$evalFile = $page['file'];
|
||||
if ( filter_var($page['Eval']??false, FILTER_VALIDATE_BOOLEAN) ) {
|
||||
eval($evalContent);
|
||||
} else {
|
||||
include "$docroot/webGui/include/DefaultPageLayout/evalContent.php";
|
||||
}
|
||||
?>
|
||||
</section>
|
||||
<?
|
||||
if ($skipIndexIncrement) {
|
||||
|
||||
10
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php
Normal file → Executable file
10
emhttp/plugins/dynamix/include/DefaultPageLayout/MainContentTabless.php
Normal file → Executable file
@@ -19,7 +19,15 @@
|
||||
|
||||
<?= generatePanels($page, $path, $defaultIcon, $docroot, true) ?>
|
||||
|
||||
<? eval('?>'.generateContent($page)); ?>
|
||||
<?
|
||||
$evalContent = '?>'.generateContent($page);
|
||||
$evalFile = $page['file'];
|
||||
if ( filter_var($page['Eval']??false, FILTER_VALIDATE_BOOLEAN) ) {
|
||||
eval($evalContent);
|
||||
} else {
|
||||
include "$docroot/webGui/include/DefaultPageLayout/evalContent.php";
|
||||
}
|
||||
?>
|
||||
<? endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
47
emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php
Executable file
47
emhttp/plugins/dynamix/include/DefaultPageLayout/evalContent.php
Executable file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
// This evaluates the contents of PHP code. Has to be "included" because the code is evaluated in the context of the calling page.
|
||||
// $evalContent is the PHP code to evaluate.
|
||||
// $evalFile is the file that the code is being evaluated in
|
||||
// Errors will be logged in the console and the php error log
|
||||
// The PHP error logged will also include the path of the .page file for easier debugging
|
||||
|
||||
$evalSuccess = false;
|
||||
$evalFile = $evalFile ?? "Unknown";
|
||||
if ( ! ($evalContent ?? false) ) {
|
||||
error_log("No evalContent within $evalFile");
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
try {
|
||||
set_error_handler(function($severity, $message, $file, $line) use ($evalFile) {
|
||||
// If error was suppressed with @, error_reporting will be 0
|
||||
if (!(error_reporting() & $severity)) {
|
||||
return true;
|
||||
}
|
||||
// Only convert fatal errors to exceptions
|
||||
$fatalErrors = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR;
|
||||
if ($severity & $fatalErrors) {
|
||||
error_log("PHP Fatal Error (Severity: $severity) in $evalFile: $message");
|
||||
throw new ErrorException($message, 0, $severity, $file, $line);
|
||||
} else {
|
||||
// Log non-fatal errors with evalFile context
|
||||
error_log("PHP Error (Severity: $severity) in $evalFile: $message at $file:$line");
|
||||
}
|
||||
// Let warnings and notices be handled normally
|
||||
return false;
|
||||
});
|
||||
eval($evalContent);
|
||||
restore_error_handler();
|
||||
$evalSuccess = true;
|
||||
ob_end_flush();
|
||||
} catch (Throwable $e) {
|
||||
restore_error_handler();
|
||||
$severity = ($e instanceof ErrorException) ? $e->getSeverity() : 'N/A';
|
||||
error_log("Error evaluating content in $evalFile (severity: $severity): ".$e->getMessage()."\nStack trace:\n".$e->getTraceAsString());
|
||||
ob_clean();
|
||||
$errorMessage = "Error evaluating content in $evalFile: ".$e->getMessage();
|
||||
echo "<script>console.error(".json_encode($errorMessage).");</script>";
|
||||
ob_end_flush();
|
||||
}
|
||||
?>
|
||||
18
emhttp/plugins/dynamix/include/PageBuilder.php
Normal file → Executable file
18
emhttp/plugins/dynamix/include/PageBuilder.php
Normal file → Executable file
@@ -18,7 +18,11 @@ function get_ini_key($key,$default) {
|
||||
$x = strpos($key, '[');
|
||||
$var = $x>0 ? substr($key,1,$x-1) : substr($key,1);
|
||||
global $$var;
|
||||
eval("\$var=$key;");
|
||||
try {
|
||||
eval("\$var=$key;");
|
||||
} catch (Throwable $e) {
|
||||
return $default;
|
||||
}
|
||||
return $var ?: $default;
|
||||
}
|
||||
|
||||
@@ -44,10 +48,14 @@ function build_pages($pattern) {
|
||||
|
||||
function page_enabled(&$page)
|
||||
{
|
||||
global $var,$disks,$devs,$users,$shares,$sec,$sec_nfs,$name,$display,$pool_devices;
|
||||
$enabled = true;
|
||||
if (isset($page['Cond'])) eval("\$enabled={$page['Cond']};");
|
||||
return $enabled;
|
||||
global $docroot,$var,$disks,$devs,$users,$shares,$sec,$sec_nfs,$name,$display,$pool_devices;
|
||||
$enabled = $evalSuccess = true;
|
||||
if (isset($page['Cond'])) {
|
||||
$evalContent= "\$enabled={$page['Cond']};";
|
||||
$evalFile = $page['file'];
|
||||
include "$docroot/webGui/include/DefaultPageLayout/evalContent.php";
|
||||
}
|
||||
return ($enabled && $evalSuccess);
|
||||
}
|
||||
|
||||
function find_pages($item) {
|
||||
|
||||
Reference in New Issue
Block a user