github.com/criyle/go-sandbox@v0.10.3/pkg/memfd/memfd_linux.go (about)

     1  package memfd
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  
     8  	"golang.org/x/sys/unix"
     9  )
    10  
    11  const createFlag = unix.MFD_CLOEXEC | unix.MFD_ALLOW_SEALING
    12  const roSeal = unix.F_SEAL_SEAL | unix.F_SEAL_SHRINK | unix.F_SEAL_GROW | unix.F_SEAL_WRITE
    13  
    14  // New creates a new memfd, caller need to close the file
    15  func New(name string) (*os.File, error) {
    16  	fd, err := unix.MemfdCreate(name, createFlag)
    17  	if err != nil {
    18  		return nil, fmt.Errorf("memfd: memfd_create failed %v", err)
    19  	}
    20  	file := os.NewFile(uintptr(fd), name)
    21  	if file == nil {
    22  		unix.Close(fd)
    23  		return nil, fmt.Errorf("memfd: NewFile failed for %v", name)
    24  	}
    25  	return file, nil
    26  }
    27  
    28  // DupToMemfd reads content from reader to sealed (readonly) memfd for given name
    29  func DupToMemfd(name string, reader io.Reader) (*os.File, error) {
    30  	file, err := New(name)
    31  	if err != nil {
    32  		return nil, fmt.Errorf("DupToMemfd: %v", err)
    33  	}
    34  	// linux syscall sendfile might be more efficient here if reader is a file
    35  	if _, err = file.ReadFrom(reader); err != nil {
    36  		file.Close()
    37  		return nil, fmt.Errorf("DupToMemfd: read from %v", err)
    38  	}
    39  	// make memfd readonly
    40  	if _, err = unix.FcntlInt(file.Fd(), unix.F_ADD_SEALS, roSeal); err != nil {
    41  		file.Close()
    42  		return nil, fmt.Errorf("DupToMemfd: memfd seal %v", err)
    43  	}
    44  	if _, err := file.Seek(0, 0); err != nil {
    45  		file.Close()
    46  		return nil, fmt.Errorf("DupToMemfd: file seek %v", err)
    47  	}
    48  	return file, nil
    49  }