When mails are processed in parallel filters can't read the content files
SMTP email proxy and relay server
Brought to you by:
graeme_walker
When E-Mails are processed in parallel, Filter Programs can't read the content file.
I have attached two .net 4.8 projects which demonstrate the problem. a ReadFilter which is a minimal filter wich reproduces the issue and a BulkMailSender which can be used to send mails in parrallel:
The used filter does nothing, but opening the file for a short moment (simulate reading) and sleeping (simulate processing):
ReadFilter Program.cs:
using System;
using System.IO;
using System.Threading;
var contentFilePath = Environment.GetCommandLineArgs()[1];
try
{
using (var fileStream = File.Open(contentFilePath, FileMode.Open, FileAccess.Read))
{
}
}
catch (IOException ex)
{
Console.WriteLine($"<<{ex.Message}>>");
return 2;
}
Thread.Sleep(5000);
return 0;
Repro:
1. Install E-MailRelay as service 2.5 on Windows
2. Replace content of emailrelay-start.bat:
start "emailrelay" "C:\Program Files\E-MailRelay\emailrelay.exe" --close-stderr --filter C:\ProgramData\E-MailRelay\ReadFilter.exe --log --log-file C:\ProgramData\E-MailRelay\emailrelay-log-%%d.txt --log-time --pid-file C:\ProgramData\E-MailRelay\emailrelay.pid --spool-dir C:\ProgramData\E-MailRelay\spool --verbose
One mail will be accepted, and one mail will be rejected, because the filter can't access the content file.
emailrelay-log.txt:
emailrelay: 20230913.140522.830: info: rejected by filter: [The process cannot access the file 'C:\\ProgramData\\E-MailRelay\\spool\\emailrelay.6988.1694606722.22.content' because it is being used by another process.]
The executables which are generated by the attached projects:
Thanks, I'll take a look later. The content file should be in the closed state when the filter runs (see src/gsmtp/gprotocolmessagestore.cpp(144) and src/gstore/gnewfile.cpp(89)).
The problem seems to be that the first message's filter inherits the file handle to the second message's content file and then .NET File.Open() in the second filter requires exclusive access. FWIW a filter using cscript and Scripting.FileSystemObject.OpenTextFile() works okay.
I think the best fix would be to use UpdateProcThreadAttribute() with PROC_THREAD_ATTRIBUTE_HANDLE_LIST to limit the set of inherited file handles when doing CreateProcess.
Thank you for your quick response. I assume, that you will fix this with your next release?
Yes, I will proably be doing a 2.5.1 release in the next month or so. I've attached the patch and uploaded an executable here:
https://sourceforge.net/projects/emailrelay/files/OldFiles/emailrelay-2.5p2.exe/download
Thank you very much. Using the Executable in a Windows Sandbox i could confirm that the issue has been resolved.
Sadly when checking the exe on VirusTotal, three security providers have flagged it as malicious: https://www.virustotal.com/gui/file/2bccf7500543dc07147efc78da269a27819dca6ec9b726341cbbbc16b1e03c58/detection
Before you get too hung up on VirusTotal try an experiment... Grab a Microsoft evaluation VM image from here:
https://developer.microsoft.com/en-us/windows/downloads/virtual-machines/
I used VirtualBox on Linux with 32Gb of memory but it still needed ~8Gb of swap and took forever to initialise, so try for a 64Gb host machine.
Configure the VM with no network adaptor.
Write a "hello world" C program ("notepad test.c"):
Build it from a "x64 native tools command prompt for vs 2022" shell using "cl test.c" There's no need to update VisualStudio. Then take a checksum with:
Submit "test.exe" to VirusTotal -- you can enable the network now that you have the SHA256 hash. Make sure the VirusTotal checksum matches the checksum you got earlier.
I found the results enlightening. What do you get?
Fixed in v2.5.1