Skip to content

Commit f96e65b

Browse files
committed
Avoid hang during discovery in projects with symlink loops
Specific combinations of symlinks can cause infinite recursion loops during project discovery. This is avoided by limiting the depth of symlink follows to a reasonable number.
1 parent ffd1152 commit f96e65b

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

internal/project/project.go

+18-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package project
1818

1919
import (
2020
"fmt"
21+
"os"
2122

2223
"github.com/arduino/arduino-lint/internal/configuration"
2324
"github.com/arduino/arduino-lint/internal/project/library"
@@ -87,7 +88,7 @@ func findProjects(targetPath *paths.Path) ([]Type, error) {
8788
} else {
8889
if configuration.SuperprojectTypeFilter() == projecttype.All || configuration.Recursive() {
8990
// Project discovery and/or type detection is required.
90-
foundParentProjects = findProjectsUnderPath(targetPath, configuration.SuperprojectTypeFilter(), configuration.Recursive())
91+
foundParentProjects = findProjectsUnderPath(targetPath, configuration.SuperprojectTypeFilter(), configuration.Recursive(), 0)
9192
} else {
9293
// Project was explicitly defined by user.
9394
foundParentProjects = append(foundParentProjects,
@@ -115,7 +116,7 @@ func findProjects(targetPath *paths.Path) ([]Type, error) {
115116
}
116117

117118
// findProjectsUnderPath finds projects of the given type under the given path. It returns a slice containing the definitions of all found projects.
118-
func findProjectsUnderPath(targetPath *paths.Path, projectTypeFilter projecttype.Type, recursive bool) []Type {
119+
func findProjectsUnderPath(targetPath *paths.Path, projectTypeFilter projecttype.Type, recursive bool, symlinkDepth int) []Type {
119120
var foundProjects []Type
120121

121122
isProject, foundProjectType := isProject(targetPath, projectTypeFilter)
@@ -133,12 +134,24 @@ func findProjectsUnderPath(targetPath *paths.Path, projectTypeFilter projecttype
133134
return foundProjects
134135
}
135136

136-
if recursive {
137+
if recursive && symlinkDepth < 10 {
137138
// targetPath was not a project, so search the subfolders.
138139
directoryListing, _ := targetPath.ReadDir()
139140
directoryListing.FilterDirs()
140141
for _, potentialProjectDirectory := range directoryListing {
141-
foundProjects = append(foundProjects, findProjectsUnderPath(potentialProjectDirectory, projectTypeFilter, recursive)...)
142+
// It is possible for a combination of symlinks to parent paths to cause project discovery to get stuck in
143+
// an endless loop of recursion. This is avoided by keeping count of the depth of symlinks and discontinuing
144+
// recursion when it exceeds reason.
145+
pathStat, err := os.Lstat(potentialProjectDirectory.String())
146+
if err != nil {
147+
panic(err)
148+
}
149+
depthDelta := 0
150+
if pathStat.Mode()&os.ModeSymlink != 0 {
151+
depthDelta = 1
152+
}
153+
154+
foundProjects = append(foundProjects, findProjectsUnderPath(potentialProjectDirectory, projectTypeFilter, recursive, symlinkDepth+depthDelta)...)
142155
}
143156
}
144157

@@ -184,7 +197,7 @@ func findSubprojects(superproject Type, apexSuperprojectType projecttype.Type) [
184197
directoryListing.FilterDirs()
185198

186199
for _, subprojectPath := range directoryListing {
187-
immediateSubprojects = append(immediateSubprojects, findProjectsUnderPath(subprojectPath, subProjectType, searchPathsRecursively)...)
200+
immediateSubprojects = append(immediateSubprojects, findProjectsUnderPath(subprojectPath, subProjectType, searchPathsRecursively, 0)...)
188201
}
189202
}
190203
}

0 commit comments

Comments
 (0)