Skip to content

Commit 19040ff

Browse files
committed
fix: handle of PE sections with duplicate names
Required for multi-profile UKIs. Signed-off-by: Andrey Smirnov <[email protected]>
1 parent 83489d3 commit 19040ff

File tree

2 files changed

+76
-23
lines changed

2 files changed

+76
-23
lines changed

Diff for: internal/pkg/uki/internal/pe/native.go

+30-22
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"fmt"
1212
"io"
1313
"os"
14-
"slices"
1514
"time"
1615

1716
"github.com/siderolabs/gen/xslices"
@@ -112,7 +111,16 @@ func AssembleNative(srcPath, dstPath string, sections []Section) error {
112111
newHeader.MinorLinkerVersion = 0
113112
newHeader.CheckSum = 0
114113

115-
newSections := slices.Clone(peFile.Sections)
114+
type peSectionWithPath struct {
115+
pe.Section
116+
SourcePath string
117+
}
118+
119+
newSections := xslices.Map(peFile.Sections, func(section *pe.Section) *peSectionWithPath {
120+
return &peSectionWithPath{
121+
Section: *section,
122+
}
123+
})
116124

117125
// calculate sections size and VMA
118126
for i := range sections {
@@ -133,14 +141,17 @@ func AssembleNative(srcPath, dstPath string, sections []Section) error {
133141

134142
newFileHeader.NumberOfSections++
135143

136-
newSections = append(newSections, &pe.Section{
137-
SectionHeader: pe.SectionHeader{
138-
Name: sections[i].Name,
139-
VirtualSize: uint32(sections[i].virtualSize),
140-
VirtualAddress: uint32(sections[i].virtualAddress),
141-
Size: uint32((sections[i].virtualSize + fileAlignment) &^ fileAlignment),
142-
Characteristics: pe.IMAGE_SCN_CNT_INITIALIZED_DATA | pe.IMAGE_SCN_MEM_READ,
144+
newSections = append(newSections, &peSectionWithPath{
145+
Section: pe.Section{
146+
SectionHeader: pe.SectionHeader{
147+
Name: sections[i].Name,
148+
VirtualSize: uint32(sections[i].virtualSize),
149+
VirtualAddress: uint32(sections[i].virtualAddress),
150+
Size: uint32((sections[i].virtualSize + fileAlignment) &^ fileAlignment),
151+
Characteristics: pe.IMAGE_SCN_CNT_INITIALIZED_DATA | pe.IMAGE_SCN_MEM_READ,
152+
},
143153
},
154+
SourcePath: sections[i].Path,
144155
})
145156
}
146157

@@ -174,7 +185,7 @@ func AssembleNative(srcPath, dstPath string, sections []Section) error {
174185
}
175186

176187
// 3. Section headers
177-
rawSections := xslices.Map(newSections, func(section *pe.Section) pe.SectionHeader32 {
188+
rawSections := xslices.Map(newSections, func(section *peSectionWithPath) pe.SectionHeader32 {
178189
var rawName [8]byte
179190

180191
copy(rawName[:], section.Name)
@@ -206,22 +217,19 @@ func AssembleNative(srcPath, dstPath string, sections []Section) error {
206217
// 4. Section data
207218
for i, rawSection := range rawSections {
208219
name := newSections[i].Name
220+
sourcePath := newSections[i].SourcePath
209221

210-
if err := func(rawSection pe.SectionHeader32, name string) error {
222+
if err := func(rawSection pe.SectionHeader32, name, sourcePath string) error {
211223
// the section might come either from the input PE file or from a separate file
212224
var sectionData io.ReadCloser
213225

214-
for _, section := range sections {
215-
if section.Append && section.Name == name {
216-
sectionData, err = os.Open(section.Path)
217-
if err != nil {
218-
return fmt.Errorf("failed to open section data: %w", err)
219-
}
220-
221-
defer sectionData.Close() //nolint: errcheck
222-
223-
break
226+
if sourcePath != "" {
227+
sectionData, err = os.Open(sourcePath)
228+
if err != nil {
229+
return fmt.Errorf("failed to open section data: %w", err)
224230
}
231+
232+
defer sectionData.Close() //nolint: errcheck
225233
}
226234

227235
if sectionData == nil {
@@ -260,7 +268,7 @@ func AssembleNative(srcPath, dstPath string, sections []Section) error {
260268
}
261269

262270
return nil
263-
}(rawSection, name); err != nil {
271+
}(rawSection, name, sourcePath); err != nil {
264272
return fmt.Errorf("failed to write section data %s: %w", name, err)
265273
}
266274
}

Diff for: internal/pkg/uki/internal/pe/pe_test.go

+46-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import (
1818
"github.com/siderolabs/talos/internal/pkg/uki/internal/pe"
1919
)
2020

21-
func TestAssembleNative(t *testing.T) {
21+
func assertToolsPresent(t *testing.T) {
22+
t.Helper()
23+
2224
for _, tool := range []string{
2325
"objcopy",
2426
"objdump",
@@ -29,6 +31,10 @@ func TestAssembleNative(t *testing.T) {
2931
t.Skipf("missing tool: %s", tool)
3032
}
3133
}
34+
}
35+
36+
func TestAssembleNative(t *testing.T) {
37+
assertToolsPresent(t)
3238

3339
t.Setenv("SOURCE_DATE_EPOCH", "1609459200")
3440

@@ -132,3 +138,42 @@ func extractSection(t *testing.T, path, section string) string {
132138

133139
return string(output)
134140
}
141+
142+
func TestMultipleSections(t *testing.T) {
143+
assertToolsPresent(t)
144+
145+
tmpDir := t.TempDir()
146+
147+
unamePath := filepath.Join(tmpDir, "uname")
148+
require.NoError(t, os.WriteFile(unamePath, []byte("Talos-helloworld"), 0o644))
149+
150+
unameNewPath := filepath.Join(tmpDir, "uname-new")
151+
require.NoError(t, os.WriteFile(unameNewPath, []byte("Talos-foobar"), 0o644))
152+
153+
outNative := filepath.Join(tmpDir, "uki-native.bin")
154+
155+
sections := func() []pe.Section {
156+
return []pe.Section{
157+
{
158+
Name: ".text",
159+
},
160+
{
161+
Name: ".uname",
162+
Append: true,
163+
Path: unamePath,
164+
},
165+
{
166+
Name: ".uname",
167+
Append: true,
168+
Path: unameNewPath,
169+
},
170+
}
171+
}
172+
173+
require.NoError(t, pe.AssembleNative("testdata/sd-stub-amd64.efi", outNative, sections()))
174+
175+
sectionContents := extractSection(t, outNative, ".uname")
176+
177+
assert.Contains(t, sectionContents, "Talos-helloworld")
178+
assert.Contains(t, sectionContents, "Talos-foobar")
179+
}

0 commit comments

Comments
 (0)