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

Add UntrustedLocation check #11286

Merged
merged 3 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from 2 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
10 changes: 10 additions & 0 deletions documentation/specs/BuildCheck/Codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Report codes are chosen to conform to suggested guidelines. Those guidelines are
| [BC0201](#bc0201---usage-of-undefined-property) | Warning | Project | 9.0.100 | Usage of undefined property. |
| [BC0202](#bc0202---property-first-declared-after-it-was-used) | Warning | Project | 9.0.100 | Property first declared after it was used. |
| [BC0203](#bc0203----property-declared-but-never-used) | None | Project | 9.0.100 | Property declared but never used. |
| [BC0301](#bc0301---building-from-downloads-folder) | None | Project | 9.0.300 | Building from Downloads folder. |
maridematte marked this conversation as resolved.
Show resolved Hide resolved


Notes:
Expand Down Expand Up @@ -176,6 +177,15 @@ Common cases of false positives:
* Property accessing is tracked for each project build request. There might be multiple distinct build requests for a project in a single build. Specific case of this is a call to the [MSBuild task](https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-task) or [CallTarget task](https://learn.microsoft.com/en-us/visualstudio/msbuild/calltarget-task) that can request a result from a project build, while passing additional or different global properties and/or calling specific target. This happens often as part of common targets - e.g. for [multi-targeted project build parallelization](../../High-level-overview.md#parallelism)
* Incremental build might skip execution of some targets, that might have been accessing properties of interest.

<a name="BC0301"></a>
## BC0301 - Building from Downloads folder.

"Downloads folder is untrusted for projects building."

Placing project files into Downloads folder (or any other folder that cannot be fully trusted including all parent folders up to a root drive) is not recomended, as unintended injection of unrelated MSBuild logic can occur.

Place your projects into trusted locations - including cases when you intend to only open the project in IDE.

<BR/>
<BR/>
<BR/>
Expand Down
96 changes: 96 additions & 0 deletions src/Build/BuildCheck/Checks/UntrustedLocationCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Build.Construction;
using Microsoft.Build.Shared;

namespace Microsoft.Build.Experimental.BuildCheck.Checks;
internal sealed class UntrustedLocationCheck : Check
YuliiaKovalova marked this conversation as resolved.
Show resolved Hide resolved
{
public static CheckRule SupportedRule = new CheckRule(
"BC0301",
"UntrustedLocation",
ResourceUtilities.GetResourceString("BuildCheck_BC0301_Title")!,
ResourceUtilities.GetResourceString("BuildCheck_BC0301_MessageFmt")!,
new CheckConfiguration() { Severity = CheckResultSeverity.Error });

public override string FriendlyName => "DotUtils.UntrustedLocationCheck";

public override IReadOnlyList<CheckRule> SupportedRules { get; } = new List<CheckRule>() { SupportedRule };

public override void Initialize(ConfigurationContext configurationContext)
{
checkedProjects.Clear();
}

internal override bool IsBuiltIn => true;

public override void RegisterActions(IBuildCheckRegistrationContext registrationContext)
{
registrationContext.RegisterEvaluatedPropertiesAction(EvaluatedPropertiesAction);
}

private HashSet<string> checkedProjects = new HashSet<string>();

private void EvaluatedPropertiesAction(BuildCheckDataContext<EvaluatedPropertiesCheckData> context)
{
if (checkedProjects.Add(context.Data.ProjectFilePath) &&
context.Data.ProjectFileDirectory.StartsWith(PathsHelper.Downloads, Shared.FileUtilities.PathComparison))
{
context.ReportResult(BuildCheckResult.Create(
SupportedRule,
ElementLocation.EmptyLocation,
context.Data.ProjectFileDirectory,
context.Data.ProjectFilePath.Substring(context.Data.ProjectFileDirectory.Length + 1)));
}
}

private static class PathsHelper
{
public static readonly string Downloads = GetDownloadsPath();

/// <summary>
/// Returns the current Downloads location. Makes sure the path doesn't end with directory separator
/// (to prevent false negatives during matching)
/// </summary>
private static string GetDownloadsPath()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Unsupported on pre-vista
if (Environment.OSVersion.Version.Major >= 6)
{
try
{
// based on doc - a final slash is not added
JanKrivanek marked this conversation as resolved.
Show resolved Hide resolved
return SHGetKnownFolderPath(new Guid("374DE290-123F-4565-9164-39C4925E467B"), 0, IntPtr.Zero);
}
catch
{
// ignored
}
}
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
JanKrivanek marked this conversation as resolved.
Show resolved Hide resolved
{
string? locationFromEnv = Environment.GetEnvironmentVariable("XDG_DOWNLOAD_DIR");
if (locationFromEnv != null && Directory.Exists(locationFromEnv))
{
return locationFromEnv.TrimEnd(['\\','/']);
}
}

return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads");
}

[DllImport("shell32",
CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
private static extern string SHGetKnownFolderPath(
[MarshalAs(UnmanagedType.LPStruct)] Guid rfid, uint dwFlags,
IntPtr hToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ internal readonly record struct BuiltInCheckFactory(
new BuiltInCheckFactory([NoEnvironmentVariablePropertyCheck.SupportedRule.Id], NoEnvironmentVariablePropertyCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct<NoEnvironmentVariablePropertyCheck>),
new BuiltInCheckFactory([EmbeddedResourceCheck.SupportedRule.Id], EmbeddedResourceCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct<EmbeddedResourceCheck>),
new BuiltInCheckFactory([TargetFrameworkConfusionCheck.SupportedRule.Id], TargetFrameworkConfusionCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct<TargetFrameworkConfusionCheck>),
new BuiltInCheckFactory([UntrustedLocationCheck.SupportedRule.Id], UntrustedLocationCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct<UntrustedLocationCheck>),
],

// BuildCheckDataSource.Execution
Expand Down
6 changes: 6 additions & 0 deletions src/Build/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -2216,6 +2216,12 @@ Utilization: {0} Average Utilization: {1:###.0}</value>
<data name="BuildCheck_BC0203_MessageFmt" xml:space="preserve">
<value>Property: '{0}' was declared/initialized, but it was never used.</value>
</data>
<data name="BuildCheck_BC0301_Title" xml:space="preserve">
<value>Downloads folder is untrusted for projects building.</value>
</data>
<data name="BuildCheck_BC0301_MessageFmt" xml:space="preserve">
<value>Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}).</value>
</data>
<data name="GlobExpansionFailed" xml:space="preserve">
<value>An exception occurred while expanding a fileSpec with globs: fileSpec: "{0}", assuming it is a file name. Exception: {1}</value>
</data>
Expand Down
10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Build/Resources/xlf/Strings.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading