Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug #329: Fix handling of quotes in process sandbox arguments #330

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

/// <summary>
/// This program is a simple launcher that uses native Windows Job objects to prevent
/// child processes from being orphaned should itself or its parent die.
///
///
/// Using minimal threads and resources, it waits for its child process or parent (if specified) to finish, and then it dies.
/// </summary>
namespace ProcessSandbox
Expand All @@ -24,7 +23,7 @@ class Program
"// [--windowStyle STYLE] // one of " + String.Join(", ", Enum.GetNames(typeof(ProcessPriorityClass))) + " (DOES NOT ALWAYS WORK)\r\n" +
"// EXECUTABLE PARAMS...";

static void Main(string[] args)
static void Main()
{
// outside of try to ensure safely cleaned up
Process child = null;
Expand All @@ -40,7 +39,8 @@ static void Main(string[] args)
ProcessPriorityClass? priorityClass = null;
ProcessWindowStyle? windowStyle = null;

ParseArgs(args, ref ppid, ref working, ref exec, ref priorityClass, ref windowStyle, execArgs);
string commandLine = Environment.CommandLine;
ParseArgs(commandLine, ref ppid, ref working, ref exec, ref priorityClass, ref windowStyle, execArgs);

// verify args
if (exec == null)
Expand All @@ -60,8 +60,10 @@ static void Main(string[] args)
job.AddProcess(self.Id);

// kick off the child process...
var startInfo = new ProcessStartInfo(exec, string.Join(" ", execArgs))
var startInfo = new ProcessStartInfo
{
FileName = exec,
Arguments = string.Join(" ", execArgs),
UseShellExecute = false,
RedirectStandardError = false,
RedirectStandardInput = false,
Expand Down Expand Up @@ -118,18 +120,71 @@ static void Main(string[] args)

// produce a response message (for possible JSON consumption) and quit
Console.WriteLine("{\"event\": \"LaunchFailure\", \"arg\": \"" + JSONEscape(exc.Message + " (" + exc.GetType() + ")") + "\"}");
return;
}

}

/// <summary>
/// Splits the command line string into an array of arguments while preserving quotes around arguments containing spaces.
/// </summary>
private static string[] SplitCommandLine(string commandLine)
{
var args = new List<string>();
var currentArg = new StringBuilder();
bool inQuotes = false;

for (int i = 0; i < commandLine.Length; i++)
{
char c = commandLine[i];

if (c == '"')
{
if (inQuotes && i + 1 < commandLine.Length && commandLine[i + 1] == '"')
{
// Handle escaped quotes ""
currentArg.Append(c);
i++;
}
else
{
inQuotes = !inQuotes;
currentArg.Append(c);
}
}
else if (c == ' ' && !inQuotes)
{
if (currentArg.Length > 0)
{
args.Add(currentArg.ToString());
currentArg.Clear();
}
}
else
{
currentArg.Append(c);
}
}

if (currentArg.Length > 0)
{
args.Add(currentArg.ToString());
}

return args.ToArray();
}


/// <summary>
/// This argument parses has to allow for arbitrary arguments after its own are parsed.
/// </summary>
private static void ParseArgs(string[] args, ref uint ppid, ref string working, ref string exec, ref ProcessPriorityClass? priorityClass, ref ProcessWindowStyle? windowStyle, List<string> execArgs)
private static void ParseArgs(string commandLine, ref uint ppid, ref string working, ref string exec, ref ProcessPriorityClass? priorityClass, ref ProcessWindowStyle? windowStyle, List<string> execArgs)
{
var args = SplitCommandLine(commandLine);
var argStream = StringStream(args);

// Skip the first argument, which is the executable path
argStream.MoveNext();

bool parsingSelfArgs = true;

try
Expand All @@ -149,7 +204,6 @@ private static void ParseArgs(string[] args, ref uint ppid, ref string working,
{
argStream.MoveNext();
ppid = uint.Parse(argStream.Current);

}
else if (parsingSelfArgs && lcArg.Equals("--working"))
{
Expand Down Expand Up @@ -177,7 +231,7 @@ private static void ParseArgs(string[] args, ref uint ppid, ref string working,
// first arg must be executable
exec = arg;

// now all args are executable args
// now all args are executable args
parsingSelfArgs = false;
}
else
Expand Down