Skip to content

IPC: Windows support #34

@joe0BAB

Description

@joe0BAB

Background: The secret engine in certain scenarios will have to run on the host OS (eg when integrated into Docker Desktop).

Image

Right now we're using the IPC implementation from https://github.com/containerd/nri/tree/main/pkg/net for the start. However, that implementation doesn't support windows. Essentially, we need to port the socket injection/sharing code to windows, either by forking the implementation and adding it or contributing to upstream.

// parent.go
package main

import (
    "fmt"
    "os"
    "os/exec"
    "strconv"
    "syscall"
    "unsafe"
)

func main() {
    // 1) Create an inheritable anonymous pipe:
    sa := &syscall.SecurityAttributes{
        Length:        uint32(unsafe.Sizeof(syscall.SecurityAttributes{})),
        InheritHandle: 1, // make handles inheritable
    }
    var rHandle, wHandle syscall.Handle
    if err := syscall.CreatePipe(&rHandle, &wHandle, sa, 0); err != nil {
        panic("CreatePipe: " + err.Error())
    }
    // Wrap ends as *os.File for Go I/O:
    rFile := os.NewFile(uintptr(rHandle), "PIPE_READ")
    wFile := os.NewFile(uintptr(wHandle), "PIPE_WRITE")
    defer rFile.Close() // parent reads from rFile
    // Note: we close wFile in the child when done, parent doesn't need it.

    // 2) Prepare the child command:
    cmd := exec.Command("child.exe") // adjust path/name as needed

    // Pass the raw handle value (so the child knows which handle to use):
    cmd.Env = append(os.Environ(),
        "PIPE_HANDLE="+strconv.FormatUint(uint64(wHandle), 10),
    )

    // Tell Go's CreateProcess to inherit exactly that handle:
    cmd.SysProcAttr = &syscall.SysProcAttr{
        AdditionalInheritedHandles: []syscall.Handle{wHandle},
    }

    // Start the child:
    if err := cmd.Start(); err != nil {
        panic("cmd.Start: " + err.Error())
    }

    // 3) In the parent, read what the child writes:
    buf := make([]byte, 128)
    n, err := rFile.Read(buf)
    if err != nil {
        panic("parent Read: " + err.Error())
    }
    fmt.Printf("Parent received: %s", string(buf[:n]))

    cmd.Wait()
}

and

// child.go
package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    // 4) Child re-reads the inherited handle from the ENV var:
    hstr := os.Getenv("PIPE_HANDLE")
    if hstr == "" {
        panic("PIPE_HANDLE not set")
    }
    hVal, err := strconv.ParseUint(hstr, 10, 0)
    if err != nil {
        panic("invalid PIPE_HANDLE: " + err.Error())
    }

    // Wrap the inherited handle in an *os.File:
    pipe := os.NewFile(uintptr(hVal), "PIPE_WRITE")
    defer pipe.Close()

    // Send a message back to parent:
    msg := "hello from child\n"
    if _, err := pipe.Write([]byte(msg)); err != nil {
        panic("child Write: " + err.Error())
    }
    fmt.Printf("Child sent: %s", msg)
}

Source: https://chatgpt.com/share/e/685a5e01-a208-800c-8272-e23fa42b7ab6

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No fields configured for Task.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions