Skip to content

Commit cc5e12c

Browse files
[SNOW-1156046] fix toctou vulnerability in EasyLogginConfig
1 parent 47235fb commit cc5e12c

File tree

3 files changed

+58
-47
lines changed

3 files changed

+58
-47
lines changed

Snowflake.Data.Tests/UnitTests/Configuration/EasyLoggingConfigFinderTest.cs

+16-17
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,23 @@ public class EasyLoggingConfigFinderTest
3939
public void Setup()
4040
{
4141
t_fileOperations = new Mock<FileOperations>();
42-
t_unixOperations = new Mock<UnixOperations>();
4342
t_environmentOperations = new Mock<EnvironmentOperations>();
44-
t_finder = new EasyLoggingConfigFinder(t_fileOperations.Object, t_unixOperations.Object, t_environmentOperations.Object);
43+
t_finder = new EasyLoggingConfigFinder(t_fileOperations.Object, t_environmentOperations.Object);
4544
MockHomeDirectory();
4645
MockExecutionDirectory();
4746
}
48-
47+
4948
[Test]
5049
public void TestThatTakesFilePathFromTheInput()
5150
{
5251
// arrange
5352
MockFileFromEnvironmentalVariable();
5453
MockFileOnDriverPath();
5554
MockFileOnHomePath();
56-
55+
5756
// act
5857
var filePath = t_finder.FindConfigFilePath(InputConfigFilePath);
59-
58+
6059
// assert
6160
Assert.AreEqual(InputConfigFilePath, filePath);
6261
t_fileOperations.VerifyNoOtherCalls();
@@ -71,14 +70,14 @@ public void TestThatTakesFilePathFromEnvironmentVariableIfInputNotPresent(
7170
MockFileFromEnvironmentalVariable();
7271
MockFileOnDriverPath();
7372
MockFileOnHomePath();
74-
73+
7574
// act
7675
var filePath = t_finder.FindConfigFilePath(inputFilePath);
77-
76+
7877
// assert
7978
Assert.AreEqual(EnvironmentalConfigFilePath, filePath);
8079
}
81-
80+
8281
[Test]
8382
public void TestThatTakesFilePathFromDriverLocationWhenNoInputParameterNorEnvironmentVariable()
8483
{
@@ -88,20 +87,20 @@ public void TestThatTakesFilePathFromDriverLocationWhenNoInputParameterNorEnviro
8887

8988
// act
9089
var filePath = t_finder.FindConfigFilePath(null);
91-
90+
9291
// assert
9392
Assert.AreEqual(s_driverConfigFilePath, filePath);
9493
}
95-
94+
9695
[Test]
9796
public void TestThatTakesFilePathFromHomeLocationWhenNoInputParamEnvironmentVarNorDriverLocation()
9897
{
9998
// arrange
10099
MockFileOnHomePath();
101-
100+
102101
// act
103102
var filePath = t_finder.FindConfigFilePath(null);
104-
103+
105104
// assert
106105
Assert.AreEqual(s_homeConfigFilePath, filePath);
107106
}
@@ -138,13 +137,13 @@ public void TestThatConfigFileIsNotUsedIfOthersCanModifyTheConfigFile()
138137
Assert.IsNotNull(thrown);
139138
Assert.AreEqual(thrown.Message, $"Error due to other users having permission to modify the config file: {s_homeConfigFilePath}");
140139
}
141-
140+
142141
[Test]
143142
public void TestThatReturnsNullIfNoWayOfGettingTheFile()
144143
{
145144
// act
146145
var filePath = t_finder.FindConfigFilePath(null);
147-
146+
148147
// assert
149148
Assert.IsNull(filePath);
150149
}
@@ -157,7 +156,7 @@ public void TestThatDoesNotFailWhenSearchForOneOfDirectoriesFails()
157156

158157
// act
159158
var filePath = t_finder.FindConfigFilePath(null);
160-
159+
161160
// assert
162161
Assert.IsNull(filePath);
163162
t_environmentOperations.Verify(e => e.GetFolderPath(Environment.SpecialFolder.UserProfile), Times.Once);
@@ -186,7 +185,7 @@ public void TestThatDoesNotFailWhenHomeDirectoryDoesNotExist()
186185

