From 0c004135f631fecae673fbfc5598945c92614362 Mon Sep 17 00:00:00 2001 From: Fabrice DIDIERJEAN Date: Wed, 22 Jul 2026 17:57:46 +0200 Subject: [PATCH] fix: prevent SIGSEGV in /frm config on dedicated servers The `/frm config` chat command resolved the calling player's controller via Sender->GetPlayer()->GetControlledCharacter()->GetLocalViewingPlayerController(). On a dedicated server there is no local viewing player controller, so that chain returns null and the following GetDSPrivilegeLevel() call dereferences it, crashing the server (SIGSEGV) on any /frm config invocation. UCommandSender::GetPlayer() already returns the sender's server-side AFGPlayerController, so use it directly and null-guard it (a null/console sender is treated as trusted). Also add the missing early return so a player without sufficient privileges no longer falls through and applies the setting anyway. --- .../Private/Commands/multi.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Source/FicsitRemoteMonitoring/Private/Commands/multi.cpp b/Source/FicsitRemoteMonitoring/Private/Commands/multi.cpp index 9193496a..2467c5d2 100644 --- a/Source/FicsitRemoteMonitoring/Private/Commands/multi.cpp +++ b/Source/FicsitRemoteMonitoring/Private/Commands/multi.cpp @@ -134,8 +134,14 @@ FChatReturn AFRMCommand::RemoteMonitoringCommand(UObject* WorldContext, UCommand FString arg1 = Arguments[1].ToLower(); FString arg2 = Arguments[2].ToLower(); - AFGPlayerController* PlayerController = Cast(Sender->GetPlayer()->GetControlledCharacter()->GetLocalViewingPlayerController()); - EPrivilegeLevel PrivilegeLevel = PlayerController->GetDSPrivilegeLevel(); + // UCommandSender::GetPlayer() already returns the sender's server-side AFGPlayerController. + // The previous GetControlledCharacter()->GetLocalViewingPlayerController() detour is null on a + // dedicated server (no local client) and crashed (SIGSEGV) on ANY /frm config. A null controller + // here means a non-player/console sender, which we treat as trusted. + AFGPlayerController* PlayerController = Sender ? Sender->GetPlayer() : nullptr; + // A null (console/non-player) sender is trusted -> InitialAdmin so the check below passes and + // short-circuits before ever calling GetNetMode() on the null controller. + const EPrivilegeLevel PrivilegeLevel = IsValid(PlayerController) ? PlayerController->GetDSPrivilegeLevel() : EPrivilegeLevel::InitialAdmin; if (PrivilegeLevel != EPrivilegeLevel::Administrator && PrivilegeLevel != EPrivilegeLevel::InitialAdmin && @@ -145,7 +151,8 @@ FChatReturn AFRMCommand::RemoteMonitoringCommand(UObject* WorldContext, UCommand ChatReturn.Chat = FString(TEXT("Insufficient Permissions to set " + arg1 + " to " +arg2)); ChatReturn.Color = FLinearColor::Red; ChatReturn.Status = EExecutionStatus::COMPLETED; - } + return ChatReturn; + } if (UFRMConfigManager::SetConfigFromInput(arg1, arg2)) {