diff options
author | gVisor bot <gvisor-bot@google.com> | 2021-05-04 23:55:46 +0000 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-05-04 23:55:46 +0000 |
commit | ae3ce097bd142f8d8cf059f2ace92c164421af9c (patch) | |
tree | ca3507d14c1f2626119e92622bd6c45834398bbe /pkg | |
parent | 3207672c9e2b3f3603f76e7aa801f63cb30a8fe0 (diff) | |
parent | 689b369f5788c15f9b018246baa4e318082c0d79 (diff) |
Merge release-20210419.0-64-g689b369f5 (automated)
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/abi/linux/elf.go | 50 | ||||
-rw-r--r-- | pkg/abi/linux/epoll.go | 6 | ||||
-rw-r--r-- | pkg/abi/linux/file.go | 5 | ||||
-rw-r--r-- | pkg/abi/linux/linux_abi_autogen_unsafe.go | 391 | ||||
-rw-r--r-- | pkg/abi/linux/netdevice.go | 4 | ||||
-rw-r--r-- | pkg/binary/binary.go | 266 | ||||
-rw-r--r-- | pkg/binary/binary_state_autogen.go | 3 | ||||
-rw-r--r-- | pkg/compressio/compressio.go | 41 | ||||
-rw-r--r-- | pkg/sentry/loader/elf.go | 14 | ||||
-rw-r--r-- | pkg/sentry/loader/loader_abi_autogen_unsafe.go | 13 | ||||
-rw-r--r-- | pkg/state/statefile/statefile.go | 21 |
11 files changed, 512 insertions, 302 deletions
diff --git a/pkg/abi/linux/elf.go b/pkg/abi/linux/elf.go index 7c9a02f20..c5713541f 100644 --- a/pkg/abi/linux/elf.go +++ b/pkg/abi/linux/elf.go @@ -106,3 +106,53 @@ const ( // NT_ARM_TLS is for ARM TLS register. NT_ARM_TLS = 0x401 ) + +// ElfHeader64 is the ELF64 file header. +// +// +marshal +type ElfHeader64 struct { + Ident [16]byte // File identification. + Type uint16 // File type. + Machine uint16 // Machine architecture. + Version uint32 // ELF format version. + Entry uint64 // Entry point. + Phoff uint64 // Program header file offset. + Shoff uint64 // Section header file offset. + Flags uint32 // Architecture-specific flags. + Ehsize uint16 // Size of ELF header in bytes. + Phentsize uint16 // Size of program header entry. + Phnum uint16 // Number of program header entries. + Shentsize uint16 // Size of section header entry. + Shnum uint16 // Number of section header entries. + Shstrndx uint16 // Section name strings section. +} + +// ElfSection64 is the ELF64 Section header. +// +// +marshal +type ElfSection64 struct { + Name uint32 // Section name (index into the section header string table). + Type uint32 // Section type. + Flags uint64 // Section flags. + Addr uint64 // Address in memory image. + Off uint64 // Offset in file. + Size uint64 // Size in bytes. + Link uint32 // Index of a related section. + Info uint32 // Depends on section type. + Addralign uint64 // Alignment in bytes. + Entsize uint64 // Size of each entry in section. +} + +// ElfProg64 is the ELF64 Program header. +// +// +marshal +type ElfProg64 struct { + Type uint32 // Entry type. + Flags uint32 // Access permission flags. + Off uint64 // File offset of contents. + Vaddr uint64 // Virtual address in memory image. + Paddr uint64 // Physical address (not used). + Filesz uint64 // Size of contents in file. + Memsz uint64 // Size of contents in memory. + Align uint64 // Alignment in memory and file. +} diff --git a/pkg/abi/linux/epoll.go b/pkg/abi/linux/epoll.go index 1121a1a92..67706f5aa 100644 --- a/pkg/abi/linux/epoll.go +++ b/pkg/abi/linux/epoll.go @@ -14,10 +14,6 @@ package linux -import ( - "gvisor.dev/gvisor/pkg/binary" -) - // Event masks. const ( EPOLLIN = 0x1 @@ -59,4 +55,4 @@ const ( ) // SizeOfEpollEvent is the size of EpollEvent struct. -var SizeOfEpollEvent = int(binary.Size(EpollEvent{})) +var SizeOfEpollEvent = (*EpollEvent)(nil).SizeBytes() diff --git a/pkg/abi/linux/file.go b/pkg/abi/linux/file.go index e11ca2d62..1e23850a9 100644 --- a/pkg/abi/linux/file.go +++ b/pkg/abi/linux/file.go @@ -19,7 +19,6 @@ import ( "strings" "gvisor.dev/gvisor/pkg/abi" - "gvisor.dev/gvisor/pkg/binary" ) // Constants for open(2). @@ -201,7 +200,7 @@ const ( ) // SizeOfStat is the size of a Stat struct. -var SizeOfStat = binary.Size(Stat{}) +var SizeOfStat = (*Stat)(nil).SizeBytes() // Flags for statx. const ( @@ -268,7 +267,7 @@ type Statx struct { } // SizeOfStatx is the size of a Statx struct. -var SizeOfStatx = binary.Size(Statx{}) +var SizeOfStatx = (*Statx)(nil).SizeBytes() // FileMode represents a mode_t. type FileMode uint16 diff --git a/pkg/abi/linux/linux_abi_autogen_unsafe.go b/pkg/abi/linux/linux_abi_autogen_unsafe.go index 4a267d833..b77c2c972 100644 --- a/pkg/abi/linux/linux_abi_autogen_unsafe.go +++ b/pkg/abi/linux/linux_abi_autogen_unsafe.go @@ -27,6 +27,9 @@ var _ marshal.Marshallable = (*ControlMessageCredentials)(nil) var _ marshal.Marshallable = (*ControlMessageHeader)(nil) var _ marshal.Marshallable = (*ControlMessageIPPacketInfo)(nil) var _ marshal.Marshallable = (*DigestMetadata)(nil) +var _ marshal.Marshallable = (*ElfHeader64)(nil) +var _ marshal.Marshallable = (*ElfProg64)(nil) +var _ marshal.Marshallable = (*ElfSection64)(nil) var _ marshal.Marshallable = (*ErrorName)(nil) var _ marshal.Marshallable = (*ExtensionName)(nil) var _ marshal.Marshallable = (*FOwnerEx)(nil) @@ -814,6 +817,394 @@ func (c *CapUserHeader) WriteTo(writer io.Writer) (int64, error) { } // SizeBytes implements marshal.Marshallable.SizeBytes. +func (e *ElfHeader64) SizeBytes() int { + return 48 + + 1*16 +} + +// MarshalBytes implements marshal.Marshallable.MarshalBytes. +func (e *ElfHeader64) MarshalBytes(dst []byte) { + for idx := 0; idx < 16; idx++ { + dst[0] = byte(e.Ident[idx]) + dst = dst[1:] + } + hostarch.ByteOrder.PutUint16(dst[:2], uint16(e.Type)) + dst = dst[2:] + hostarch.ByteOrder.PutUint16(dst[:2], uint16(e.Machine)) + dst = dst[2:] + hostarch.ByteOrder.PutUint32(dst[:4], uint32(e.Version)) + dst = dst[4:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Entry)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Phoff)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Shoff)) + dst = dst[8:] + hostarch.ByteOrder.PutUint32(dst[:4], uint32(e.Flags)) + dst = dst[4:] + hostarch.ByteOrder.PutUint16(dst[:2], uint16(e.Ehsize)) + dst = dst[2:] + hostarch.ByteOrder.PutUint16(dst[:2], uint16(e.Phentsize)) + dst = dst[2:] + hostarch.ByteOrder.PutUint16(dst[:2], uint16(e.Phnum)) + dst = dst[2:] + hostarch.ByteOrder.PutUint16(dst[:2], uint16(e.Shentsize)) + dst = dst[2:] + hostarch.ByteOrder.PutUint16(dst[:2], uint16(e.Shnum)) + dst = dst[2:] + hostarch.ByteOrder.PutUint16(dst[:2], uint16(e.Shstrndx)) + dst = dst[2:] +} + +// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. +func (e *ElfHeader64) UnmarshalBytes(src []byte) { + for idx := 0; idx < 16; idx++ { + e.Ident[idx] = src[0] + src = src[1:] + } + e.Type = uint16(hostarch.ByteOrder.Uint16(src[:2])) + src = src[2:] + e.Machine = uint16(hostarch.ByteOrder.Uint16(src[:2])) + src = src[2:] + e.Version = uint32(hostarch.ByteOrder.Uint32(src[:4])) + src = src[4:] + e.Entry = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Phoff = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Shoff = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Flags = uint32(hostarch.ByteOrder.Uint32(src[:4])) + src = src[4:] + e.Ehsize = uint16(hostarch.ByteOrder.Uint16(src[:2])) + src = src[2:] + e.Phentsize = uint16(hostarch.ByteOrder.Uint16(src[:2])) + src = src[2:] + e.Phnum = uint16(hostarch.ByteOrder.Uint16(src[:2])) + src = src[2:] + e.Shentsize = uint16(hostarch.ByteOrder.Uint16(src[:2])) + src = src[2:] + e.Shnum = uint16(hostarch.ByteOrder.Uint16(src[:2])) + src = src[2:] + e.Shstrndx = uint16(hostarch.ByteOrder.Uint16(src[:2])) + src = src[2:] +} + +// Packed implements marshal.Marshallable.Packed. +//go:nosplit +func (e *ElfHeader64) Packed() bool { + return true +} + +// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe. +func (e *ElfHeader64) MarshalUnsafe(dst []byte) { + gohacks.Memmove(unsafe.Pointer(&dst[0]), unsafe.Pointer(e), uintptr(e.SizeBytes())) +} + +// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe. +func (e *ElfHeader64) UnmarshalUnsafe(src []byte) { + gohacks.Memmove(unsafe.Pointer(e), unsafe.Pointer(&src[0]), uintptr(e.SizeBytes())) +} + +// CopyOutN implements marshal.Marshallable.CopyOutN. +//go:nosplit +func (e *ElfHeader64) CopyOutN(cc marshal.CopyContext, addr hostarch.Addr, limit int) (int, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := cc.CopyOutBytes(addr, buf[:limit]) // escapes: okay. + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return length, err +} + +// CopyOut implements marshal.Marshallable.CopyOut. +//go:nosplit +func (e *ElfHeader64) CopyOut(cc marshal.CopyContext, addr hostarch.Addr) (int, error) { + return e.CopyOutN(cc, addr, e.SizeBytes()) +} + +// CopyIn implements marshal.Marshallable.CopyIn. +//go:nosplit +func (e *ElfHeader64) CopyIn(cc marshal.CopyContext, addr hostarch.Addr) (int, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := cc.CopyInBytes(addr, buf) // escapes: okay. + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return length, err +} + +// WriteTo implements io.WriterTo.WriteTo. +func (e *ElfHeader64) WriteTo(writer io.Writer) (int64, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := writer.Write(buf) + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return int64(length), err +} + +// SizeBytes implements marshal.Marshallable.SizeBytes. +func (e *ElfProg64) SizeBytes() int { + return 56 +} + +// MarshalBytes implements marshal.Marshallable.MarshalBytes. +func (e *ElfProg64) MarshalBytes(dst []byte) { + hostarch.ByteOrder.PutUint32(dst[:4], uint32(e.Type)) + dst = dst[4:] + hostarch.ByteOrder.PutUint32(dst[:4], uint32(e.Flags)) + dst = dst[4:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Off)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Vaddr)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Paddr)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Filesz)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Memsz)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Align)) + dst = dst[8:] +} + +// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. +func (e *ElfProg64) UnmarshalBytes(src []byte) { + e.Type = uint32(hostarch.ByteOrder.Uint32(src[:4])) + src = src[4:] + e.Flags = uint32(hostarch.ByteOrder.Uint32(src[:4])) + src = src[4:] + e.Off = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Vaddr = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Paddr = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Filesz = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Memsz = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Align = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] +} + +// Packed implements marshal.Marshallable.Packed. +//go:nosplit +func (e *ElfProg64) Packed() bool { + return true +} + +// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe. +func (e *ElfProg64) MarshalUnsafe(dst []byte) { + gohacks.Memmove(unsafe.Pointer(&dst[0]), unsafe.Pointer(e), uintptr(e.SizeBytes())) +} + +// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe. +func (e *ElfProg64) UnmarshalUnsafe(src []byte) { + gohacks.Memmove(unsafe.Pointer(e), unsafe.Pointer(&src[0]), uintptr(e.SizeBytes())) +} + +// CopyOutN implements marshal.Marshallable.CopyOutN. +//go:nosplit +func (e *ElfProg64) CopyOutN(cc marshal.CopyContext, addr hostarch.Addr, limit int) (int, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := cc.CopyOutBytes(addr, buf[:limit]) // escapes: okay. + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return length, err +} + +// CopyOut implements marshal.Marshallable.CopyOut. +//go:nosplit +func (e *ElfProg64) CopyOut(cc marshal.CopyContext, addr hostarch.Addr) (int, error) { + return e.CopyOutN(cc, addr, e.SizeBytes()) +} + +// CopyIn implements marshal.Marshallable.CopyIn. +//go:nosplit +func (e *ElfProg64) CopyIn(cc marshal.CopyContext, addr hostarch.Addr) (int, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := cc.CopyInBytes(addr, buf) // escapes: okay. + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return length, err +} + +// WriteTo implements io.WriterTo.WriteTo. +func (e *ElfProg64) WriteTo(writer io.Writer) (int64, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := writer.Write(buf) + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return int64(length), err +} + +// SizeBytes implements marshal.Marshallable.SizeBytes. +func (e *ElfSection64) SizeBytes() int { + return 64 +} + +// MarshalBytes implements marshal.Marshallable.MarshalBytes. +func (e *ElfSection64) MarshalBytes(dst []byte) { + hostarch.ByteOrder.PutUint32(dst[:4], uint32(e.Name)) + dst = dst[4:] + hostarch.ByteOrder.PutUint32(dst[:4], uint32(e.Type)) + dst = dst[4:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Flags)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Addr)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Off)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Size)) + dst = dst[8:] + hostarch.ByteOrder.PutUint32(dst[:4], uint32(e.Link)) + dst = dst[4:] + hostarch.ByteOrder.PutUint32(dst[:4], uint32(e.Info)) + dst = dst[4:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Addralign)) + dst = dst[8:] + hostarch.ByteOrder.PutUint64(dst[:8], uint64(e.Entsize)) + dst = dst[8:] +} + +// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. +func (e *ElfSection64) UnmarshalBytes(src []byte) { + e.Name = uint32(hostarch.ByteOrder.Uint32(src[:4])) + src = src[4:] + e.Type = uint32(hostarch.ByteOrder.Uint32(src[:4])) + src = src[4:] + e.Flags = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Addr = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Off = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Size = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Link = uint32(hostarch.ByteOrder.Uint32(src[:4])) + src = src[4:] + e.Info = uint32(hostarch.ByteOrder.Uint32(src[:4])) + src = src[4:] + e.Addralign = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] + e.Entsize = uint64(hostarch.ByteOrder.Uint64(src[:8])) + src = src[8:] +} + +// Packed implements marshal.Marshallable.Packed. +//go:nosplit +func (e *ElfSection64) Packed() bool { + return true +} + +// MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe. +func (e *ElfSection64) MarshalUnsafe(dst []byte) { + gohacks.Memmove(unsafe.Pointer(&dst[0]), unsafe.Pointer(e), uintptr(e.SizeBytes())) +} + +// UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe. +func (e *ElfSection64) UnmarshalUnsafe(src []byte) { + gohacks.Memmove(unsafe.Pointer(e), unsafe.Pointer(&src[0]), uintptr(e.SizeBytes())) +} + +// CopyOutN implements marshal.Marshallable.CopyOutN. +//go:nosplit +func (e *ElfSection64) CopyOutN(cc marshal.CopyContext, addr hostarch.Addr, limit int) (int, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := cc.CopyOutBytes(addr, buf[:limit]) // escapes: okay. + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return length, err +} + +// CopyOut implements marshal.Marshallable.CopyOut. +//go:nosplit +func (e *ElfSection64) CopyOut(cc marshal.CopyContext, addr hostarch.Addr) (int, error) { + return e.CopyOutN(cc, addr, e.SizeBytes()) +} + +// CopyIn implements marshal.Marshallable.CopyIn. +//go:nosplit +func (e *ElfSection64) CopyIn(cc marshal.CopyContext, addr hostarch.Addr) (int, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := cc.CopyInBytes(addr, buf) // escapes: okay. + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return length, err +} + +// WriteTo implements io.WriterTo.WriteTo. +func (e *ElfSection64) WriteTo(writer io.Writer) (int64, error) { + // Construct a slice backed by dst's underlying memory. + var buf []byte + hdr := (*reflect.SliceHeader)(unsafe.Pointer(&buf)) + hdr.Data = uintptr(gohacks.Noescape(unsafe.Pointer(e))) + hdr.Len = e.SizeBytes() + hdr.Cap = e.SizeBytes() + + length, err := writer.Write(buf) + // Since we bypassed the compiler's escape analysis, indicate that e + // must live until the use above. + runtime.KeepAlive(e) // escapes: replaced by intrinsic. + return int64(length), err +} + +// SizeBytes implements marshal.Marshallable.SizeBytes. func (s *SockErrCMsgIPv4) SizeBytes() int { return 0 + (*SockExtendedErr)(nil).SizeBytes() + diff --git a/pkg/abi/linux/netdevice.go b/pkg/abi/linux/netdevice.go index 0faf015c7..51a39704b 100644 --- a/pkg/abi/linux/netdevice.go +++ b/pkg/abi/linux/netdevice.go @@ -14,8 +14,6 @@ package linux -import "gvisor.dev/gvisor/pkg/binary" - const ( // IFNAMSIZ is the size of the name field for IFReq. IFNAMSIZ = 16 @@ -66,7 +64,7 @@ func (ifr *IFReq) SetName(name string) { } // SizeOfIFReq is the binary size of an IFReq struct (40 bytes). -var SizeOfIFReq = binary.Size(IFReq{}) +var SizeOfIFReq = (*IFReq)(nil).SizeBytes() // IFMap contains interface hardware parameters. type IFMap struct { diff --git a/pkg/binary/binary.go b/pkg/binary/binary.go deleted file mode 100644 index 25065aef9..000000000 --- a/pkg/binary/binary.go +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2018 The gVisor Authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package binary translates between select fixed-sized types and a binary -// representation. -package binary - -import ( - "encoding/binary" - "fmt" - "io" - "reflect" -) - -// LittleEndian is the same as encoding/binary.LittleEndian. -// -// It is included here as a convenience. -var LittleEndian = binary.LittleEndian - -// BigEndian is the same as encoding/binary.BigEndian. -// -// It is included here as a convenience. -var BigEndian = binary.BigEndian - -// AppendUint16 appends the binary representation of a uint16 to buf. -func AppendUint16(buf []byte, order binary.ByteOrder, num uint16) []byte { - buf = append(buf, make([]byte, 2)...) - order.PutUint16(buf[len(buf)-2:], num) - return buf -} - -// AppendUint32 appends the binary representation of a uint32 to buf. -func AppendUint32(buf []byte, order binary.ByteOrder, num uint32) []byte { - buf = append(buf, make([]byte, 4)...) - order.PutUint32(buf[len(buf)-4:], num) - return buf -} - -// AppendUint64 appends the binary representation of a uint64 to buf. -func AppendUint64(buf []byte, order binary.ByteOrder, num uint64) []byte { - buf = append(buf, make([]byte, 8)...) - order.PutUint64(buf[len(buf)-8:], num) - return buf -} - -// Marshal appends a binary representation of data to buf. -// -// data must only contain fixed-length signed and unsigned ints, arrays, -// slices, structs and compositions of said types. data may be a pointer, -// but cannot contain pointers. -func Marshal(buf []byte, order binary.ByteOrder, data interface{}) []byte { - return marshal(buf, order, reflect.Indirect(reflect.ValueOf(data))) -} - -func marshal(buf []byte, order binary.ByteOrder, data reflect.Value) []byte { - switch data.Kind() { - case reflect.Int8: - buf = append(buf, byte(int8(data.Int()))) - case reflect.Int16: - buf = AppendUint16(buf, order, uint16(int16(data.Int()))) - case reflect.Int32: - buf = AppendUint32(buf, order, uint32(int32(data.Int()))) - case reflect.Int64: - buf = AppendUint64(buf, order, uint64(data.Int())) - - case reflect.Uint8: - buf = append(buf, byte(data.Uint())) - case reflect.Uint16: - buf = AppendUint16(buf, order, uint16(data.Uint())) - case reflect.Uint32: - buf = AppendUint32(buf, order, uint32(data.Uint())) - case reflect.Uint64: - buf = AppendUint64(buf, order, data.Uint()) - - case reflect.Array, reflect.Slice: - for i, l := 0, data.Len(); i < l; i++ { - buf = marshal(buf, order, data.Index(i)) - } - - case reflect.Struct: - for i, l := 0, data.NumField(); i < l; i++ { - buf = marshal(buf, order, data.Field(i)) - } - - default: - panic("invalid type: " + data.Type().String()) - } - return buf -} - -// Unmarshal unpacks buf into data. -// -// data must be a slice or a pointer and buf must have a length of exactly -// Size(data). data must only contain fixed-length signed and unsigned ints, -// arrays, slices, structs and compositions of said types. -func Unmarshal(buf []byte, order binary.ByteOrder, data interface{}) { - value := reflect.ValueOf(data) - switch value.Kind() { - case reflect.Ptr: - value = value.Elem() - case reflect.Slice: - default: - panic("invalid type: " + value.Type().String()) - } - buf = unmarshal(buf, order, value) - if len(buf) != 0 { - panic(fmt.Sprintf("buffer too long by %d bytes", len(buf))) - } -} - -func unmarshal(buf []byte, order binary.ByteOrder, data reflect.Value) []byte { - switch data.Kind() { - case reflect.Int8: - data.SetInt(int64(int8(buf[0]))) - buf = buf[1:] - case reflect.Int16: - data.SetInt(int64(int16(order.Uint16(buf)))) - buf = buf[2:] - case reflect.Int32: - data.SetInt(int64(int32(order.Uint32(buf)))) - buf = buf[4:] - case reflect.Int64: - data.SetInt(int64(order.Uint64(buf))) - buf = buf[8:] - - case reflect.Uint8: - data.SetUint(uint64(buf[0])) - buf = buf[1:] - case reflect.Uint16: - data.SetUint(uint64(order.Uint16(buf))) - buf = buf[2:] - case reflect.Uint32: - data.SetUint(uint64(order.Uint32(buf))) - buf = buf[4:] - case reflect.Uint64: - data.SetUint(order.Uint64(buf)) - buf = buf[8:] - - case reflect.Array, reflect.Slice: - for i, l := 0, data.Len(); i < l; i++ { - buf = unmarshal(buf, order, data.Index(i)) - } - - case reflect.Struct: - for i, l := 0, data.NumField(); i < l; i++ { - if field := data.Field(i); field.CanSet() { - buf = unmarshal(buf, order, field) - } else { - buf = buf[sizeof(field):] - } - } - - default: - panic("invalid type: " + data.Type().String()) - } - return buf -} - -// Size calculates the buffer sized needed by Marshal or Unmarshal. -// -// Size only support the types supported by Marshal. -func Size(v interface{}) uintptr { - return sizeof(reflect.Indirect(reflect.ValueOf(v))) -} - -func sizeof(data reflect.Value) uintptr { - switch data.Kind() { - case reflect.Int8, reflect.Uint8: - return 1 - case reflect.Int16, reflect.Uint16: - return 2 - case reflect.Int32, reflect.Uint32: - return 4 - case reflect.Int64, reflect.Uint64: - return 8 - - case reflect.Array, reflect.Slice: - var size uintptr - for i, l := 0, data.Len(); i < l; i++ { - size += sizeof(data.Index(i)) - } - return size - - case reflect.Struct: - var size uintptr - for i, l := 0, data.NumField(); i < l; i++ { - size += sizeof(data.Field(i)) - } - return size - - default: - panic("invalid type: " + data.Type().String()) - } -} - -// ReadUint16 reads a uint16 from r. -func ReadUint16(r io.Reader, order binary.ByteOrder) (uint16, error) { - buf := make([]byte, 2) - if _, err := io.ReadFull(r, buf); err != nil { - return 0, err - } - return order.Uint16(buf), nil -} - -// ReadUint32 reads a uint32 from r. -func ReadUint32(r io.Reader, order binary.ByteOrder) (uint32, error) { - buf := make([]byte, 4) - if _, err := io.ReadFull(r, buf); err != nil { - return 0, err - } - return order.Uint32(buf), nil -} - -// ReadUint64 reads a uint64 from r. -func ReadUint64(r io.Reader, order binary.ByteOrder) (uint64, error) { - buf := make([]byte, 8) - if _, err := io.ReadFull(r, buf); err != nil { - return 0, err - } - return order.Uint64(buf), nil -} - -// WriteUint16 writes a uint16 to w. -func WriteUint16(w io.Writer, order binary.ByteOrder, num uint16) error { - buf := make([]byte, 2) - order.PutUint16(buf, num) - _, err := w.Write(buf) - return err -} - -// WriteUint32 writes a uint32 to w. -func WriteUint32(w io.Writer, order binary.ByteOrder, num uint32) error { - buf := make([]byte, 4) - order.PutUint32(buf, num) - _, err := w.Write(buf) - return err -} - -// WriteUint64 writes a uint64 to w. -func WriteUint64(w io.Writer, order binary.ByteOrder, num uint64) error { - buf := make([]byte, 8) - order.PutUint64(buf, num) - _, err := w.Write(buf) - return err -} - -// AlignUp rounds a length up to an alignment. align must be a power of 2. -func AlignUp(length int, align uint) int { - return (length + int(align) - 1) & ^(int(align) - 1) -} - -// AlignDown rounds a length down to an alignment. align must be a power of 2. -func AlignDown(length int, align uint) int { - return length & ^(int(align) - 1) -} diff --git a/pkg/binary/binary_state_autogen.go b/pkg/binary/binary_state_autogen.go deleted file mode 100644 index 4661a5982..000000000 --- a/pkg/binary/binary_state_autogen.go +++ /dev/null @@ -1,3 +0,0 @@ -// automatically generated by stateify. - -package binary diff --git a/pkg/compressio/compressio.go b/pkg/compressio/compressio.go index b094c5662..615d7f134 100644 --- a/pkg/compressio/compressio.go +++ b/pkg/compressio/compressio.go @@ -48,12 +48,12 @@ import ( "compress/flate" "crypto/hmac" "crypto/sha256" + "encoding/binary" "errors" "hash" "io" "runtime" - "gvisor.dev/gvisor/pkg/binary" "gvisor.dev/gvisor/pkg/sync" ) @@ -130,6 +130,10 @@ type worker struct { hashPool *hashPool input chan *chunk output chan result + + // scratch is a temporary buffer used for marshalling. This is declared + // unfront here to avoid reallocation. + scratch [4]byte } // work is the main work routine; see worker. @@ -167,7 +171,8 @@ func (w *worker) work(compress bool, level int) { // Write the hash, if enabled. if h != nil { - binary.WriteUint32(h, binary.BigEndian, uint32(c.compressed.Len())) + binary.BigEndian.PutUint32(w.scratch[:], uint32(c.compressed.Len())) + h.Write(w.scratch[:4]) c.h = h h = nil } @@ -175,7 +180,8 @@ func (w *worker) work(compress bool, level int) { // Check the hash of the compressed contents. if h != nil { h.Write(c.compressed.Bytes()) - binary.WriteUint32(h, binary.BigEndian, uint32(c.compressed.Len())) + binary.BigEndian.PutUint32(w.scratch[:], uint32(c.compressed.Len())) + h.Write(w.scratch[:4]) io.CopyN(h, bytes.NewReader(c.lastSum), int64(len(c.lastSum))) sum := h.Sum(nil) @@ -352,6 +358,10 @@ type Reader struct { // in is the source. in io.Reader + + // scratch is a temporary buffer used for marshalling. This is declared + // unfront here to avoid reallocation. + scratch [4]byte } var _ io.Reader = (*Reader)(nil) @@ -368,14 +378,15 @@ func NewReader(in io.Reader, key []byte) (*Reader, error) { // Use double buffering for read. r.init(key, 2*runtime.GOMAXPROCS(0), false, 0) - var err error - if r.chunkSize, err = binary.ReadUint32(in, binary.BigEndian); err != nil { + if _, err := io.ReadFull(in, r.scratch[:4]); err != nil { return nil, err } + r.chunkSize = binary.BigEndian.Uint32(r.scratch[:4]) if r.hashPool != nil { h := r.hashPool.getHash() - binary.WriteUint32(h, binary.BigEndian, r.chunkSize) + binary.BigEndian.PutUint32(r.scratch[:], r.chunkSize) + h.Write(r.scratch[:4]) r.lastSum = h.Sum(nil) r.hashPool.putHash(h) sum := make([]byte, len(r.lastSum)) @@ -467,8 +478,7 @@ func (r *Reader) Read(p []byte) (int, error) { // reader. The length is used to limit the reader. // // See writer.flush. - l, err := binary.ReadUint32(r.in, binary.BigEndian) - if err != nil { + if _, err := io.ReadFull(r.in, r.scratch[:4]); err != nil { // This is generally okay as long as there // are still buffers outstanding. We actually // just wait for completion of those buffers here @@ -488,6 +498,7 @@ func (r *Reader) Read(p []byte) (int, error) { return done, err } } + l := binary.BigEndian.Uint32(r.scratch[:4]) // Read this chunk and schedule decompression. compressed := bufPool.Get().(*bytes.Buffer) @@ -573,6 +584,10 @@ type Writer struct { // closed indicates whether the file has been closed. closed bool + + // scratch is a temporary buffer used for marshalling. This is declared + // unfront here to avoid reallocation. + scratch [4]byte } var _ io.Writer = (*Writer)(nil) @@ -594,13 +609,15 @@ func NewWriter(out io.Writer, key []byte, chunkSize uint32, level int) (*Writer, } w.init(key, 1+runtime.GOMAXPROCS(0), true, level) - if err := binary.WriteUint32(w.out, binary.BigEndian, chunkSize); err != nil { + binary.BigEndian.PutUint32(w.scratch[:], chunkSize) + if _, err := w.out.Write(w.scratch[:4]); err != nil { return nil, err } if w.hashPool != nil { h := w.hashPool.getHash() - binary.WriteUint32(h, binary.BigEndian, chunkSize) + binary.BigEndian.PutUint32(w.scratch[:], chunkSize) + h.Write(w.scratch[:4]) w.lastSum = h.Sum(nil) w.hashPool.putHash(h) if _, err := io.CopyN(w.out, bytes.NewReader(w.lastSum), int64(len(w.lastSum))); err != nil { @@ -616,7 +633,9 @@ func (w *Writer) flush(c *chunk) error { // Prefix each chunk with a length; this allows the reader to safely // limit reads while buffering. l := uint32(c.compressed.Len()) - if err := binary.WriteUint32(w.out, binary.BigEndian, l); err != nil { + + binary.BigEndian.PutUint32(w.scratch[:], l) + if _, err := w.out.Write(w.scratch[:4]); err != nil { return err } diff --git a/pkg/sentry/loader/elf.go b/pkg/sentry/loader/elf.go index e92d9fdc3..8fc3e2a79 100644 --- a/pkg/sentry/loader/elf.go +++ b/pkg/sentry/loader/elf.go @@ -22,7 +22,6 @@ import ( "gvisor.dev/gvisor/pkg/abi" "gvisor.dev/gvisor/pkg/abi/linux" - "gvisor.dev/gvisor/pkg/binary" "gvisor.dev/gvisor/pkg/context" "gvisor.dev/gvisor/pkg/cpuid" "gvisor.dev/gvisor/pkg/hostarch" @@ -47,10 +46,10 @@ const ( var ( // header64Size is the size of elf.Header64. - header64Size = int(binary.Size(elf.Header64{})) + header64Size = (*linux.ElfHeader64)(nil).SizeBytes() // Prog64Size is the size of elf.Prog64. - prog64Size = int(binary.Size(elf.Prog64{})) + prog64Size = (*linux.ElfProg64)(nil).SizeBytes() ) func progFlagsAsPerms(f elf.ProgFlag) hostarch.AccessType { @@ -136,7 +135,6 @@ func parseHeader(ctx context.Context, f fullReader) (elfInfo, error) { log.Infof("Unsupported ELF endianness: %v", endian) return elfInfo{}, syserror.ENOEXEC } - byteOrder := binary.LittleEndian if version := elf.Version(ident[elf.EI_VERSION]); version != elf.EV_CURRENT { log.Infof("Unsupported ELF version: %v", version) @@ -145,7 +143,7 @@ func parseHeader(ctx context.Context, f fullReader) (elfInfo, error) { // EI_OSABI is ignored by Linux, which is the only OS supported. os := abi.Linux - var hdr elf.Header64 + var hdr linux.ElfHeader64 hdrBuf := make([]byte, header64Size) _, err = f.ReadFull(ctx, usermem.BytesIOSequence(hdrBuf), 0) if err != nil { @@ -156,7 +154,7 @@ func parseHeader(ctx context.Context, f fullReader) (elfInfo, error) { } return elfInfo{}, err } - binary.Unmarshal(hdrBuf, byteOrder, &hdr) + hdr.UnmarshalUnsafe(hdrBuf) // We support amd64 and arm64. var a arch.Arch @@ -213,8 +211,8 @@ func parseHeader(ctx context.Context, f fullReader) (elfInfo, error) { phdrs := make([]elf.ProgHeader, hdr.Phnum) for i := range phdrs { - var prog64 elf.Prog64 - binary.Unmarshal(phdrBuf[:prog64Size], byteOrder, &prog64) + var prog64 linux.ElfProg64 + prog64.UnmarshalUnsafe(phdrBuf[:prog64Size]) phdrBuf = phdrBuf[prog64Size:] phdrs[i] = elf.ProgHeader{ Type: elf.ProgType(prog64.Type), diff --git a/pkg/sentry/loader/loader_abi_autogen_unsafe.go b/pkg/sentry/loader/loader_abi_autogen_unsafe.go new file mode 100644 index 000000000..bfa048912 --- /dev/null +++ b/pkg/sentry/loader/loader_abi_autogen_unsafe.go @@ -0,0 +1,13 @@ +// Automatically generated marshal implementation. See tools/go_marshal. + +// If there are issues with build tag aggregation, see +// tools/go_marshal/gomarshal/generator.go:writeHeader(). The build tags here +// come from the input set of files used to generate this file. This input set +// is filtered based on pre-defined file suffixes related to build tags, see +// tools/defs.bzl:calculate_sets(). + +package loader + +import ( +) + diff --git a/pkg/state/statefile/statefile.go b/pkg/state/statefile/statefile.go index bdfb800fb..d27c8c8a8 100644 --- a/pkg/state/statefile/statefile.go +++ b/pkg/state/statefile/statefile.go @@ -48,6 +48,7 @@ import ( "compress/flate" "crypto/hmac" "crypto/sha256" + "encoding/binary" "encoding/json" "fmt" "hash" @@ -55,7 +56,6 @@ import ( "strings" "time" - "gvisor.dev/gvisor/pkg/binary" "gvisor.dev/gvisor/pkg/compressio" "gvisor.dev/gvisor/pkg/state/wire" ) @@ -90,6 +90,13 @@ type WriteCloser interface { io.Closer } +func writeMetadataLen(w io.Writer, val uint64) error { + var buf [8]byte + binary.BigEndian.PutUint64(buf[:], val) + _, err := w.Write(buf[:]) + return err +} + // NewWriter returns a state data writer for a statefile. // // Note that the returned WriteCloser must be closed. @@ -127,7 +134,7 @@ func NewWriter(w io.Writer, key []byte, metadata map[string]string) (WriteCloser } // Metadata length. - if err := binary.WriteUint64(mw, binary.BigEndian, uint64(len(b))); err != nil { + if err := writeMetadataLen(mw, uint64(len(b))); err != nil { return nil, err } // Metadata bytes; io.MultiWriter will return a short write error if @@ -158,6 +165,14 @@ func MetadataUnsafe(r io.Reader) (map[string]string, error) { return metadata(r, nil) } +func readMetadataLen(r io.Reader) (uint64, error) { + var buf [8]byte + if _, err := io.ReadFull(r, buf[:]); err != nil { + return 0, err + } + return binary.BigEndian.Uint64(buf[:]), nil +} + // metadata validates the magic header and reads out the metadata from a state // data stream. func metadata(r io.Reader, h hash.Hash) (map[string]string, error) { @@ -183,7 +198,7 @@ func metadata(r io.Reader, h hash.Hash) (map[string]string, error) { } }() - metadataLen, err := binary.ReadUint64(r, binary.BigEndian) + metadataLen, err := readMetadataLen(r) if err != nil { return nil, err } |