...

Source file src/github.com/opencontainers/runc/libcontainer/utils/cmsg.go

Documentation: github.com/opencontainers/runc/libcontainer/utils

     1  package utils
     2  
     3  /*
     4   * Copyright 2016, 2017 SUSE LLC
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  import (
    20  	"fmt"
    21  	"os"
    22  
    23  	"golang.org/x/sys/unix"
    24  )
    25  
    26  // MaxSendfdLen is the maximum length of the name of a file descriptor being
    27  // sent using SendFd. The name of the file handle returned by RecvFd will never
    28  // be larger than this value.
    29  const MaxNameLen = 4096
    30  
    31  // oobSpace is the size of the oob slice required to store a single FD. Note
    32  // that unix.UnixRights appears to make the assumption that fd is always int32,
    33  // so sizeof(fd) = 4.
    34  var oobSpace = unix.CmsgSpace(4)
    35  
    36  // RecvFd waits for a file descriptor to be sent over the given AF_UNIX
    37  // socket. The file name of the remote file descriptor will be recreated
    38  // locally (it is sent as non-auxiliary data in the same payload).
    39  func RecvFd(socket *os.File) (*os.File, error) {
    40  	// For some reason, unix.Recvmsg uses the length rather than the capacity
    41  	// when passing the msg_controllen and other attributes to recvmsg.  So we
    42  	// have to actually set the length.
    43  	name := make([]byte, MaxNameLen)
    44  	oob := make([]byte, oobSpace)
    45  
    46  	sockfd := socket.Fd()
    47  	n, oobn, _, _, err := unix.Recvmsg(int(sockfd), name, oob, 0)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	if n >= MaxNameLen || oobn != oobSpace {
    53  		return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
    54  	}
    55  
    56  	// Truncate.
    57  	name = name[:n]
    58  	oob = oob[:oobn]
    59  
    60  	scms, err := unix.ParseSocketControlMessage(oob)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	if len(scms) != 1 {
    65  		return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
    66  	}
    67  	scm := scms[0]
    68  
    69  	fds, err := unix.ParseUnixRights(&scm)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	if len(fds) != 1 {
    74  		return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
    75  	}
    76  	fd := uintptr(fds[0])
    77  
    78  	return os.NewFile(fd, string(name)), nil
    79  }
    80  
    81  // SendFd sends a file descriptor over the given AF_UNIX socket. In
    82  // addition, the file.Name() of the given file will also be sent as
    83  // non-auxiliary data in the same payload (allowing to send contextual
    84  // information for a file descriptor).
    85  func SendFd(socket *os.File, name string, fd uintptr) error {
    86  	if len(name) >= MaxNameLen {
    87  		return fmt.Errorf("sendfd: filename too long: %s", name)
    88  	}
    89  	return SendFds(socket, []byte(name), int(fd))
    90  }
    91  
    92  // SendFds sends a list of files descriptor and msg over the given AF_UNIX socket.
    93  func SendFds(socket *os.File, msg []byte, fds ...int) error {
    94  	oob := unix.UnixRights(fds...)
    95  	return unix.Sendmsg(int(socket.Fd()), msg, oob, nil, 0)
    96  }
    97  

View as plain text