Unhandled exception reading from X509CertificateStore - c#

I'm working with a really old project and moving it from on-prem to an azure VM running windows server 2016 and after the move we noticed an API endpoint returning Bad Gateway (502). I recreated the request using postman and noticed that I didn't even get a response back. After adding a bunch of logging i narrowed it down to the method below where it's suppose to read the security token from a certificate.
It seems like an unhandled exception occurrs just before the code which iterates each certificate but I can't seem to catch the exception using UnhandledExceptionEventHandler.
As far as I can see all the required certificates are in place. The one used here I even gave the user group "Everyone" full access just to just to eliminate that as a possible reason for the error
In reality this method is full of logging for each line of code but I've removed it for readability.
private static X509SecurityToken GetSecurityTokenBySimpleDisplayName(string simpleDisplayName)
{
if (string.IsNullOrEmpty(simpleDisplayName))
throw new ArgumentNullException("simpleDisplayName");
try
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
using (X509CertificateStore store = X509CertificateStore.LocalMachineStore(X509CertificateStore.MyStore))
{
var isOpen = store.OpenRead();
int certIndex = -1;
/***** HERE IS WHERE IT CRASHES *****/
for (int i = 0; i < store.Certificates.Count; i++)
{
if (store.Certificates[i].SimpleDisplayName.ToLower().Equals(simpleDisplayName.ToLower()))
certIndex = i;
}
if (certIndex < 0)
{
throw new SecurityException("Certificate " + simpleDisplayName + " not found");
}
var token = new X509SecurityToken(store.Certificates[certIndex]);
return token;
}
}
catch(Exception ex)
{
// Logging exception
return null;
}
}
public static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
// Logging exception
}
The application event log gives this error:
Faulting application name: w3wp.exe, version: 10.0.14393.0, time stamp: 0x57899b8a
Faulting module name: KERNELBASE.dll, version: 10.0.14393.3383, time stamp: 0x5ddcba29
Exception code: 0xe0434352
Fault offset: 0x0000000000034c48
Faulting process id: 0x3528
Faulting application start time: 0x01d5f20898415d08
Faulting application path: c:\windows\system32\inetsrv\w3wp.exe
Faulting module path: C:\windows\System32\KERNELBASE.dll
Report Id: 64f16b87-a524-4e0e-9ab9-d8295ce7b29b
Faulting package full name:
Faulting package-relative application ID:
How can I get a better idea of what's wrong?

Found the answer. The application pool needed to be set to "Enable 32-bit application" once that was in place it started working again

Related

Delegate getting GC even after pinning?

