From 9a2df6451c1ec33941dc4b19dcbd45114b183b9a Mon Sep 17 00:00:00 2001 From: KeatonTheBot Date: Mon, 12 Jan 2026 16:14:39 -0600 Subject: [PATCH] Linux: Fix file picker not launching from disabling core dumps Core dumps are disabled by default on Linux, but this prevents access to the file picker due to security hardening. To work around this, core dumps are selectively enabled and disabled around the file picker tasks. --- src/Ryujinx/Common/ApplicationHelper.cs | 15 +++++ .../DownloadableContentManagerViewModel.cs | 8 +++ .../UI/ViewModels/MainWindowViewModel.cs | 56 +++++++++++++++++++ .../UI/ViewModels/ModManagerViewModel.cs | 7 +++ .../UI/ViewModels/TitleUpdateViewModel.cs | 8 +++ .../UI/Views/Settings/SettingsUIView.axaml.cs | 8 +++ .../UserProfileImageSelectorView.axaml.cs | 8 +++ 7 files changed, 110 insertions(+) diff --git a/src/Ryujinx/Common/ApplicationHelper.cs b/src/Ryujinx/Common/ApplicationHelper.cs index 3efd9ed62..f958c0159 100644 --- a/src/Ryujinx/Common/ApplicationHelper.cs +++ b/src/Ryujinx/Common/ApplicationHelper.cs @@ -18,6 +18,7 @@ using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.Utilities; using Ryujinx.Common.Helper; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.Loaders.Processes.Extensions; @@ -410,6 +411,8 @@ namespace Ryujinx.Ava.Common public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName) { + OsUtils.SetCoreDumpable(true); + Gommon.Optional result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] @@ -419,10 +422,17 @@ namespace Ryujinx.Ava.Common return; ExtractAoc(result.Value.Path.LocalPath, updateFilePath, updateName); + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0) { + OsUtils.SetCoreDumpable(true); + Gommon.Optional result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] @@ -432,6 +442,11 @@ namespace Ryujinx.Ava.Common return; ExtractSection(result.Value.Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex); + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token) diff --git a/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs index 39e53184f..0bec24945 100644 --- a/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs @@ -8,6 +8,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Systems.AppLibrary; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Common.Utilities; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; @@ -128,6 +129,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async void Add() { + OsUtils.SetCoreDumpable(true); + IReadOnlyList result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], @@ -158,6 +161,11 @@ namespace Ryujinx.Ava.UI.ViewModels { await ShowNewDlcAddedDialog(totalDlcAdded); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } private bool AddDownloadableContent(string path, out int numDlcAdded) diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index ae84a15a2..b8062d659 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -1323,6 +1323,8 @@ namespace Ryujinx.Ava.UI.ViewModels private async Task LoadContentFromFolder(LocaleKeys localeMessageAddedKey, LocaleKeys localeMessageRemovedKey, LoadContentFromFolderDelegate onDirsSelected, LocaleKeys dirSelectDialogTitle) { + OsUtils.SetCoreDumpable(true); + Optional> result = await StorageProvider.OpenMultiFolderPickerAsync( new FolderPickerOpenOptions { Title = LocaleManager.Instance[dirSelectDialogTitle] }); @@ -1350,6 +1352,11 @@ namespace Ryujinx.Ava.UI.ViewModels (int)Symbol.Checkmark); }); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } #endregion @@ -1412,6 +1419,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task InstallFirmwareFromFile() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions { FileTypeFilter = new List @@ -1441,20 +1450,34 @@ namespace Ryujinx.Ava.UI.ViewModels { await HandleFirmwareInstallation(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public async Task InstallFirmwareFromFolder() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFolderPickerAsync(); if (result.HasValue) { await HandleFirmwareInstallation(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public async Task InstallKeysFromFile() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions { FileTypeFilter = new List @@ -1472,16 +1495,28 @@ namespace Ryujinx.Ava.UI.ViewModels { await HandleKeysInstallation(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public async Task InstallKeysFromFolder() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFolderPickerAsync(); if (result.HasValue) { await HandleKeysInstallation(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public void OpenRyujinxFolder() @@ -1585,6 +1620,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task OpenFile() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFilePickerAsync(new FilePickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.LoadApplicationFromFileDialogTitle], @@ -1656,6 +1693,11 @@ namespace Ryujinx.Ava.UI.ViewModels LocaleManager.Instance[LocaleKeys.MenuBarFileOpenFromFileError]); } } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public async Task LoadDlcFromFolder() @@ -1678,6 +1720,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task OpenFolder() { + OsUtils.SetCoreDumpable(true); + Optional result = await StorageProvider.OpenSingleFolderPickerAsync( new FolderPickerOpenOptions { @@ -1693,6 +1737,11 @@ namespace Ryujinx.Ava.UI.ViewModels await LoadApplication(applicationData); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public static bool InitializeUserConfig(ApplicationData application) @@ -1900,6 +1949,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task OpenBinFile() { + OsUtils.SetCoreDumpable(true); + if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning) { Optional result = await StorageProvider.OpenSingleFilePickerAsync( @@ -1919,6 +1970,11 @@ namespace Ryujinx.Ava.UI.ViewModels { AppHost.Device.System.ScanAmiiboFromBin(result.Value.Path.LocalPath); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } } public async Task OpenSkylanderWindow() diff --git a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs index 45e67add0..569d293e6 100644 --- a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs @@ -288,6 +288,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async void Add() { + OsUtils.SetCoreDumpable(true); + IReadOnlyList result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle], @@ -298,6 +300,11 @@ namespace Ryujinx.Ava.UI.ViewModels { AddMod(new DirectoryInfo(folder.Path.LocalPath)); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public void DeleteAll() diff --git a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs index 3d34643ab..c10da7bf9 100644 --- a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs @@ -7,6 +7,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Systems.AppLibrary; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Common.Utilities; using System.Collections.Generic; using System.IO; using System.Linq; @@ -148,6 +149,8 @@ namespace Ryujinx.Ava.UI.ViewModels public async Task Add() { + OsUtils.SetCoreDumpable(true); + IReadOnlyList result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { AllowMultiple = true, @@ -177,6 +180,11 @@ namespace Ryujinx.Ava.UI.ViewModels { await ShowNewUpdatesAddedDialog(totalUpdatesAdded); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } public void Save() diff --git a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs index f0742a579..62e4e72a6 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs +++ b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs @@ -7,6 +7,7 @@ using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.Utilities; +using Ryujinx.Common.Utilities; using System.Collections.Generic; using System.IO; using System.Linq; @@ -27,6 +28,8 @@ namespace Ryujinx.Ava.UI.Views.Settings private async Task AddDirButton(TextBox addDirBox, AvaloniaList directories) { + OsUtils.SetCoreDumpable(true); + string path = addDirBox.Text; if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !directories.Contains(path)) @@ -48,6 +51,11 @@ namespace Ryujinx.Ava.UI.Views.Settings ViewModel.GameListNeedsRefresh = true; } } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } private void RemoveGameDirButton_OnClick(object sender, RoutedEventArgs e) diff --git a/src/Ryujinx/UI/Views/User/UserProfileImageSelectorView.axaml.cs b/src/Ryujinx/UI/Views/User/UserProfileImageSelectorView.axaml.cs index 3a5b7c6b7..9b9cc3303 100644 --- a/src/Ryujinx/UI/Views/User/UserProfileImageSelectorView.axaml.cs +++ b/src/Ryujinx/UI/Views/User/UserProfileImageSelectorView.axaml.cs @@ -8,6 +8,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using SkiaSharp; using System.Collections.Generic; @@ -62,6 +63,8 @@ namespace Ryujinx.Ava.UI.Views.User private async void Import_OnClick(object sender, RoutedEventArgs e) { + OsUtils.SetCoreDumpable(true); + IReadOnlyList result = await ((Window)this.GetVisualRoot()!).StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { AllowMultiple = false, @@ -81,6 +84,11 @@ namespace Ryujinx.Ava.UI.Views.User _profile.Image = ProcessProfileImage(File.ReadAllBytes(result[0].Path.LocalPath)); _parent.GoBack(); } + + if (!Program.CoreDumpArg) + { + OsUtils.SetCoreDumpable(false); + } } private void GoBack(object sender, RoutedEventArgs e)