Skip to content

Commit 6a9d2c5

Browse files
Harden YAML document prefixes
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent afa5bc9 commit 6a9d2c5

12 files changed

Lines changed: 162 additions & 28 deletions

src/functions/private/Get-YamlContentWithoutComment.ps1

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@ function Get-YamlContentWithoutComment {
88
param (
99
[Parameter(Mandatory)]
1010
[AllowEmptyString()]
11-
[string] $Text
11+
[string] $Text,
12+
13+
[Parameter(Mandatory)]
14+
[pscustomobject] $Mark
1215
)
1316

1417
$comment = Find-YamlCommentStart -Text $Text
1518
if ($comment -ge 0) {
19+
$commentMark = New-YamlMark -Index ($Mark.Index + $comment) -Line $Mark.Line `
20+
-Column ($Mark.Column + $comment)
21+
Assert-YamlNoByteOrderMark -Text $Text.Substring($comment) -Mark $commentMark
1622
return $Text.Substring(0, $comment).TrimEnd(' ', "`t")
1723
}
1824
return $Text.TrimEnd(' ', "`t")

src/functions/private/Read-YamlBlockMapping.ps1

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,15 @@ function Read-YamlBlockMapping {
5353
(Test-YamlDocumentByteOrderMark -Context $Context -RequireDocumentStart)) {
5454
break
5555
}
56-
if ($trimmed.Length -eq 0 -or $trimmed.StartsWith('#', [System.StringComparison]::Ordinal)) {
56+
if ($trimmed.StartsWith('#', [System.StringComparison]::Ordinal)) {
57+
$column = $line.Length - $trimmed.Length
58+
$mark = New-YamlMark -Index ($Context.LineStarts[$lineNumber] + $column) `
59+
-Line $lineNumber -Column $column
60+
Assert-YamlNoByteOrderMark -Text $trimmed -Mark $mark
61+
$Context.LineIndex++
62+
continue
63+
}
64+
if ($trimmed.Length -eq 0) {
5765
$Context.LineIndex++
5866
continue
5967
}
@@ -94,7 +102,11 @@ function Read-YamlBlockMapping {
94102
'A tab cannot separate a mapping indicator from a compact block collection.'
95103
))
96104
}
97-
if ([string]::IsNullOrEmpty((Get-YamlContentWithoutComment -Text $keyText))) {
105+
$keyMark = New-YamlMark -Index ($Context.LineStarts[$lineNumber] + $keyColumn) `
106+
-Line $lineNumber -Column $keyColumn
107+
if ([string]::IsNullOrEmpty((
108+
Get-YamlContentWithoutComment -Text $keyText -Mark $keyMark
109+
))) {
98110
$Context.LineIndex++
99111
Skip-YamlBlockTrivia -Context $Context
100112
if ($Context.LineIndex -ge $Context.Lines.Count) {
@@ -165,7 +177,12 @@ function Read-YamlBlockMapping {
165177
'A tab cannot separate a mapping indicator from a compact block collection.'
166178
))
167179
}
168-
if ([string]::IsNullOrEmpty((Get-YamlContentWithoutComment -Text $valueText))) {
180+
$valueMark = New-YamlMark -Index (
181+
$Context.LineStarts[$Context.LineIndex] + $valueColumn
182+
) -Line $Context.LineIndex -Column $valueColumn
183+
if ([string]::IsNullOrEmpty((
184+
Get-YamlContentWithoutComment -Text $valueText -Mark $valueMark
185+
))) {
169186
$valueLineNumber = $Context.LineIndex
170187
$Context.LineIndex++
171188
Skip-YamlBlockTrivia -Context $Context
@@ -234,7 +251,11 @@ function Read-YamlBlockMapping {
234251
$leading = $valueSource.Length - $valueSource.TrimStart(' ', "`t").Length
235252
$valueText = $valueSource.TrimStart(' ', "`t")
236253
$valueColumn = $contentColumn + $valueStart + $leading
237-
if ([string]::IsNullOrEmpty((Get-YamlContentWithoutComment -Text $valueText))) {
254+
$valueMark = New-YamlMark -Index ($Context.LineStarts[$lineNumber] + $valueColumn) `
255+
-Line $lineNumber -Column $valueColumn
256+
if ([string]::IsNullOrEmpty((
257+
Get-YamlContentWithoutComment -Text $valueText -Mark $valueMark
258+
))) {
238259
$Context.LineIndex = $lineNumber + 1
239260
Skip-YamlBlockTrivia -Context $Context
240261
if ($Context.LineIndex -lt $Context.Lines.Count) {

src/functions/private/Read-YamlBlockNode.ps1

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,10 @@ function Read-YamlBlockNode {
113113
$unknownTag = $properties.HasUnknownTag -or $PendingUnknownTag
114114
$anchor = if (-not [string]::IsNullOrEmpty($properties.Anchor)) { $properties.Anchor } else { $PendingAnchor }
115115
$restSource = $properties.Rest
116-
$rest = Get-YamlContentWithoutComment -Text $restSource
117116
$contentColumn = $SegmentColumn + $properties.Consumed
117+
$restMark = New-YamlMark -Index ($Context.LineStarts[$lineNumber] + $contentColumn) `
118+
-Line $lineNumber -Column $contentColumn
119+
$rest = Get-YamlContentWithoutComment -Text $restSource -Mark $restMark
118120

119121
if ([string]::IsNullOrEmpty($rest)) {
120122
$Context.LineIndex++

src/functions/private/Read-YamlBlockScalar.ps1

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ function Read-YamlBlockScalar {
3131
[string] $Anchor = ''
3232
)
3333

34+
$headerMark = New-YamlMark -Index (
35+
$Context.LineStarts[$Context.LineIndex] + $HeaderColumn
36+
) -Line $Context.LineIndex -Column $HeaderColumn
37+
Assert-YamlNoByteOrderMark -Text $Header -Mark $headerMark
3438
if ($Header -notmatch (
3539
'^([|>])(?:(?:([1-9])([+-])?)|(?:([+-])([1-9])?))?' +
3640
'(?:[ \t]+#.*|[ \t]*)$'

src/functions/private/Read-YamlBlockSequence.ps1

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,15 @@ function Read-YamlBlockSequence {
5151
(Test-YamlDocumentByteOrderMark -Context $Context -RequireDocumentStart)) {
5252
break
5353
}
54-
if ($trimmed.Length -eq 0 -or $trimmed.StartsWith('#', [System.StringComparison]::Ordinal)) {
54+
if ($trimmed.StartsWith('#', [System.StringComparison]::Ordinal)) {
55+
$column = $line.Length - $trimmed.Length
56+
$mark = New-YamlMark -Index ($Context.LineStarts[$Context.LineIndex] + $column) `
57+
-Line $Context.LineIndex -Column $column
58+
Assert-YamlNoByteOrderMark -Text $trimmed -Mark $mark
59+
$Context.LineIndex++
60+
continue
61+
}
62+
if ($trimmed.Length -eq 0) {
5563
$Context.LineIndex++
5664
continue
5765
}
@@ -70,7 +78,12 @@ function Read-YamlBlockSequence {
7078
)
7179
}
7280

73-
if ([string]::IsNullOrEmpty((Get-YamlContentWithoutComment -Text $rest))) {
81+
$restMark = New-YamlMark -Index (
82+
$Context.LineStarts[$Context.LineIndex] + $itemColumn
83+
) -Line $Context.LineIndex -Column $itemColumn
84+
if ([string]::IsNullOrEmpty((
85+
Get-YamlContentWithoutComment -Text $rest -Mark $restMark
86+
))) {
7487
$line = $Context.LineIndex
7588
$Context.LineIndex++
7689
Skip-YamlBlockTrivia -Context $Context

src/functions/private/Read-YamlPlainScalar.ps1

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ function Read-YamlPlainScalar {
3636
-Column $FirstColumn
3737
$parts = [System.Collections.Generic.List[object]]::new()
3838
$firstComment = Find-YamlCommentStart -Text $FirstText
39-
$firstValue = (Get-YamlContentWithoutComment -Text $FirstText).Trim(' ', "`t")
39+
$firstValue = Get-YamlContentWithoutComment -Text $FirstText -Mark $start
40+
$firstValue = $firstValue.Trim(' ', "`t")
4041
Assert-YamlNoByteOrderMark -Text $firstValue -Mark $start
4142
$firstCharacter = if ($firstValue.Length -gt 0) { $firstValue[0] } else { [char] 0 }
4243
$forbiddenFirst = $firstCharacter -in @(
@@ -88,7 +89,9 @@ function Read-YamlPlainScalar {
8889
}
8990
$sourceContent = $line.Substring($indent)
9091
$comment = Find-YamlCommentStart -Text $sourceContent
91-
$content = Get-YamlContentWithoutComment -Text $sourceContent
92+
$contentMark = New-YamlMark -Index ($Context.LineStarts[$Context.LineIndex] + $indent) `
93+
-Line $Context.LineIndex -Column $indent
94+
$content = Get-YamlContentWithoutComment -Text $sourceContent -Mark $contentMark
9295
if ((Find-YamlMappingColon -Text $content) -ge 0) {
9396
break
9497
}

src/functions/private/Read-YamlStreamCore.ps1

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -51,16 +51,16 @@ function Read-YamlStreamCore {
5151
$implicitDocumentSeen = $false
5252

5353
while ($context.LineIndex -lt $lines.Count) {
54-
Read-YamlDocumentByteOrderMark -Context $context
55-
Skip-YamlBlockTrivia -Context $context
54+
Skip-YamlDocumentPrefix -Context $context
5655
if ($context.LineIndex -ge $lines.Count) {
5756
break
5857
}
5958
if ($lines[$context.LineIndex] -match '^\.\.\.(?:[ \t]|$)') {
60-
$suffix = Get-YamlContentWithoutComment -Text $lines[$context.LineIndex].Substring(3)
59+
$mark = New-YamlMark -Index ($lineStarts[$context.LineIndex] + 3) `
60+
-Line $context.LineIndex -Column 3
61+
$suffix = Get-YamlContentWithoutComment `
62+
-Text $lines[$context.LineIndex].Substring(3) -Mark $mark
6163
if ($suffix.Trim(' ', "`t").Length -gt 0) {
62-
$mark = New-YamlMark -Index ($lineStarts[$context.LineIndex] + 3) `
63-
-Line $context.LineIndex -Column 3
6464
throw (New-YamlException -Start $mark -End $mark -ErrorId 'YamlInvalidDocumentEnd' -Message (
6565
'Unexpected content follows the document end marker.'
6666
))
@@ -109,7 +109,12 @@ function Read-YamlStreamCore {
109109
$leading = $afterMarker.Length - $afterMarker.TrimStart(' ', "`t").Length
110110
$segment = $afterMarker.TrimStart(' ', "`t")
111111
$segmentColumn = 3 + $leading
112-
if ([string]::IsNullOrEmpty((Get-YamlContentWithoutComment -Text $segment))) {
112+
$segmentMark = New-YamlMark -Index (
113+
$lineStarts[$context.LineIndex] + $segmentColumn
114+
) -Line $context.LineIndex -Column $segmentColumn
115+
if ([string]::IsNullOrEmpty((
116+
Get-YamlContentWithoutComment -Text $segment -Mark $segmentMark
117+
))) {
113118
$markerLine = $context.LineIndex
114119
$context.LineIndex++
115120
Skip-YamlBlockTrivia -Context $context
@@ -164,24 +169,23 @@ function Read-YamlStreamCore {
164169
}
165170
$documents.Add($document)
166171

167-
Skip-YamlBlockTrivia -Context $context
168-
Read-YamlDocumentByteOrderMark -Context $context -RequireDocumentStart
169-
Skip-YamlBlockTrivia -Context $context
172+
Skip-YamlDocumentPrefix -Context $context -RequireDocumentStart
170173
$explicitEnd = $false
171174
if ($context.LineIndex -lt $lines.Count -and
172175
$lines[$context.LineIndex] -match '^\.\.\.(?:[ \t]|$)') {
173176
$explicitEnd = $true
174177
$endLine = $lines[$context.LineIndex]
175-
if ((Get-YamlContentWithoutComment -Text $endLine.Substring(3)).
178+
$endMark = New-YamlMark -Index ($lineStarts[$context.LineIndex] + 3) `
179+
-Line $context.LineIndex -Column 3
180+
if ((Get-YamlContentWithoutComment -Text $endLine.Substring(3) -Mark $endMark).
176181
Trim(' ', "`t").Length -gt 0) {
177-
$mark = New-YamlMark -Index ($lineStarts[$context.LineIndex] + 3) `
178-
-Line $context.LineIndex -Column 3
179-
throw (New-YamlException -Start $mark -End $mark -ErrorId 'YamlInvalidDocumentEnd' -Message (
182+
throw (New-YamlException -Start $endMark -End $endMark `
183+
-ErrorId 'YamlInvalidDocumentEnd' -Message (
180184
'Unexpected content follows the document end marker.'
181185
))
182186
}
183187
$context.LineIndex++
184-
Skip-YamlBlockTrivia -Context $context
188+
Skip-YamlDocumentPrefix -Context $context
185189
$implicitDocumentSeen = $false
186190
}
187191
if (-not $explicitEnd -and $context.LineIndex -lt $lines.Count -and

src/functions/private/Skip-YamlBlockTrivia.ps1

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@ function Skip-YamlBlockTrivia {
1616
while ($Context.LineIndex -lt $Context.Lines.Count) {
1717
$line = $Context.Lines[$Context.LineIndex]
1818
$trimmed = $line.TrimStart(' ', "`t")
19-
if ($trimmed.Length -eq 0 -or $trimmed.StartsWith('#', [System.StringComparison]::Ordinal)) {
19+
if ($trimmed.StartsWith('#', [System.StringComparison]::Ordinal)) {
20+
$column = $line.Length - $trimmed.Length
21+
$mark = New-YamlMark -Index ($Context.LineStarts[$Context.LineIndex] + $column) `
22+
-Line $Context.LineIndex -Column $column
23+
Assert-YamlNoByteOrderMark -Text $trimmed -Mark $mark
24+
$Context.LineIndex++
25+
continue
26+
}
27+
if ($trimmed.Length -eq 0) {
2028
$Context.LineIndex++
2129
continue
2230
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function Skip-YamlDocumentPrefix {
2+
<#
3+
.SYNOPSIS
4+
Advances across repeated YAML document prefixes.
5+
#>
6+
[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
7+
'PSUseShouldProcessForStateChangingFunctions', '',
8+
Justification = 'Advances an in-memory parser context.'
9+
)]
10+
[CmdletBinding()]
11+
param (
12+
[Parameter(Mandatory)]
13+
[pscustomobject] $Context,
14+
15+
[switch] $RequireDocumentStart
16+
)
17+
18+
do {
19+
$lineIndex = $Context.LineIndex
20+
$textLength = $Context.Text.Length
21+
Read-YamlDocumentByteOrderMark -Context $Context `
22+
-RequireDocumentStart:$RequireDocumentStart
23+
Skip-YamlBlockTrivia -Context $Context
24+
} while (
25+
$Context.LineIndex -ne $lineIndex -or
26+
$Context.Text.Length -ne $textLength
27+
)
28+
}

src/functions/private/Skip-YamlFlowTrivia.ps1

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,24 @@ function Skip-YamlFlowTrivia {
2323
continue
2424
}
2525
if ($character -eq '#') {
26+
$mark = New-YamlMark -Index $Cursor.Index -Line $Cursor.Line -Column $Cursor.Column
2627
if ($Cursor.Index -gt 0 -and
2728
$Context.Text[$Cursor.Index - 1] -notin @(' ', "`t", "`n")) {
28-
$mark = New-YamlMark -Index $Cursor.Index -Line $Cursor.Line -Column $Cursor.Column
2929
throw (New-YamlException -Start $mark -End $mark -ErrorId 'YamlInvalidComment' -Message (
3030
'A YAML comment must be separated from preceding content.'
3131
))
3232
}
33+
$commentEnd = $Context.Text.IndexOf(
34+
"`n",
35+
$Cursor.Index,
36+
[System.StringComparison]::Ordinal
37+
)
38+
if ($commentEnd -lt 0) {
39+
$commentEnd = $Context.Text.Length
40+
}
41+
Assert-YamlNoByteOrderMark `
42+
-Text $Context.Text.Substring($Cursor.Index, $commentEnd - $Cursor.Index) `
43+
-Mark $mark
3344
while ($Cursor.Index -lt $Context.Text.Length -and $Context.Text[$Cursor.Index] -ne "`n") {
3445
Move-YamlCursor -Cursor $Cursor -Context $Context
3546
}
@@ -56,6 +67,18 @@ function Skip-YamlFlowTrivia {
5667
return
5768
}
5869
if ($Context.Text[$Cursor.Index] -eq '#') {
70+
$mark = New-YamlMark -Index $Cursor.Index -Line $Cursor.Line -Column $Cursor.Column
71+
$commentEnd = $Context.Text.IndexOf(
72+
"`n",
73+
$Cursor.Index,
74+
[System.StringComparison]::Ordinal
75+
)
76+
if ($commentEnd -lt 0) {
77+
$commentEnd = $Context.Text.Length
78+
}
79+
Assert-YamlNoByteOrderMark `
80+
-Text $Context.Text.Substring($Cursor.Index, $commentEnd - $Cursor.Index) `
81+
-Mark $mark
5982
while ($Cursor.Index -lt $Context.Text.Length -and $Context.Text[$Cursor.Index] -ne "`n") {
6083
Move-YamlCursor -Cursor $Cursor -Context $Context
6184
}

0 commit comments

Comments
 (0)