Compare commits

..

2 Commits

Author SHA1 Message Date
Thomas Boop
bf647c0e9e fix value escaping 2022-08-30 15:27:42 -04:00
Konrad Pabjan
59894790de Validate lines and columns for Annotations (#2082) 2022-08-24 16:02:51 -04:00
6 changed files with 28 additions and 37 deletions

View File

@@ -1,6 +1,9 @@
## Bugs ## Bugs
- Fixed an issue where self hosted environments had their docker env's overwritten (#2107) - Avoid key based command injection via Docker command arguments (#2062)
## Misc ## Misc
- Added step context name and start/finish time in step telemetry (#2069)
- Improved error logs when there is a missing 'using' token configuration in the metadata file (#2052)
- Added full job name and nested workflow details in log (#2049)
## Windows x64 ## Windows x64
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows. We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.

View File

@@ -1 +1 @@
2.296.2 <Update to ./src/runnerversion when creating release>

View File

@@ -585,6 +585,8 @@ namespace GitHub.Runner.Worker
public void ProcessCommand(IExecutionContext context, string inputLine, ActionCommand command, ContainerInfo container) public void ProcessCommand(IExecutionContext context, string inputLine, ActionCommand command, ContainerInfo container)
{ {
ValidateLinesAndColumns(command, context);
command.Properties.TryGetValue(IssueCommandProperties.File, out string file); command.Properties.TryGetValue(IssueCommandProperties.File, out string file);
command.Properties.TryGetValue(IssueCommandProperties.Line, out string line); command.Properties.TryGetValue(IssueCommandProperties.Line, out string line);
command.Properties.TryGetValue(IssueCommandProperties.Column, out string column); command.Properties.TryGetValue(IssueCommandProperties.Column, out string column);

View File

@@ -6,9 +6,6 @@ namespace GitHub.Runner.Worker.Container
{ {
public class DockerUtil public class DockerUtil
{ {
private static readonly Regex QuoteEscape = new Regex(@"(\\*)" + "\"", RegexOptions.Compiled);
private static readonly Regex EndOfStringEscape = new Regex(@"(\\+)$", RegexOptions.Compiled);
public static List<PortMapping> ParseDockerPort(IList<string> portMappingLines) public static List<PortMapping> ParseDockerPort(IList<string> portMappingLines)
{ {
const string targetPort = "targetPort"; const string targetPort = "targetPort";
@@ -71,7 +68,7 @@ namespace GitHub.Runner.Worker.Container
{ {
return ""; return "";
} }
return $"{flag} {EscapeString(key)}"; return $"{flag} \"{EscapeString(key)}\"";
} }
public static string CreateEscapedOption(string flag, string key, string value) public static string CreateEscapedOption(string flag, string key, string value)
@@ -80,28 +77,12 @@ namespace GitHub.Runner.Worker.Container
{ {
return ""; return "";
} }
var escapedString = EscapeString($"{key}={value}"); return $"{flag} \"{EscapeString(key)}={value.Replace("\"", "\\\"")}\"";
return $"{flag} {escapedString}";
} }
private static string EscapeString(string value) private static string EscapeString(string value)
{ {
if (String.IsNullOrEmpty(value)) return value.Replace("\\", "\\\\").Replace("\"", "\\\"");
{
return "";
}
// Dotnet escaping rules are weird here, we can only escape \ if it precedes a "
// If a double quotation mark follows two or an even number of backslashes, each proceeding backslash pair is replaced with one backslash and the double quotation mark is removed.
// If a double quotation mark follows an odd number of backslashes, including just one, each preceding pair is replaced with one backslash and the remaining backslash is removed; however, in this case the double quotation mark is not removed.
// https://docs.microsoft.com/en-us/dotnet/api/system.environment.getcommandlineargs?redirectedfrom=MSDN&view=net-6.0#remarks
// First, find any \ followed by a " and double the number of \ + 1.
value = QuoteEscape.Replace(value, @"$1$1\" + "\"");
// Next, what if it ends in `\`, it would escape the end quote. So, we need to detect that at the end of the string and perform the same escape
// Luckily, we can just use the $ character with detects the end of string in regex
value = EndOfStringEscape.Replace(value, @"$1$1");
// Finally, wrap it in quotes
return $"\"{value}\"";
} }
} }
} }

View File

@@ -149,12 +149,13 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Worker")] [Trait("Category", "Worker")]
[InlineData("", "")] [InlineData("", "")]
[InlineData("foo", "foo")] [InlineData("HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #")]
[InlineData("foo \\ bar", "foo \\ bar")] [InlineData("HOME \"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #")]
[InlineData("foo \\", "foo \\\\")] [InlineData("HOME \\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #")]
[InlineData("foo \\\\", "foo \\\\\\\\")] [InlineData("HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\\\\\"alpine:3.8 sh -c id #")]
[InlineData("foo \\\" bar", "foo \\\\\\\" bar")] [InlineData("HOME \"\"alpine:3.8 sh -c id #", "HOME \\\"\\\"alpine:3.8 sh -c id #")]
[InlineData("foo \\\\\" bar", "foo \\\\\\\\\\\" bar")] [InlineData("HOME \\\"\"alpine:3.8 sh -c id #", "HOME \\\\\\\"\\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \"\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\\\\\"alpine:3.8 sh -c id #")]
public void CreateEscapedOption_keyOnly(string input, string escaped) public void CreateEscapedOption_keyOnly(string input, string escaped)
{ {
var flag = "--example"; var flag = "--example";
@@ -174,11 +175,15 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
[Theory] [Theory]
[Trait("Level", "L0")] [Trait("Level", "L0")]
[Trait("Category", "Worker")] [Trait("Category", "Worker")]
[InlineData("foo", "bar", "foo=bar")] [InlineData("HOME", "", "HOME", "")]
[InlineData("foo\\", "bar", "foo\\=bar")] [InlineData("HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #", "HOME alpine:3.8 sh -c id #")]
[InlineData("foo\\", "bar\\", "foo\\=bar\\\\")] [InlineData("HOME \"alpine:3.8 sh -c id #", "HOME \"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #")]
[InlineData("foo \\","bar \\", "foo \\=bar \\\\")] [InlineData("HOME \\\"alpine:3.8 sh -c id #", "HOME \\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #", "HOME \\\\\"alpine:3.8 sh -c id #")]
public void CreateEscapedOption_keyValue(string keyInput, string valueInput, string escapedString) [InlineData("HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\\\\\"alpine:3.8 sh -c id #", "HOME \\\\\\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \"\"alpine:3.8 sh -c id #", "HOME \"\"alpine:3.8 sh -c id #", "HOME \\\"\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \\\"\"alpine:3.8 sh -c id #", "HOME \\\"\"alpine:3.8 sh -c id #", "HOME \\\\\\\"\\\"alpine:3.8 sh -c id #", "HOME \\\\\"\\\"alpine:3.8 sh -c id #")]
[InlineData("HOME \"\\\"alpine:3.8 sh -c id #", "HOME \"\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\\\\\"alpine:3.8 sh -c id #", "HOME \\\"\\\\\"alpine:3.8 sh -c id #")]
public void CreateEscapedOption_keyValue(string keyInput, string valueInput, string escapedKey, string escapedValue)
{ {
var flag = "--example"; var flag = "--example";
var actual = DockerUtil.CreateEscapedOption(flag, keyInput, valueInput); var actual = DockerUtil.CreateEscapedOption(flag, keyInput, valueInput);
@@ -189,7 +194,7 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
} }
else else
{ {
expected = $"{flag} \"{escapedString}\""; expected = $"{flag} \"{escapedKey}={escapedValue}\"";
} }
Assert.Equal(expected, actual); Assert.Equal(expected, actual);
} }

View File

@@ -1 +1 @@
2.296.2 2.296.0