Skip to content

Commit

Permalink
Merge pull request chocolatey#1506 from gep13/issue-1505
Browse files Browse the repository at this point in the history
(chocolateyGH-1505) Ensure package information from registry is escaped
  • Loading branch information
ferventcoder authored Feb 26, 2018
2 parents 0a86d5e + 143fbd3 commit 5ddcb20
Show file tree
Hide file tree
Showing 5 changed files with 161 additions and 112 deletions.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Copyright © 2017 - 2018 Chocolatey Software, Inc
// Copyright © 2011 - 2017 RealDimensions Software, LLC
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//
//
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -24,7 +24,11 @@ public static string get_value_as_string(this RegistryKey key, string name)
{
if (key == null) return string.Empty;

return key.GetValue(name).to_string().Replace("\0", string.Empty);
// Since it is possible that registry keys contain characters that are not valid
// in XML files, ensure that all content is escaped, prior to serialization
var escapedXml = System.Security.SecurityElement.Escape(key.GetValue(name).to_string());

return escapedXml == null ? string.Empty : escapedXml.Replace("\0", string.Empty);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Copyright © 2017 - 2018 Chocolatey Software, Inc
// Copyright © 2011 - 2017 RealDimensions Software, LLC
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//
//
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -16,6 +16,7 @@

namespace chocolatey.infrastructure.app.services
{
using System;
using System.IO;
using System.Text;
using NuGet;
Expand All @@ -29,6 +30,7 @@ public class ChocolateyPackageInformationService : IChocolateyPackageInformation
private readonly IRegistryService _registryService;
private readonly IFilesService _filesService;
private const string REGISTRY_SNAPSHOT_FILE = ".registry";
private const string REGISTRY_SNAPSHOT_BAD_FILE = ".registry.bad";
private const string FILES_SNAPSHOT_FILE = ".files";
private const string SILENT_UNINSTALLER_FILE = ".silentUninstaller";
private const string SIDE_BY_SIDE_FILE = ".sxs";
Expand Down Expand Up @@ -59,28 +61,56 @@ public ChocolateyPackageInformation get_package_information(IPackage package)
return packageInformation;
}

FaultTolerance.try_catch_with_logging_exception(
() =>
var deserializationErrorMessage = @"
A corrupt .registry file exists at {0}.
Open this file in a text editor, and remove/escape any characters that
are regarded as illegal within XML contents. These are typically the
characters <, >, "", ', and &. Once these have been corrected, rename
the .registry.bad file to .registry. Once saved, try running the same
Chocolatey command that was just executed, so verify problem is fixed.
NOTE: It will not be possible to rename the file in Windows Explorer.
Instead, you can use the following PowerShell command:
Move-Item .\.registry.bad .\.registry
".format_with(_fileSystem.combine_paths(pkgStorePath, REGISTRY_SNAPSHOT_BAD_FILE));
try
{
if (_fileSystem.file_exists(_fileSystem.combine_paths(pkgStorePath, REGISTRY_SNAPSHOT_BAD_FILE)))
{
this.Log().Warn(deserializationErrorMessage);
}
else
{
packageInformation.RegistrySnapshot = _registryService.read_from_file(_fileSystem.combine_paths(pkgStorePath, REGISTRY_SNAPSHOT_FILE));
}
}
catch (Exception)
{
FaultTolerance.try_catch_with_logging_exception(
() =>
{
packageInformation.RegistrySnapshot = _registryService.read_from_file(_fileSystem.combine_paths(pkgStorePath, REGISTRY_SNAPSHOT_FILE));
},
"Unable to read registry snapshot file for {0} (located at {1})".format_with(package.Id, _fileSystem.combine_paths(pkgStorePath, REGISTRY_SNAPSHOT_FILE)),
this.Log().Warn(deserializationErrorMessage);

// rename the bad registry file so that it isn't processed again
_fileSystem.move_file(_fileSystem.combine_paths(pkgStorePath, REGISTRY_SNAPSHOT_FILE), _fileSystem.combine_paths(pkgStorePath, REGISTRY_SNAPSHOT_BAD_FILE));
},
"Unable to read registry snapshot file for {0} (located at {1})".format_with(package.Id, _fileSystem.combine_paths(pkgStorePath, REGISTRY_SNAPSHOT_FILE)),
throwError: false,
logWarningInsteadOfError: true,
isSilent: true
);

);
}