Related code here: https://github.com/AkazaRenn/FruitLanguageSwitcher/blob/main/Core/Hotkey.cs#L17
Callback code related class:
internal class Hotkey {
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void AHKDelegate();
private readonly AutoHotkeyEngine ahk = AutoHotkeyEngine.Instance;
private readonly List<GCHandle> handles = new();
public Hotkey(AHKDelegate _onCapsLock) {
SetVarOnSettings();
handles.Add(GCHandle.Alloc(_onCapsLock));
ahk.SetVar("onCapsLockPtr", GetActionDelegateStr(_onCapsLock));
ahk.ExecRaw(System.Text.Encoding.Default.GetString(Properties.Resources.CapsLock));
}
~Hotkey() {
foreach(var handle in handles) {
handle.Free();
}
}
Unmanaged code:
$CapsLock::
If (GetKeyState("CapsLock", "T")) {
SetCapsLockState Off
} else {
KeyWait, CapsLock, T0.5
If (ErrorLevel) {
SetCapsLockState On
KeyWait, CapsLock
} else {
DllCall(onCapsLockPtr)
}
}
Return
The actual delegate passed into Hotkey() can be found here: https://github.com/AkazaRenn/FruitLanguageSwitcher/blob/main/App.xaml.cs#L82
The pinned pointer address of the delegates are sent to AHKDLL (unmanaged) for callback. It will work fine at the beginning, but the program will crash after a random period of time (quite a few hours), with such log in Event Viewer:
Application: FruitLanguageSwitcher.exe
CoreCLR Version: 7.0.222.60605
.NET Version: 7.0.2
Description: The application requested process termination through System.Environment.FailFast.
Message: A callback was made on a garbage collected delegate of type 'FruitLanguageSwitcher!FruitLanguageSwitcher.Core.Hotkey+AHKDelegate::Invoke'.
Stack:
Faulting application name: FruitLanguageSwitcher.exe, version: 1.0.0.0, time stamp: 0x638f99ee
Faulting module name: coreclr.dll, version: 7.0.222.60605, time stamp: 0x638f9099
Exception code: 0x80131623
Fault offset: 0x00000000002662d9
Faulting process id: 0x0xFDC
Faulting application start time: 0x0x1D92F3E416B9F1A
Faulting application path: C:\Program Files\WindowsApps\AkazaRenn.82975CBC0BB1_1.2.2.0_x64__fhf2jh1qk9hx4\FruitLanguageSwitcher.exe
Faulting module path: C:\Program Files\WindowsApps\AkazaRenn.82975CBC0BB1_1.2.2.0_x64__fhf2jh1qk9hx4\coreclr.dll
Report Id: 69384484-bd77-4f32-b5f0-6c01c00fb673
Faulting package full name: AkazaRenn.82975CBC0BB1_1.2.2.0_x64__fhf2jh1qk9hx4
Faulting package-relative application ID: App
I've tried doing mashalling and object pinning, as suggested by some other questions in SOF, but none had solved my problem. I'm quite confused now on how to make my delegate actually pinned. Thanks in advance!
To conclude it simply, I don't even need a GCHandle, simply save the delegate as a static variable can do the job, like:
private static readonly List<AHKDelegate> handlers = new();
public Hotkey(AHKDelegate _onCapsLock, AHKDelegate _onLanguageChange, AHKDelegate _onRaltUp) {
handlers.Add(_onCapsLock);
ahk.SetVar("onCapsLockPtr", GetActionDelegateStr(_onCapsLock));
handlers.Add(_onLanguageChange);
ahk.SetVar("onLanguageChangePtr", GetActionDelegateStr(_onLanguageChange));
handlers.Add(_onRaltUp);
ahk.SetVar("onRaltUpPtr", GetActionDelegateStr(_onRaltUp));
}
Thanks to #HansPassant for pointing it out!

C# error propagating up the stack when it should not

I'm encountering an issue where a service is exiting on errors that should never propagate up.
I built a microservice manager (.NET as the local environment doesnt support .NET Core and some of its native microservice abilities)
Built in VS2019 targeting .NET 4.5.2 (I know, but this is the world we live in)
For the microservice manager, it is built and installed as a windows service. Entry looks like this (#if/#else was for testing locally, it is working as intended when registered as a windows service)
Program.cs (Entry point)
` static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
#if DEBUG
Scheduler myScheduler = new Scheduler();
myScheduler.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Scheduler()
};
ServiceBase.Run(ServicesToRun);
#endif
}
}`
Scheduler.cs
//(confidential code hidden)
`private static readonly Configuration config = Newtonsoft.Json.JsonConvert.DeserializeObject<Configuration>(
File.ReadAllText(configFilePath)
);
public Scheduler()
{
//InitializeComponent(); //windows service, doesnt need UI components initialized
}
public void OnDebug()
{
OnStart(null); //triggers when developing locally
}
protected override async void OnStart(string[] args)
{
try
{
logger.Log($#"Service manager starting...");
logger.Log($#"Finding external services... {config.services.Count} services found.");
foreach (var service in config.services)
{
try
{
if (service.disabled)
{
logger.Log(
$#"Skipping {service.name}: disabled=true in Data Transport Service's appSettings.json file");
continue;
}
logger.Queue($#"Starting: {service.name}...");
string serviceLocation = service.useRelativePath
? Path.Combine(assemblyLocation, service.path)
: service.path;
var svc = Assembly.LoadFrom(serviceLocation);
var assemblyType = svc.GetType($#"{svc.GetName().Name}.Program");
var methodInfo = assemblyType.GetMethod("Main");
var instanceObject = Activator.CreateInstance(assemblyType, new object[0]);
methodInfo.Invoke(instanceObject, new object[0]);
logger.Queue(" Running").Send("");
}
catch (TargetInvocationException ex)
{
logger.Queue(" Failed").Send("");
logger.Log("an error occurred", LOG.LEVEL.CRITICAL, ex);
}
catch (Exception ex)
{
logger.Queue(" Failed").Send("");
logger.Log("an error occurred", LOG.LEVEL.CRITICAL, ex);
}
}
logger.Log("Finished loading services.");
}
catch (Exception ex)
{
logger.Log($#"Critical error encountered", LOG.LEVEL.CRITICAL, ex);
}
}
Microservice:
public [Confidential]()
{
if (currentProfile == null)
{
var errMsg =
$#"Service not loaded, Profile not found, check appSettings.currentProfile: '{config.currentProfile}'";
logger.Log(errMsg,severity: LOG.LEVEL.CRITICAL);
throw new SettingsPropertyNotFoundException(errMsg);
}
if (currentProfile.disabled)
{
var errMsg = $#"Service not loaded: {config.serviceName}, Service's appSettings.currentProfile.disabled=true";
logger.Log(errMsg,LOG.LEVEL.WARN);
throw new ArgumentException(errMsg);
}
logger.Log($#"Loading: '{config.serviceName}' with following configuration:{Environment.NewLine}{JsonConvert.SerializeObject(currentProfile,Formatting.Indented)}");
logger.Queue($#"Encrypting config file passwords...");
bool updateConfig = false;
foreach (var kafkaSource in config.dataTargets)
{
if (!kafkaSource.password.IsEncrypted())
{
updateConfig = true;
logger.Queue($#"%tabEncrypting: {kafkaSource.name}");
kafkaSource.password = kafkaSource.password.Encrypt();
}
else
{
logger.Queue($#"%tabAlready encrypted: {kafkaSource.name}");
}
}
logger.Send(Environment.NewLine);
if (updateConfig)
{
File.WriteAllText(
configFilePath,
Newtonsoft.Json.JsonConvert.SerializeObject(config));
}
var _source = config.dataSources.FirstOrDefault(x=>x.name==currentProfile.dataSource);
var _target = config.dataTargets.FirstOrDefault(x => x.name == currentProfile.dataTarget);
source = new Connectors.Sql(logger,
_source?.name,
_source?.connectionString,
_source.pollingInterval,
_source.maxRowsPerSelect,
_source.maxRowsPerUpdate);
target = new Connectors.KafkaProducer(logger)
{
bootstrapServers = _target?.bootstrapServers,
name = _target?.name,
password = _target?.password.Decrypt(),
sslCaLocation = Path.Combine(assemblyLocation,_target?.sslCaLocation),
topic = _target?.topic,
username = _target?.username
};
Start();
}
public void Start()
{
Timer timer = new Timer();
try
{
logger.Log($#"SQL polling interval: {source.pollingInterval} seconds");
timer.Interval = source.pollingInterval * 1000;
timer.Elapsed += new ElapsedEventHandler(this.OnTimer);
timer.Start();
if (currentProfile.executeOnStartup)
Run();
}
catch (Exception ex)
{
var sb = new StringBuilder();
sb.AppendLine($#"Critical error encountered loading external service: {config.serviceName}.");
if (!timer.Enabled)
sb.AppendLine($#"service unloaded - Schedule not started!");
else
sb.AppendLine($#"service appears to be loaded and running on schedule.");
logger.Log(sb.ToString(), LOG.LEVEL.CRITICAL, ex);
}
}
public void OnTimer(object sender, ElapsedEventArgs e)
{
try
{
Run();
}
catch (Exception ex)
{
logger.Log($#"Critical error during scheduled run on service: {config.serviceName}.", LOG.LEVEL.CRITICAL, ex);
}
}
public async void Run()
{
//Get new alarm events from SQL source
logger.Queue("Looking for new alarms...");
var rows = await GetNewEvents();`
The exception occurred during the GetNewEvents method, which attempted to open a SqlConnection to a SQL server that was unavailable due to network issues, that method intentionally throws an exception, which should throw up to OnTimer, where it gets caught, logged, and the timer keeps running. During development/testing, I used invalid credentials, bad connection string, etc and simulated this type of error and it worked as expected, logged the error, kept running. For some reason recently, that error is not caught in OnTimer, it propagates up, where it should be caught by Start (but isn't), after that it should be caught by the parent service manager which is entirely wrapped in a try/catch with no throw's, and above that (because their could be multiple microservices managed by that service) the entry point to the service manager is wrapped in try/catch with no throws, all for isolation from microservice errors. For some reason though, now, the error from a VERY downstream application is propagating all the way up.
Typically, this code runs 24/7 no issues, the microservice it is loading from the config file launches and runs fine. The entry into that specific microservice starts with a try {...} catch (Exception ex) {...} block.
The concept is to have a microservice manager than can launch a number of microservices without having to install all of them as windows services, and have some level of configuration driven by a config file that dictates how the main service runs.
The microservice represented here opens a SQL connection, reads data, performs business logic, publishes results to Kafka, it does this on a polling interval dictated by the config file contained in the microservice. As stated above, its ran for months without issue.
Recently, I noticed the main microservice manager service was not running on the windows server, I investigated the Server Application Logs and found a "Runtime Error" that essentially stated the microservice, while attempting to connect to sql, failed (network issue) and caused the entire microservice manager to exit. To my understanding, they way I'm launching the microservice should isolate it from the main service manager app. Additionally, the main service manager app is wrapped in a very generic try catch block. The entry point to the micro service itself is wrapped in a try catch, and almost every component in the microservice is wrapped in try / catch per business need. The scenario that faulted (cant connect to sql) intentionally throws an error for logging purposes, but should be caught by the immediate parent try/catch, which does not propagate or re-throw, only logs the error to a txt file and the windows server app log.
How is it that this exception is bubbling up through isolation points and causing the main service to fault and exit? I tested this extensively during development and prior to release, this exact scenario being unable to connect to sql, and it generated the correct log entry, and tried again on the next polling cycle as expected.
I haven't tried any other approaches as yet, as I feel they would be band-aid fixes as best as I dont understand why the original design is suddenly failing. The server hasn't changed, no patching/security updates/etc.
From the server Application Log:
Application: DataTransportService.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.Exception
at Connectors.SqlHelper.DbHelper+d__13`1[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
at IntelligentAlarms.IntelligentAlarm+d__14.MoveNext()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(System.Threading.Tasks.Task)
at IntelligentAlarms.IntelligentAlarm+d__12.MoveNext()
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__6_1(System.Object)
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()

C# application crashes on debug

I have a multithreaded c# project. I have removed a lock, that locked unnecessarily shared objects, and tried to make those shared objects to be for single thread.
The thing is now the process is crashing, with no error whats so ever - not in the event viewer or when I run in debug.
Can anyone suggest a way for me to diagnose the error? Because the fact that visual studio just lets the process stop with nothing for me to work with makes me stuck. My last resort is WinDbg, and I would like to avoid that.
you could try to hook into unhandled app domain exceptions -
http://msdn.microsoft.com/en-GB/library/system.appdomain.unhandledexception.aspx
and also check out unhandled thread exceptions:
https://msdn.microsoft.com/en-GB/library/system.windows.forms.application.threadexception.aspx
(code from example in appdomain link)
using System;
using System.Security.Permissions;
public class Example
{
[SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlAppDomain)]
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
try {
throw new Exception("1");
} catch (Exception e) {
Console.WriteLine("Catch clause caught : {0} \n", e.Message);
}
throw new Exception("2");
}
static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception) args.ExceptionObject;
Console.WriteLine("MyHandler caught : " + e.Message);
Console.WriteLine("Runtime terminating: {0}", args.IsTerminating);
}
}
// The example displays the following output:
// Catch clause caught : 1
//
// MyHandler caught : 2
// Runtime terminating: True
//
// Unhandled Exception: System.Exception: 2
// at Example.Main()
It's also a good idea to check the Exceptions that cause a Debugger-break in Visual studio.
You can find this unter Debug->Exceptions... or with Crtl+D, E
Maybe visual studio just skips the exception that is causing your crash

The server is not operational exception freezes my windows service

In our intranet we got a windows service with 2 timers in it. First one works each 5 minutes and get Active Directory users list and update Database with it, second works each hour and do some other stuff.
Sometime maintenance work on network starts, and service inner logic catch exception and write it to log. It is always the same one - The server is not operational. After it both timer seems to stop working, but service got status - started, and nothing happend any more.
Exception handling look like this:
void UserSyncTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
try
{
new ADUsersSync().Sync();
}
catch(Exception exc) {
Log.ErrorFormat("UserSyncTimer_Elapsed: Exception {0}", exc);
}
}
And there is main try catch block inside Sync function:
public void Sync()
{
try
{
DirectoryEntry Ldap = new DirectoryEntry("LDAP://OU=Users,OU=MOS1,OU=CCE,DC=portal,DC=ru");
DirectorySearcher searcher = new DirectorySearcher(Ldap);
searcher.Filter = "(&(objectClass=user)(objectCategory=Person)(memberOf:1.2.840.113556.1.4.1941:=CN=All Users,OU=DL,OU=Groups,DC=portal,DC=ru)) ";
SearchResultCollection _s = searcher.FindAll();
foreach (SearchResult sr in _s)
{
//... some code ..
}
}
catch (Exception e)
{
Log.DebugFormat("ADUsersSync Debug: in main catch and exception: {0}", e.Message);
Log.Error(e);
}
}
Logs looks like this:
2014-08-31 14:12:49,956 [10] DEBUG PortalService.BLL.ADUsersSync - ADUsersSync Debug: in main catch and exception: The server is not operational.
2014-08-31 14:12:49,966 [10] ERROR PortalService.BLL.ADUsersSync - System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational.
at System.DirectoryServices.SearchResultCollection.ResultsEnumerator.MoveNext()
at PortalService.BLL.ADUsersSync.Sync()
2014-08-31 14:17:50,169 [5] DEBUG PortalService.BLL.ADUsersSync - ADUsersSync Debug: in main catch and exception: The server is not operational.
2014-08-31 14:17:50,170 [5] ERROR PortalService.BLL.ADUsersSync - System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational.
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindAll()
at TNTPortalService.BLL.ADUsersSync.Sync()
What can i do to prevent service from freezing?
Also there was memory leak because of not disposing SearchResultCollection, and it consume 1.5GB RAM on server. Wayting for the next fial to make deep check with company it support.

Handling AppDomain.CurrentDomain.UnhandledException in windows service

I have window service which acts as a sync software. I want to add unhanded exception logging on my service, so I modified my program.cs like this:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
static void Main()
{
// Register Unhandled Exception Handler
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(UnhandledExceptionHandler);
// Run Service
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service()
};
ServiceBase.Run(ServicesToRun);
}
static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs args)
{
// Get Exception
Exception ex = (Exception)args.ExceptionObject;
// Generate Error
string ErrorMessage = String.Format(
"Error: {0}\r\n" +
"Runtime Terminating: {1}\r\n----- ----- ----- ----- ----- -----\r\n\r\n" +
"{2}\r\n\r\n####################################\r\n",
ex.Message,
args.IsTerminating,
ex.StackTrace.Trim());
// Write Error To File
try
{
using (StreamWriter sw = File.AppendText("UnhandledExceptions.log"))
sw.WriteLine(errorMessage);
}
catch { }
}
}
Then on my Service.cs file, in the OnStart method, I added a throw new Exception("test"); to see if unhanded exceptions are being logged to file as expected.
When I start my service, it stops immediately as expected; however it doesn't seem to be logging the exception to the specified file.
Any idea what I am doing wrong here? Thanks in advance for any help.
Before you ask, my service runs as Local Service and the directory where my service .exe runs from (c:\mysync) already has Local Service added in the security tab with full read/write access.
OnStart is called in Service base class inside try-catch block. If an exception happens on this stage it catches it and just set a status 1 as a result and do not throw it further:
string[] args = (string[]) state;
try
{
this.OnStart(args);
.....
}
catch (Exception ex)
{
this.WriteEventLogEntry(Res.GetString("StartFailed", new object[1]
{
(object) ((object) ex).ToString()
}), EventLogEntryType.Error);
this.status.currentState = 1;
}
As a result you can find a record in EventLogs, but you can't catch it as an unhanded domain exception, as there is no such exception.
using (StreamWriter sw = File.AppendText("UnhandledExceptions.log"))
It is forever a really bad idea to not use full path names for files (like c:\foo\bar.log). Especially in a service, you have very little control over the default directory for your service. Because it is started by the service control manager, not by the user from the command prompt or a desktop shortcut.
So high odds that you are just looking at the wrong file. The real one probably ended up being written to c:\windows\system32 (or syswow64). The operating system directories are normally write protected but that doesn't work for a service, they run with a highly privileged account so can litter the hard drive anywhere.
Always use full path names. Using the EventLog instead is highly recommended.

Categories