// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package control import ( "bytes" "fmt" "io" "net" "os" "path/filepath" "syscall" "time" ) const handoffMarker = "FENRIR-CONNECTION\n" // Transfer the original connected socket, rather than forwarding its text. // SO_PEERCRED and replies then remain attached to the actual caller, including // when an unprivileged shared owner routes a request to a root TTY reader. func handoff(caller *net.UnixConn, path string) error { connection, err := net.DialTimeout("unix", path, 200*time.Millisecond) if err != nil { return err } defer connection.Close() target := connection.(*net.UnixConn) var expectedPID int _, parseErr := fmt.Sscanf(filepath.Base(path), "fenrirscreenreader-%d.sock", &expectedPID) pid, uid, credentialErr := peer(target) info, statErr := os.Lstat(path) if parseErr != nil || credentialErr != nil || statErr != nil || pid != expectedPID { return fmt.Errorf("private reader identity changed") } if stat, ok := info.Sys().(*syscall.Stat_t); !ok || int(stat.Uid) != uid { return fmt.Errorf("private reader ownership changed") } _ = target.SetDeadline(time.Now().Add(500 * time.Millisecond)) raw, err := caller.SyscallConn() if err != nil { return err } var sendErr error err = raw.Control(func(fd uintptr) { count, _, err := target.WriteMsgUnix([]byte(handoffMarker), syscall.UnixRights(int(fd)), nil) sendErr = err if sendErr == nil && count < len(handoffMarker) { _, sendErr = io.WriteString(target, handoffMarker[count:]) } }) if err != nil { return err } return sendErr } func receive_request(connection *net.UnixConn) (string, *net.UnixConn, error) { _ = connection.SetReadDeadline(time.Now().Add(250 * time.Millisecond)) var buffer [8192]byte control := make([]byte, syscall.CmsgSpace(4)) count, controlCount, flags, _, err := connection.ReadMsgUnix(buffer[:], control) if err != nil { return "", nil, err } var files []int messages, parseErr := syscall.ParseSocketControlMessage(control[:controlCount]) for _, message := range messages { fds, err := syscall.ParseUnixRights(&message) if err != nil { parseErr = err } for _, fd := range fds { syscall.CloseOnExec(fd) } files = append(files, fds...) } defer func() { for _, fd := range files { _ = syscall.Close(fd) } }() if parseErr != nil || flags&(syscall.MSG_CTRUNC|syscall.MSG_TRUNC) != 0 { return "", nil, fmt.Errorf("invalid connection handoff") } if len(files) > 0 { if len(files) != 1 { return "", nil, fmt.Errorf("invalid connection handoff") } frame := io.MultiReader(bytes.NewReader(buffer[:count]), connection) header := make([]byte, len(handoffMarker)) if _, err := io.ReadFull(frame, header); err != nil || string(header) != handoffMarker { return "", nil, fmt.Errorf("invalid connection handoff header") } // FileConn duplicates the descriptor. The received descriptor is closed // below; the duplicate belongs to the request handler. file := os.NewFile(uintptr(files[0]), "remote-caller") files = nil forwarded, err := net.FileConn(file) file.Close() if err != nil { return "", nil, err } unix, ok := forwarded.(*net.UnixConn) if !ok || forwarded.LocalAddr().Network() != "unix" { forwarded.Close() return "", nil, fmt.Errorf("handoff is not a Unix connection") } return "", unix, nil } text, err := read_request(connection, buffer[:count]) return text, nil, err }