FaultTolerance.try_catch_with_logging_exception(
() =>
{
packageInformation.FilesSnapshot = _filesService.read_from_file(_fileSystem.combine_paths(pkgStorePath, FILES_SNAPSHOT_FILE));
},
"Unable to read files snapshot file",
throwError: false,
logWarningInsteadOfError: true,
packageInformation.FilesSnapshot = _filesService.read_from_file(_fileSystem.combine_paths(pkgStorePath, FILES_SNAPSHOT_FILE));
},
"Unable to read files snapshot file",
throwError: false,
logWarningInsteadOfError: true,
isSilent:true
);

packageInformation.HasSilentUninstall = _fileSystem.file_exists(_fileSystem.combine_paths(pkgStorePath, SILENT_UNINSTALLER_FILE));
packageInformation.IsSideBySide = _fileSystem.file_exists(_fileSystem.combine_paths(pkgStorePath, SIDE_BY_SIDE_FILE));
packageInformation.IsPinned = _fileSystem.file_exists(_fileSystem.combine_paths(pkgStorePath, PIN_FILE));
Expand All @@ -97,9 +127,9 @@ public ChocolateyPackageInformation get_package_information(IPackage package)
() =>
{
packageInformation.VersionOverride = new SemanticVersion(_fileSystem.read_file(versionOverrideFile).trim_safe());
},
"Unable to read version override file",
throwError: false,
},
"Unable to read version override file",
throwError: false,
logWarningInsteadOfError: true
);
}
Expand Down Expand Up @@ -148,8 +178,8 @@ public void save_package_information(ChocolateyPackageInformation packageInforma
else
{
_fileSystem.delete_file(_fileSystem.combine_paths(pkgStorePath, ARGS_FILE));
}
}

if (!string.IsNullOrWhiteSpace(packageInformation.ExtraInformation))
{
var extraFile = _fileSystem.combine_paths(pkgStorePath, EXTRA_FILE);
Expand All @@ -160,7 +190,7 @@ public void save_package_information(ChocolateyPackageInformation packageInforma
{
_fileSystem.delete_file(_fileSystem.combine_paths(pkgStorePath, EXTRA_FILE));
}

if (packageInformation.VersionOverride != null)
{
var versionOverrideFile = _fileSystem.combine_paths(pkgStorePath, VERSION_OVERRIDE_FILE);
Expand Down Expand Up @@ -192,7 +222,7 @@ public void save_package_information(ChocolateyPackageInformation packageInforma
else
{
_fileSystem.delete_file(_fileSystem.combine_paths(pkgStorePath, PIN_FILE));
}
}
}

public void remove_package_information(IPackage package)
Expand Down
14 changes: 7 additions & 7 deletions src/chocolatey/infrastructure.app/services/RegistryService.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Copyright © 2017 - 2018 Chocolatey Software, Inc
// Copyright © 2011 - 2017 RealDimensions Software, LLC
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//
//
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down Expand Up @@ -253,7 +253,7 @@ public void evaluate_keys(RegistryKey key, Registry snapshot)
private void get_msi_information(RegistryApplicationKey appKey, RegistryKey key)
{
_componentLoopCount = 0;

var userDataProductKeyId = get_msi_user_data_key(key.Name);
if (string.IsNullOrWhiteSpace(userDataProductKeyId)) return;

Expand Down Expand Up @@ -398,7 +398,7 @@ public Registry read_from_file(string filePath)
return null;
}

return _xmlService.deserialize<Registry>(filePath);
return _xmlService.deserialize<Registry>(filePath, 1);
}

private void get_values(RegistryKey key, string subKeyName, IList<GenericRegistryValue> values, bool expandValues)
Expand Down Expand Up @@ -530,4 +530,4 @@ public static GenericRegistryValue get_value(RegistryHiveType hive, string subKe
}
}

}
}
17 changes: 13 additions & 4 deletions src/chocolatey/infrastructure/services/IXmlService.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Copyright © 2017 - 2018 Chocolatey Software, Inc
// Copyright © 2011 - 2017 RealDimensions Software, LLC
//
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
//
//
// You may obtain a copy of the License at
//
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -26,6 +26,15 @@ public interface IXmlService
/// <returns></returns>
XmlType deserialize<XmlType>(string xmlFilePath);

/// <summary>
/// Deserializes the specified XML file path.
/// </summary>
/// <typeparam name="XmlType">The type of the ml type.</typeparam>
/// <param name="xmlFilePath">The XML file path.</param>
/// <param name="retryCount">The number of times to attempt deserialization on event of a failure.</param>
/// <returns></returns>
XmlType deserialize<XmlType>(string xmlFilePath, int retryCount);

/// <summary>
/// Serializes the specified XML type.
/// </summary>
Expand Down
Loading

0 comments on commit 5ddcb20

Please sign in to comment.