github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/strace/socket.go (about)

     1  // Copyright 2018 Google LLC.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package strace
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"github.com/u-root/u-root/pkg/strace/internal/abi"
    22  	"github.com/u-root/u-root/pkg/strace/internal/binary"
    23  	"github.com/u-root/u-root/pkg/ubinary"
    24  	"golang.org/x/sys/unix"
    25  )
    26  
    27  func cmsghdr(t Task, addr Addr, length uint64, maxBytes uint64) string {
    28  	if length > maxBytes {
    29  		return fmt.Sprintf("%#x (error decoding control: invalid length (%d))", addr, length)
    30  	}
    31  
    32  	buf := make([]byte, length)
    33  	if _, err := t.Read(addr, &buf); err != nil {
    34  		return fmt.Sprintf("%#x (error decoding control: %v)", addr, err)
    35  	}
    36  
    37  	var strs []string
    38  
    39  	for i := 0; i < len(buf); {
    40  		if i+abi.SizeOfControlMessageHeader > len(buf) {
    41  			strs = append(strs, "{invalid control message (too short)}")
    42  			break
    43  		}
    44  
    45  		var h abi.ControlMessageHeader
    46  		binary.Unmarshal(buf[i:i+abi.SizeOfControlMessageHeader], ubinary.NativeEndian, &h)
    47  
    48  		var skipData bool
    49  		level := "SOL_SOCKET"
    50  		if h.Level != unix.SOL_SOCKET {
    51  			skipData = true
    52  			level = fmt.Sprint(h.Level)
    53  		}
    54  
    55  		typ, ok := abi.ControlMessageType[h.Type]
    56  		if !ok {
    57  			skipData = true
    58  			typ = fmt.Sprint(h.Type)
    59  		}
    60  
    61  		if h.Length > uint64(len(buf)-i) {
    62  			strs = append(strs, fmt.Sprintf(
    63  				"{level=%s, type=%s, length=%d, content extends beyond buffer}",
    64  				level,
    65  				typ,
    66  				h.Length,
    67  			))
    68  			break
    69  		}
    70  
    71  		i += abi.SizeOfControlMessageHeader
    72  		// TODO: uh, what
    73  		width := archWidth
    74  		length := int(h.Length) - abi.SizeOfControlMessageHeader
    75  
    76  		if skipData {
    77  			strs = append(strs, fmt.Sprintf("{level=%s, type=%s, length=%d}", level, typ, h.Length))
    78  			i += alignUp(length, uint(width))
    79  			continue
    80  		}
    81  
    82  		switch h.Type {
    83  		case unix.SCM_RIGHTS:
    84  			rightsSize := alignDown(length, abi.SizeOfControlMessageRight)
    85  
    86  			numRights := rightsSize / abi.SizeOfControlMessageRight
    87  			fds := make(abi.ControlMessageRights, numRights)
    88  			binary.Unmarshal(buf[i:i+rightsSize], ubinary.NativeEndian, &fds)
    89  
    90  			rights := make([]string, 0, len(fds))
    91  			for _, fd := range fds {
    92  				rights = append(rights, fmt.Sprint(fd))
    93  			}
    94  
    95  			strs = append(strs, fmt.Sprintf(
    96  				"{level=%s, type=%s, length=%d, content: %s}",
    97  				level,
    98  				typ,
    99  				h.Length,
   100  				strings.Join(rights, ","),
   101  			))
   102  
   103  		case unix.SCM_CREDENTIALS:
   104  			if length < abi.SizeOfControlMessageCredentials {
   105  				strs = append(strs, fmt.Sprintf(
   106  					"{level=%s, type=%s, length=%d, content too short}",
   107  					level,
   108  					typ,
   109  					h.Length,
   110  				))
   111  				break
   112  			}
   113  
   114  			var creds abi.ControlMessageCredentials
   115  			binary.Unmarshal(buf[i:i+abi.SizeOfControlMessageCredentials], binary.LittleEndian, &creds)
   116  
   117  			strs = append(strs, fmt.Sprintf(
   118  				"{level=%s, type=%s, length=%d, pid: %d, uid: %d, gid: %d}",
   119  				level,
   120  				typ,
   121  				h.Length,
   122  				creds.PID,
   123  				creds.UID,
   124  				creds.GID,
   125  			))
   126  
   127  		case unix.SO_TIMESTAMP:
   128  			if length < abi.SizeOfTimeval {
   129  				strs = append(strs, fmt.Sprintf(
   130  					"{level=%s, type=%s, length=%d, content too short}",
   131  					level,
   132  					typ,
   133  					h.Length,
   134  				))
   135  				break
   136  			}
   137  
   138  			var tv unix.Timeval
   139  			binary.Unmarshal(buf[i:i+abi.SizeOfTimeval], ubinary.NativeEndian, &tv)
   140  
   141  			strs = append(strs, fmt.Sprintf(
   142  				"{level=%s, type=%s, length=%d, Sec: %d, Usec: %d}",
   143  				level,
   144  				typ,
   145  				h.Length,
   146  				tv.Sec,
   147  				tv.Usec,
   148  			))
   149  
   150  		default:
   151  			panic("unreachable")
   152  		}
   153  		i += alignUp(length, uint(width))
   154  	}
   155  
   156  	return fmt.Sprintf("%#x %s", addr, strings.Join(strs, ", "))
   157  }
   158  
   159  func msghdr(t Task, addr Addr, printContent bool, maxBytes uint64) string {
   160  	var msg abi.MessageHeader64
   161  	if _, err := t.Read(addr, &msg); err != nil {
   162  		return fmt.Sprintf("%#x (error decoding msghdr: %v)", addr, err)
   163  	}
   164  
   165  	s := fmt.Sprintf(
   166  		"%#x {name=%#x, namelen=%d, iovecs=%s",
   167  		addr,
   168  		msg.Name,
   169  		msg.NameLen,
   170  		iovecs(t, Addr(msg.Iov), int(msg.IovLen), printContent, maxBytes),
   171  	)
   172  	if printContent {
   173  		s = fmt.Sprintf("%s, control={%s}", s, cmsghdr(t, Addr(msg.Control), msg.ControlLen, maxBytes))
   174  	} else {
   175  		s = fmt.Sprintf("%s, control=%#x, control_len=%d", s, msg.Control, msg.ControlLen)
   176  	}
   177  	return fmt.Sprintf("%s, flags=%d}", s, msg.Flags)
   178  }
   179  
   180  func sockAddr(t Task, addr Addr, length uint32) string {
   181  	if addr == 0 {
   182  		return "null"
   183  	}
   184  
   185  	b, err := CaptureAddress(t, addr, length)
   186  	if err != nil {
   187  		return fmt.Sprintf("%#x {error reading address: %v}", addr, err)
   188  	}
   189  
   190  	// Extract address family.
   191  	if len(b) < 2 {
   192  		return fmt.Sprintf("%#x {address too short: %d bytes}", addr, len(b))
   193  	}
   194  	family := ubinary.NativeEndian.Uint16(b)
   195  
   196  	familyStr := abi.SocketFamily.Parse(uint64(family))
   197  
   198  	switch family {
   199  	case unix.AF_INET, unix.AF_INET6, unix.AF_UNIX:
   200  		fa, err := GetAddress(t, b)
   201  		if err != nil {
   202  			return fmt.Sprintf("%#x {Family: %s, error extracting address: %v}", addr, familyStr, err)
   203  		}
   204  
   205  		if family == unix.AF_UNIX {
   206  			return fmt.Sprintf("%#x {Family: %s, Addr: %q}", addr, familyStr, fa.Addr)
   207  		}
   208  
   209  		return fmt.Sprintf("%#x {Family: %s, Addr: %#02x, Port: %d}", addr, familyStr, []byte(fa.Addr), fa.Port)
   210  	case unix.AF_NETLINK:
   211  		//sa, err := netlink.ExtractSockAddr(b)
   212  		//if err != nil {
   213  		return fmt.Sprintf("%#x {Family: %s, error extracting address: %v}", addr, familyStr, err)
   214  		//}
   215  		//return fmt.Sprintf("%#x {Family: %s, PortID: %d, Groups: %d}", addr, familyStr, sa.PortID, sa.Groups)
   216  	default:
   217  		return fmt.Sprintf("%#x {Family: %s, family addr format unknown}", addr, familyStr)
   218  	}
   219  }
   220  
   221  func postSockAddr(t Task, addr Addr, lengthPtr Addr) string {
   222  	if addr == 0 {
   223  		return "null"
   224  	}
   225  
   226  	if lengthPtr == 0 {
   227  		return fmt.Sprintf("%#x {length null}", addr)
   228  	}
   229  
   230  	l, err := copySockLen(t, lengthPtr)
   231  	if err != nil {
   232  		return fmt.Sprintf("%#x {error reading length: %v}", addr, err)
   233  	}
   234  
   235  	return sockAddr(t, addr, l)
   236  }
   237  
   238  func copySockLen(t Task, addr Addr) (uint32, error) {
   239  	// socklen_t is 32-bits.
   240  	var l uint32
   241  	_, err := t.Read(addr, &l)
   242  	return l, err
   243  }
   244  
   245  func sockLenPointer(t Task, addr Addr) string {
   246  	if addr == 0 {
   247  		return "null"
   248  	}
   249  	l, err := copySockLen(t, addr)
   250  	if err != nil {
   251  		return fmt.Sprintf("%#x {error reading length: %v}", addr, err)
   252  	}
   253  	return fmt.Sprintf("%#x {length=%v}", addr, l)
   254  }