diff --git a/documentation/specs/BuildCheck/Codes.md b/documentation/specs/BuildCheck/Codes.md index 9845c431061..9b355f9c89f 100644 --- a/documentation/specs/BuildCheck/Codes.md +++ b/documentation/specs/BuildCheck/Codes.md @@ -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. | Notes: @@ -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. + +## 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. +


diff --git a/src/Build/BuildCheck/Checks/UntrustedLocationCheck.cs b/src/Build/BuildCheck/Checks/UntrustedLocationCheck.cs new file mode 100644 index 00000000000..5dcf2c75ea9 --- /dev/null +++ b/src/Build/BuildCheck/Checks/UntrustedLocationCheck.cs @@ -0,0 +1,97 @@ +// 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 +{ + 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 SupportedRules { get; } = new List() { 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 checkedProjects = new HashSet(); + + private void EvaluatedPropertiesAction(BuildCheckDataContext 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(); + + /// + /// Returns the current Downloads location. Makes sure the path doesn't end with directory separator + /// (to prevent false negatives during matching) + /// + private static string GetDownloadsPath() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Unsupported on pre-vista + if (Environment.OSVersion.Version.Major >= 6) + { + try + { + // based on doc (https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetknownfolderpath) + // - a final slash is not added + return SHGetKnownFolderPath(new Guid("374DE290-123F-4565-9164-39C4925E467B"), 0, IntPtr.Zero); + } + catch + { + // ignored + } + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + 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); + } +} diff --git a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs index cc9ee125ac1..c7d6e8d4a9b 100644 --- a/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs +++ b/src/Build/BuildCheck/Infrastructure/BuildCheckManagerProvider.cs @@ -152,6 +152,7 @@ internal readonly record struct BuiltInCheckFactory( new BuiltInCheckFactory([NoEnvironmentVariablePropertyCheck.SupportedRule.Id], NoEnvironmentVariablePropertyCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), new BuiltInCheckFactory([EmbeddedResourceCheck.SupportedRule.Id], EmbeddedResourceCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), new BuiltInCheckFactory([TargetFrameworkConfusionCheck.SupportedRule.Id], TargetFrameworkConfusionCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), + new BuiltInCheckFactory([UntrustedLocationCheck.SupportedRule.Id], UntrustedLocationCheck.SupportedRule.DefaultConfiguration.IsEnabled ?? false, Construct), ], // BuildCheckDataSource.Execution diff --git a/src/Build/Resources/Strings.resx b/src/Build/Resources/Strings.resx index afa2052daca..7d0944aaae4 100644 --- a/src/Build/Resources/Strings.resx +++ b/src/Build/Resources/Strings.resx @@ -2216,6 +2216,12 @@ Utilization: {0} Average Utilization: {1:###.0} Property: '{0}' was declared/initialized, but it was never used. + + Downloads folder is untrusted for projects building. + + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + An exception occurred while expanding a fileSpec with globs: fileSpec: "{0}", assuming it is a file name. Exception: {1} diff --git a/src/Build/Resources/xlf/Strings.cs.xlf b/src/Build/Resources/xlf/Strings.cs.xlf index de10f0f34a9..5a0a67d41e6 100644 --- a/src/Build/Resources/xlf/Strings.cs.xlf +++ b/src/Build/Resources/xlf/Strings.cs.xlf @@ -241,6 +241,16 @@ Vlastnost, která se nepoužívá, by se neměla deklarovat. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. Vytvoření otázky SELHALO. Vytváření bylo předčasně ukončeno, protože se při něm narazilo na cíl nebo úlohu, které nebyly aktuální. diff --git a/src/Build/Resources/xlf/Strings.de.xlf b/src/Build/Resources/xlf/Strings.de.xlf index 7ae4ff64846..eeb010d4816 100644 --- a/src/Build/Resources/xlf/Strings.de.xlf +++ b/src/Build/Resources/xlf/Strings.de.xlf @@ -241,6 +241,16 @@ Eine Eigenschaft, die nicht verwendet wird, sollte nicht deklariert werden. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. Fehler beim Erstellen der Frage. Der Build wurde früh beendet, da ein Ziel oder eine Aufgabe gefunden wurde, die nicht aktuell war. diff --git a/src/Build/Resources/xlf/Strings.es.xlf b/src/Build/Resources/xlf/Strings.es.xlf index f94a047df5b..1d07258d83a 100644 --- a/src/Build/Resources/xlf/Strings.es.xlf +++ b/src/Build/Resources/xlf/Strings.es.xlf @@ -241,6 +241,16 @@ No se debe declarar una propiedad que no se use. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. La creación de la pregunta ha FALLADO. La creación finalizó antes de tiempo al encontrar un objetivo o tarea que no estaba actualizado. diff --git a/src/Build/Resources/xlf/Strings.fr.xlf b/src/Build/Resources/xlf/Strings.fr.xlf index 56c560c71f7..49915d05bee 100644 --- a/src/Build/Resources/xlf/Strings.fr.xlf +++ b/src/Build/Resources/xlf/Strings.fr.xlf @@ -241,6 +241,16 @@ Une propriété qui n'est pas utilisée ne doit pas être déclarée. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. ÉCHEC de la génération de la question. La génération s’est arrêtée tôt, car elle a rencontré une cible ou une tâche qui n’était pas à jour. diff --git a/src/Build/Resources/xlf/Strings.it.xlf b/src/Build/Resources/xlf/Strings.it.xlf index c70a79dbe40..eac7e974ac2 100644 --- a/src/Build/Resources/xlf/Strings.it.xlf +++ b/src/Build/Resources/xlf/Strings.it.xlf @@ -241,6 +241,16 @@ Una proprietà non utilizzata non deve essere dichiarata. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. Compilazione della domanda NON RIUSCITA. La compilazione è terminata in anticipo perché è stata rilevata una destinazione o un'attività non aggiornata. diff --git a/src/Build/Resources/xlf/Strings.ja.xlf b/src/Build/Resources/xlf/Strings.ja.xlf index 0981d946bbb..5a4afa752f5 100644 --- a/src/Build/Resources/xlf/Strings.ja.xlf +++ b/src/Build/Resources/xlf/Strings.ja.xlf @@ -241,6 +241,16 @@ 使用されていないプロパティは宣言しないでください。 + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. 質問のビルドに失敗しました。ビルドは、最新ではないターゲットまたはタスクが検出されたため、早期に終了しました。 diff --git a/src/Build/Resources/xlf/Strings.ko.xlf b/src/Build/Resources/xlf/Strings.ko.xlf index bc6bd7f0df2..11df5f300ff 100644 --- a/src/Build/Resources/xlf/Strings.ko.xlf +++ b/src/Build/Resources/xlf/Strings.ko.xlf @@ -241,6 +241,16 @@ 사용되지 않는 속성은 선언하면 안 됩니다. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. 질문 빌드에 실패했습니다. 빌드가 최신이 아닌 대상 또는 작업을 발견하여 일찍 종료되었습니다. diff --git a/src/Build/Resources/xlf/Strings.pl.xlf b/src/Build/Resources/xlf/Strings.pl.xlf index 197d5dd80b1..111b8435c22 100644 --- a/src/Build/Resources/xlf/Strings.pl.xlf +++ b/src/Build/Resources/xlf/Strings.pl.xlf @@ -241,6 +241,16 @@ Nie należy deklarować właściwości, która nie jest używana. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. NIEPOWODZENIE kompilacji pytania. Kompilacja została zakończona wcześniej, ponieważ napotkała element docelowy lub zadanie, które nie było aktualne. diff --git a/src/Build/Resources/xlf/Strings.pt-BR.xlf b/src/Build/Resources/xlf/Strings.pt-BR.xlf index 2a5e78cb408..9ca12faebcc 100644 --- a/src/Build/Resources/xlf/Strings.pt-BR.xlf +++ b/src/Build/Resources/xlf/Strings.pt-BR.xlf @@ -241,6 +241,16 @@ Uma propriedade que não é usada não deve ser declarada. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. FALHA na compilação da pergunta. A compilação foi encerrada antecipadamente ao se deparar com um alvo ou tarefa que não estava atualizado. diff --git a/src/Build/Resources/xlf/Strings.ru.xlf b/src/Build/Resources/xlf/Strings.ru.xlf index 82bb6700ee8..9e429bb5b88 100644 --- a/src/Build/Resources/xlf/Strings.ru.xlf +++ b/src/Build/Resources/xlf/Strings.ru.xlf @@ -241,6 +241,16 @@ Не следует объявлять свойство, которое не используется. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. СБОЙ сборки вопроса. Выход из сборки выполнен раньше, так как была обнаружена цель или задача без обновления. diff --git a/src/Build/Resources/xlf/Strings.tr.xlf b/src/Build/Resources/xlf/Strings.tr.xlf index a7d019b7276..eb3c8477986 100644 --- a/src/Build/Resources/xlf/Strings.tr.xlf +++ b/src/Build/Resources/xlf/Strings.tr.xlf @@ -241,6 +241,16 @@ Kullanılmamış bir özellik bildirilmemelidir. + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. Soru derleme BAŞARISIZ oldu. Güncel olmayan bir hedef veya görev ile karşılaştığından derleme işleminden erken çıkıldı. diff --git a/src/Build/Resources/xlf/Strings.zh-Hans.xlf b/src/Build/Resources/xlf/Strings.zh-Hans.xlf index 66127cb659d..cc466fc0b85 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hans.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hans.xlf @@ -241,6 +241,16 @@ 不应声明未使用的属性。 + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. 问题生成失败。生成提前退出,因为遇到不是最新的目标或任务。 diff --git a/src/Build/Resources/xlf/Strings.zh-Hant.xlf b/src/Build/Resources/xlf/Strings.zh-Hant.xlf index c10b95fe378..55a3af4f87f 100644 --- a/src/Build/Resources/xlf/Strings.zh-Hant.xlf +++ b/src/Build/Resources/xlf/Strings.zh-Hant.xlf @@ -241,6 +241,16 @@ 不應宣告未使用的屬性。 + + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + Location: '{0}' cannot be fully trusted, place your projects outside of that folder (Project: {1}). + + + + Downloads folder is untrusted for projects building. + Downloads folder is untrusted for projects building. + + Question build FAILED. The build exited early as it encountered a target or task that was not up-to-date. 問題建立失敗。建置提早結束,因為它遇到不是最新的目標或工作。