From 49bd2636ba5951553eb0944399c0f6206e03effe Mon Sep 17 00:00:00 2001 From: Jonathan Klabunde Tomer Date: Mon, 26 Aug 2024 12:10:37 -0700 Subject: [PATCH] CodeSign: pad LINKEDIT to multiple of page size when reading When we are creating a new CodeSignature, we align its offset up to a multiple of the page size; we then read the existing LINKEDIT section (and the entire beginning of the file, for signing) based on the location of that code signature. If the existing LINKEDIT section's end was not page-aligned, we get an EOF when attempting to read up to the page-aligned flie size, causing signing to fail. This change limits our read to the actual size of the file (or LINKEDIT section, at least), while keeping the buffer we read into the correct size (and therefore implicitly padding it with zeroes, which will get written out when we rewrite the LINKEDIT section and new signature). --- export.go | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/export.go b/export.go index 04cddbb..d0a4b13 100644 --- a/export.go +++ b/export.go @@ -324,10 +324,15 @@ func (f *File) CodeSign(config *codesign.Config) error { config.CodeSize = uint64(cs.Offset) - // cache __LINKEDIT data (up to but not including any existing code signature) for saving later + // cache __LINKEDIT data (up to but not including any existing code signature) for saving later. + // if the actual data doesn't go up to a page boundary (because we're adding a new signature), pad it with zeroes ledata := make([]byte, uint64(cs.Offset)-linkedit.Offset) - if _, err := f.cr.ReadAtAddr(ledata, linkedit.Addr); err != nil { - return fmt.Errorf("failed to read __LINKEDIT data: %v", err) + size := uint64(len(ledata)) + if size > linkedit.Filesz { + size = linkedit.Filesz + } + if n, err := f.cr.ReadAtAddr(ledata[:size], linkedit.Addr); err != nil { + return fmt.Errorf("failed to read __LINKEDIT data: %d, %v", n, err) } f.ledata = bytes.NewBuffer(ledata) @@ -337,9 +342,9 @@ func (f *File) CodeSign(config *codesign.Config) error { // update LC_CODE_SIGNATURE size cs.Size = uint32((linkedit.Offset + linkedit.Filesz) - uint64(cs.Offset)) - // read data to be signed + // read data to be signed; pad to beginning of code signature if necessary (in case we added a signature to a not-page-aligned-size file) data := make([]byte, cs.Offset) - if _, err := f.ReadAt(data, 0); err != nil { + if _, err := f.ReadAt(data[:linkedit.Offset+size], 0); err != nil { return fmt.Errorf("failed to read codesign data: %v", err) } // write modified file header and load commands (including __LINKEDIT and CodeSignature), since they are covered by hashes