187186
// act
188187
var filePath = t_finder.FindConfigFilePath(null);
189-
188+
190189
// assert
191190
Assert.IsNull(filePath);
192191
t_environmentOperations.Verify(e => e.GetFolderPath(Environment.SpecialFolder.UserProfile), Times.Once);
@@ -220,7 +219,7 @@ private static void MockExecutionDirectory()
220219
.Setup(e => e.GetExecutionDirectory())
221220
.Returns(DriverDirectory);
222221
}
223-
222+
224223
private static void MockFileOnHomePathDoesNotExist()
225224
{
226225
t_fileOperations

Snowflake.Data/Configuration/EasyLoggingConfigFinder.cs

+6-26
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,13 @@ internal class EasyLoggingConfigFinder
1919
internal const string ClientConfigEnvironmentName = "SF_CLIENT_CONFIG_FILE";
2020

2121
private readonly FileOperations _fileOperations;
22-
private readonly UnixOperations _unixOperations;
2322
private readonly EnvironmentOperations _environmentOperations;
2423

25-
public static readonly EasyLoggingConfigFinder Instance = new EasyLoggingConfigFinder(FileOperations.Instance, UnixOperations.Instance, EnvironmentOperations.Instance);
24+
public static readonly EasyLoggingConfigFinder Instance = new EasyLoggingConfigFinder(FileOperations.Instance, EnvironmentOperations.Instance);
2625

27-
internal EasyLoggingConfigFinder(FileOperations fileOperations, UnixOperations unixFileOperations, EnvironmentOperations environmentOperations)
26+
internal EasyLoggingConfigFinder(FileOperations fileOperations, EnvironmentOperations environmentOperations)
2827
{
2928
_fileOperations = fileOperations;
30-
_unixOperations = unixFileOperations;
3129
_environmentOperations = environmentOperations;
3230
}
3331

@@ -38,16 +36,12 @@ internal EasyLoggingConfigFinder()
3836
public virtual string FindConfigFilePath(string configFilePathFromConnectionString)
3937
{
4038
var configFilePath = GetFilePathFromInputParameter(configFilePathFromConnectionString, "connection string")
41-
?? GetFilePathEnvironmentVariable()
42-
?? GetFilePathFromDriverLocation()
43-
?? GetFilePathFromHomeDirectory();
44-
if (configFilePath != null)
45-
{
46-
CheckIfValidPermissions(configFilePath);
47-
}
39+
?? GetFilePathEnvironmentVariable()
40+
?? GetFilePathFromDriverLocation()
41+
?? GetFilePathFromHomeDirectory();
4842
return configFilePath;
4943
}
50-
44+
5145
private string GetFilePathEnvironmentVariable()
5246
{
5347
var filePath = _environmentOperations.GetEnvironmentVariable(ClientConfigEnvironmentName);
@@ -100,19 +94,5 @@ private string OnlyIfFileExists(string filePath, string directoryDescription)
10094
}
10195
return null;
10296
}
103-
104-
private void CheckIfValidPermissions(string filePath)
105-
{
106-
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
107-
return;
108-
109-
// Check if others have permissions to modify the file and fail if so
110-
if (_unixOperations.CheckFileHasAnyOfPermissions(filePath, FileAccessPermissions.GroupWrite | FileAccessPermissions.OtherWrite))
111-
{
112-
var errorMessage = $"Error due to other users having permission to modify the config file: {filePath}";
113-
s_logger.Error(errorMessage);
114-
throw new Exception(errorMessage);
115-
}
116-
}
11797
}
11898
}

Snowflake.Data/Configuration/EasyLoggingConfigParser.cs

+36-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@
77
using System.IO;
88
using System.Linq;
99
using System.Reflection;
10+
using System.Runtime.InteropServices;
11+
using Microsoft.IdentityModel.Tokens;
12+
using Mono.Unix;
1013
using Newtonsoft.Json;
1114
using Newtonsoft.Json.Linq;
15+
using Snowflake.Data.Core.Tools;
1216
using Snowflake.Data.Log;
1317

1418
namespace Snowflake.Data.Configuration
@@ -17,23 +21,36 @@ internal class EasyLoggingConfigParser
1721
{
1822
private static readonly SFLogger s_logger = SFLoggerFactory.GetLogger<EasyLoggingConfigParser>();
1923

24+
private readonly UnixOperations _unixOperations = UnixOperations.Instance;
25+
2026
public static readonly EasyLoggingConfigParser Instance = new EasyLoggingConfigParser();
2127

2228
public virtual ClientConfig Parse(string filePath)
2329
{
2430
var configFile = TryToReadFile(filePath);
25-
return configFile == null ? null : TryToParseFile(configFile);
31+
return configFile.IsNullOrEmpty() ? null : TryToParseFile(configFile);
2632
}
2733

2834
private string TryToReadFile(string filePath)
2935
{
3036
if (string.IsNullOrEmpty(filePath))
3137
{
32-
return null;
38+
return String.Empty;
3339
}
40+
3441
try
3542
{
36-
return File.ReadAllText(filePath);
43+
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
44+
{
45+
using (StreamReader reader = new StreamReader(fileStream))
46+
{
47+
CheckIfValidPermissions(filePath);
48+
49+
string fileContent = reader.ReadToEnd();
50+
51+
return fileContent;
52+
}
53+
}
3754
}
3855
catch (Exception e)
3956
{
@@ -45,7 +62,8 @@ private string TryToReadFile(string filePath)
4562

4663
private ClientConfig TryToParseFile(string fileContent)
4764
{
48-
try {
65+
try
66+
{
4967
var config = JsonConvert.DeserializeObject<ClientConfig>(fileContent);
5068
Validate(config);
5169
CheckForUnknownFields(fileContent);
@@ -80,5 +98,19 @@ private void CheckForUnknownFields(string fileContent)
8098
.ToList()
8199
.ForEach(unknownKey => s_logger.Warn($"Unknown field from config: {unknownKey.Name}"));
82100
}
101+
102+
private void CheckIfValidPermissions(string filePath)
103+
{
104+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
105+
return;
106+
107+
// Check if others have permissions to modify the file and fail if so
108+
if (_unixOperations.CheckFileHasAnyOfPermissions(filePath, FileAccessPermissions.GroupWrite | FileAccessPermissions.OtherWrite))
109+
{
110+
var errorMessage = $"Error due to other users having permission to modify the config file: {filePath}";
111+
s_logger.Error(errorMessage);
112+
throw new Exception(errorMessage);
113+
}
114+
}
83115
}
84116
}

0 commit comments

Comments
 (0)