github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/proc/net.go (about)

     1  // Copyright 2018 The gVisor Authors.
     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 proc
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  	"io"
    21  	"reflect"
    22  	"time"
    23  
    24  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    25  	"github.com/SagerNet/gvisor/pkg/context"
    26  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    27  	"github.com/SagerNet/gvisor/pkg/hostarch"
    28  	"github.com/SagerNet/gvisor/pkg/log"
    29  	"github.com/SagerNet/gvisor/pkg/sentry/fs"
    30  	"github.com/SagerNet/gvisor/pkg/sentry/fs/proc/seqfile"
    31  	"github.com/SagerNet/gvisor/pkg/sentry/fs/ramfs"
    32  	"github.com/SagerNet/gvisor/pkg/sentry/inet"
    33  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    34  	"github.com/SagerNet/gvisor/pkg/sentry/kernel/auth"
    35  	"github.com/SagerNet/gvisor/pkg/sentry/socket"
    36  	"github.com/SagerNet/gvisor/pkg/sentry/socket/unix"
    37  	"github.com/SagerNet/gvisor/pkg/sentry/socket/unix/transport"
    38  	"github.com/SagerNet/gvisor/pkg/tcpip/header"
    39  )
    40  
    41  // LINT.IfChange
    42  
    43  // newNetDir creates a new proc net entry.
    44  func newNetDir(ctx context.Context, t *kernel.Task, msrc *fs.MountSource) *fs.Inode {
    45  	k := t.Kernel()
    46  
    47  	var contents map[string]*fs.Inode
    48  	if s := t.NetworkNamespace().Stack(); s != nil {
    49  		// TODO(github.com/SagerNet/issue/1833): Make sure file contents reflect the task
    50  		// network namespace.
    51  		contents = map[string]*fs.Inode{
    52  			"dev":  seqfile.NewSeqFileInode(ctx, &netDev{s: s}, msrc),
    53  			"snmp": seqfile.NewSeqFileInode(ctx, &netSnmp{s: s}, msrc),
    54  
    55  			// The following files are simple stubs until they are
    56  			// implemented in netstack, if the file contains a
    57  			// header the stub is just the header otherwise it is
    58  			// an empty file.
    59  			"arp": newStaticProcInode(ctx, msrc, []byte("IP address       HW type     Flags       HW address            Mask     Device\n")),
    60  
    61  			"netlink":   newStaticProcInode(ctx, msrc, []byte("sk       Eth Pid    Groups   Rmem     Wmem     Dump     Locks     Drops     Inode\n")),
    62  			"netstat":   newStaticProcInode(ctx, msrc, []byte("TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed EmbryonicRsts PruneCalled RcvPruned OfoPruned OutOfWindowIcmps LockDroppedIcmps ArpFilter TW TWRecycled TWKilled PAWSPassive PAWSActive PAWSEstab DelayedACKs DelayedACKLocked DelayedACKLost ListenOverflows ListenDrops TCPPrequeued TCPDirectCopyFromBacklog TCPDirectCopyFromPrequeue TCPPrequeueDropped TCPHPHits TCPHPHitsToUser TCPPureAcks TCPHPAcks TCPRenoRecovery TCPSackRecovery TCPSACKReneging TCPFACKReorder TCPSACKReorder TCPRenoReorder TCPTSReorder TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo TCPLostRetransmit TCPRenoFailures TCPSackFailures TCPLossFailures TCPFastRetrans TCPForwardRetrans TCPSlowStartRetrans TCPTimeouts TCPLossProbes TCPLossProbeRecovery TCPRenoRecoveryFail TCPSackRecoveryFail TCPSchedulerFailed TCPRcvCollapsed TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv TCPAbortOnData TCPAbortOnClose TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger TCPAbortFailed TCPMemoryPressures TCPSACKDiscard TCPDSACKIgnoredOld TCPDSACKIgnoredNoUndo TCPSpuriousRTOs TCPMD5NotFound TCPMD5Unexpected TCPMD5Failure TCPSackShifted TCPSackMerged TCPSackShiftFallback TCPBacklogDrop TCPMinTTLDrop TCPDeferAcceptDrop IPReversePathFilter TCPTimeWaitOverflow TCPReqQFullDoCookies TCPReqQFullDrop TCPRetransFail TCPRcvCoalesce TCPOFOQueue TCPOFODrop TCPOFOMerge TCPChallengeACK TCPSYNChallenge TCPFastOpenActive TCPFastOpenActiveFail TCPFastOpenPassive TCPFastOpenPassiveFail TCPFastOpenListenOverflow TCPFastOpenCookieReqd TCPSpuriousRtxHostQueues BusyPollRxPackets TCPAutoCorking TCPFromZeroWindowAdv TCPToZeroWindowAdv TCPWantZeroWindowAdv TCPSynRetrans TCPOrigDataSent TCPHystartTrainDetect TCPHystartTrainCwnd TCPHystartDelayDetect TCPHystartDelayCwnd TCPACKSkippedSynRecv TCPACKSkippedPAWS TCPACKSkippedSeq TCPACKSkippedFinWait2 TCPACKSkippedTimeWait TCPACKSkippedChallenge TCPWinProbe TCPKeepAlive TCPMTUPFail TCPMTUPSuccess\n")),
    63  			"packet":    newStaticProcInode(ctx, msrc, []byte("sk       RefCnt Type Proto  Iface R Rmem   User   Inode\n")),
    64  			"protocols": newStaticProcInode(ctx, msrc, []byte("protocol  size sockets  memory press maxhdr  slab module     cl co di ac io in de sh ss gs se re sp bi br ha uh gp em\n")),
    65  			// Linux sets psched values to: nsec per usec, psched
    66  			// tick in ns, 1000000, high res timer ticks per sec
    67  			// (ClockGetres returns 1ns resolution).
    68  			"psched": newStaticProcInode(ctx, msrc, []byte(fmt.Sprintf("%08x %08x %08x %08x\n", uint64(time.Microsecond/time.Nanosecond), 64, 1000000, uint64(time.Second/time.Nanosecond)))),
    69  			"ptype":  newStaticProcInode(ctx, msrc, []byte("Type Device      Function\n")),
    70  			"route":  seqfile.NewSeqFileInode(ctx, &netRoute{s: s}, msrc),
    71  			"tcp":    seqfile.NewSeqFileInode(ctx, &netTCP{k: k}, msrc),
    72  			"udp":    seqfile.NewSeqFileInode(ctx, &netUDP{k: k}, msrc),
    73  			"unix":   seqfile.NewSeqFileInode(ctx, &netUnix{k: k}, msrc),
    74  		}
    75  
    76  		if s.SupportsIPv6() {
    77  			contents["if_inet6"] = seqfile.NewSeqFileInode(ctx, &ifinet6{s: s}, msrc)
    78  			contents["ipv6_route"] = newStaticProcInode(ctx, msrc, []byte(""))
    79  			contents["tcp6"] = seqfile.NewSeqFileInode(ctx, &netTCP6{k: k}, msrc)
    80  			contents["udp6"] = newStaticProcInode(ctx, msrc, []byte("  sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode\n"))
    81  		}
    82  	}
    83  	d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
    84  	return newProcInode(ctx, d, msrc, fs.SpecialDirectory, t)
    85  }
    86  
    87  // ifinet6 implements seqfile.SeqSource for /proc/net/if_inet6.
    88  //
    89  // +stateify savable
    90  type ifinet6 struct {
    91  	s inet.Stack
    92  }
    93  
    94  func (n *ifinet6) contents() []string {
    95  	var lines []string
    96  	nics := n.s.Interfaces()
    97  	for id, naddrs := range n.s.InterfaceAddrs() {
    98  		nic, ok := nics[id]
    99  		if !ok {
   100  			// NIC was added after NICNames was called. We'll just
   101  			// ignore it.
   102  			continue
   103  		}
   104  
   105  		for _, a := range naddrs {
   106  			// IPv6 only.
   107  			if a.Family != linux.AF_INET6 {
   108  				continue
   109  			}
   110  
   111  			// Fields:
   112  			// IPv6 address displayed in 32 hexadecimal chars without colons
   113  			// Netlink device number (interface index) in hexadecimal (use nic id)
   114  			// Prefix length in hexadecimal
   115  			// Scope value (use 0)
   116  			// Interface flags
   117  			// Device name
   118  			lines = append(lines, fmt.Sprintf("%032x %02x %02x %02x %02x %8s\n", a.Addr, id, a.PrefixLen, 0, a.Flags, nic.Name))
   119  		}
   120  	}
   121  	return lines
   122  }
   123  
   124  // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate.
   125  func (*ifinet6) NeedsUpdate(generation int64) bool {
   126  	return true
   127  }
   128  
   129  // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
   130  func (n *ifinet6) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
   131  	contents := n.contents()
   132  	minI := 0
   133  	if h != nil {
   134  		minI = h.(int) + 1
   135  		if minI > len(contents) {
   136  			minI = len(contents)
   137  		}
   138  	}
   139  	var data []seqfile.SeqData
   140  	for i, l := range contents[minI:] {
   141  		data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI})
   142  	}
   143  
   144  	return data, 0
   145  }
   146  
   147  // netDev implements seqfile.SeqSource for /proc/net/dev.
   148  //
   149  // +stateify savable
   150  type netDev struct {
   151  	s inet.Stack
   152  }
   153  
   154  // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate.
   155  func (n *netDev) NeedsUpdate(generation int64) bool {
   156  	return true
   157  }
   158  
   159  // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. See Linux's
   160  // net/core/net-procfs.c:dev_seq_show.
   161  func (n *netDev) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
   162  	interfaces := n.s.Interfaces()
   163  	contents := make([]string, 2, 2+len(interfaces))
   164  	// Add the table header. From net/core/net-procfs.c:dev_seq_show.
   165  	contents[0] = "Inter-|   Receive                                                |  Transmit\n"
   166  	contents[1] = " face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n"
   167  
   168  	for _, i := range interfaces {
   169  		// Implements the same format as
   170  		// net/core/net-procfs.c:dev_seq_printf_stats.
   171  		var stats inet.StatDev
   172  		if err := n.s.Statistics(&stats, i.Name); err != nil {
   173  			log.Warningf("Failed to retrieve interface statistics for %v: %v", i.Name, err)
   174  			continue
   175  		}
   176  		l := fmt.Sprintf(
   177  			"%6s: %7d %7d %4d %4d %4d %5d %10d %9d %8d %7d %4d %4d %4d %5d %7d %10d\n",
   178  			i.Name,
   179  			// Received
   180  			stats[0], // bytes
   181  			stats[1], // packets
   182  			stats[2], // errors
   183  			stats[3], // dropped
   184  			stats[4], // fifo
   185  			stats[5], // frame
   186  			stats[6], // compressed
   187  			stats[7], // multicast
   188  			// Transmitted
   189  			stats[8],  // bytes
   190  			stats[9],  // packets
   191  			stats[10], // errors
   192  			stats[11], // dropped
   193  			stats[12], // fifo
   194  			stats[13], // frame
   195  			stats[14], // compressed
   196  			stats[15]) // multicast
   197  		contents = append(contents, l)
   198  	}
   199  
   200  	minI := 0
   201  	if h != nil {
   202  		minI = h.(int) + 1
   203  		if minI > len(contents) {
   204  			minI = len(contents)
   205  		}
   206  	}
   207  	var data []seqfile.SeqData
   208  	for i, l := range contents[minI:] {
   209  		data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI})
   210  	}
   211  
   212  	return data, 0
   213  }
   214  
   215  // netSnmp implements seqfile.SeqSource for /proc/net/snmp.
   216  //
   217  // +stateify savable
   218  type netSnmp struct {
   219  	s inet.Stack
   220  }
   221  
   222  // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate.
   223  func (n *netSnmp) NeedsUpdate(generation int64) bool {
   224  	return true
   225  }
   226  
   227  type snmpLine struct {
   228  	prefix string
   229  	header string
   230  }
   231  
   232  var snmp = []snmpLine{
   233  	{
   234  		prefix: "Ip",
   235  		header: "Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates",
   236  	},
   237  	{
   238  		prefix: "Icmp",
   239  		header: "InMsgs InErrors InCsumErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps",
   240  	},
   241  	{
   242  		prefix: "IcmpMsg",
   243  	},
   244  	{
   245  		prefix: "Tcp",
   246  		header: "RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts InCsumErrors",
   247  	},
   248  	{
   249  		prefix: "Udp",
   250  		header: "InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti",
   251  	},
   252  	{
   253  		prefix: "UdpLite",
   254  		header: "InDatagrams NoPorts InErrors OutDatagrams RcvbufErrors SndbufErrors InCsumErrors IgnoredMulti",
   255  	},
   256  }
   257  
   258  func toSlice(a interface{}) []uint64 {
   259  	v := reflect.Indirect(reflect.ValueOf(a))
   260  	return v.Slice(0, v.Len()).Interface().([]uint64)
   261  }
   262  
   263  func sprintSlice(s []uint64) string {
   264  	if len(s) == 0 {
   265  		return ""
   266  	}
   267  	r := fmt.Sprint(s)
   268  	return r[1 : len(r)-1] // Remove "[]" introduced by fmt of slice.
   269  }
   270  
   271  // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData. See Linux's
   272  // net/core/net-procfs.c:dev_seq_show.
   273  func (n *netSnmp) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
   274  	contents := make([]string, 0, len(snmp)*2)
   275  	types := []interface{}{
   276  		&inet.StatSNMPIP{},
   277  		&inet.StatSNMPICMP{},
   278  		nil, // TODO(github.com/SagerNet/issue/628): Support IcmpMsg stats.
   279  		&inet.StatSNMPTCP{},
   280  		&inet.StatSNMPUDP{},
   281  		&inet.StatSNMPUDPLite{},
   282  	}
   283  	for i, stat := range types {
   284  		line := snmp[i]
   285  		if stat == nil {
   286  			contents = append(
   287  				contents,
   288  				fmt.Sprintf("%s:\n", line.prefix),
   289  				fmt.Sprintf("%s:\n", line.prefix),
   290  			)
   291  			continue
   292  		}
   293  		if err := n.s.Statistics(stat, line.prefix); err != nil {
   294  			if linuxerr.Equals(linuxerr.EOPNOTSUPP, err) {
   295  				log.Infof("Failed to retrieve %s of /proc/net/snmp: %v", line.prefix, err)
   296  			} else {
   297  				log.Warningf("Failed to retrieve %s of /proc/net/snmp: %v", line.prefix, err)
   298  			}
   299  		}
   300  		var values string
   301  		if line.prefix == "Tcp" {
   302  			tcp := stat.(*inet.StatSNMPTCP)
   303  			// "Tcp" needs special processing because MaxConn is signed. RFC 2012.
   304  			values = fmt.Sprintf("%s %d %s", sprintSlice(tcp[:3]), int64(tcp[3]), sprintSlice(tcp[4:]))
   305  		} else {
   306  			values = sprintSlice(toSlice(stat))
   307  		}
   308  		contents = append(
   309  			contents,
   310  			fmt.Sprintf("%s: %s\n", line.prefix, line.header),
   311  			fmt.Sprintf("%s: %s\n", line.prefix, values),
   312  		)
   313  	}
   314  
   315  	minI := 0
   316  	if h != nil {
   317  		minI = h.(int) + 1
   318  		if minI > len(contents) {
   319  			minI = len(contents)
   320  		}
   321  	}
   322  	data := make([]seqfile.SeqData, 0, len(snmp)*2)
   323  	for i, l := range contents[minI:] {
   324  		data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI})
   325  	}
   326  
   327  	return data, 0
   328  }
   329  
   330  // netRoute implements seqfile.SeqSource for /proc/net/route.
   331  //
   332  // +stateify savable
   333  type netRoute struct {
   334  	s inet.Stack
   335  }
   336  
   337  // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate.
   338  func (n *netRoute) NeedsUpdate(generation int64) bool {
   339  	return true
   340  }
   341  
   342  // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
   343  // See Linux's net/ipv4/fib_trie.c:fib_route_seq_show.
   344  func (n *netRoute) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
   345  	interfaces := n.s.Interfaces()
   346  	contents := []string{"Iface\tDestination\tGateway\tFlags\tRefCnt\tUse\tMetric\tMask\tMTU\tWindow\tIRTT"}
   347  	for _, rt := range n.s.RouteTable() {
   348  		// /proc/net/route only includes ipv4 routes.
   349  		if rt.Family != linux.AF_INET {
   350  			continue
   351  		}
   352  
   353  		// /proc/net/route does not include broadcast or multicast routes.
   354  		if rt.Type == linux.RTN_BROADCAST || rt.Type == linux.RTN_MULTICAST {
   355  			continue
   356  		}
   357  
   358  		iface, ok := interfaces[rt.OutputInterface]
   359  		if !ok || iface.Name == "lo" {
   360  			continue
   361  		}
   362  
   363  		var (
   364  			gw     uint32
   365  			prefix uint32
   366  			flags  = linux.RTF_UP
   367  		)
   368  		if len(rt.GatewayAddr) == header.IPv4AddressSize {
   369  			flags |= linux.RTF_GATEWAY
   370  			gw = hostarch.ByteOrder.Uint32(rt.GatewayAddr)
   371  		}
   372  		if len(rt.DstAddr) == header.IPv4AddressSize {
   373  			prefix = hostarch.ByteOrder.Uint32(rt.DstAddr)
   374  		}
   375  		l := fmt.Sprintf(
   376  			"%s\t%08X\t%08X\t%04X\t%d\t%d\t%d\t%08X\t%d\t%d\t%d",
   377  			iface.Name,
   378  			prefix,
   379  			gw,
   380  			flags,
   381  			0, // RefCnt.
   382  			0, // Use.
   383  			0, // Metric.
   384  			(uint32(1)<<rt.DstLen)-1,
   385  			0, // MTU.
   386  			0, // Window.
   387  			0, // RTT.
   388  		)
   389  		contents = append(contents, l)
   390  	}
   391  
   392  	minI := 0
   393  	if h != nil {
   394  		minI = h.(int) + 1
   395  		if minI > len(contents) {
   396  			minI = len(contents)
   397  		}
   398  	}
   399  	var data []seqfile.SeqData
   400  	for i, l := range contents[minI:] {
   401  		l = fmt.Sprintf("%-127s\n", l)
   402  		data = append(data, seqfile.SeqData{Buf: []byte(l), Handle: i + minI})
   403  	}
   404  
   405  	return data, 0
   406  }
   407  
   408  // netUnix implements seqfile.SeqSource for /proc/net/unix.
   409  //
   410  // +stateify savable
   411  type netUnix struct {
   412  	k *kernel.Kernel
   413  }
   414  
   415  // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate.
   416  func (*netUnix) NeedsUpdate(generation int64) bool {
   417  	return true
   418  }
   419  
   420  // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
   421  func (n *netUnix) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
   422  	var buf bytes.Buffer
   423  	for _, se := range n.k.ListSockets() {
   424  		s := se.Sock.Get()
   425  		if s == nil {
   426  			log.Debugf("Couldn't resolve weakref with ID %v in socket table, racing with destruction?", se.ID)
   427  			continue
   428  		}
   429  		sfile := s.(*fs.File)
   430  		if family, _, _ := sfile.FileOperations.(socket.Socket).Type(); family != linux.AF_UNIX {
   431  			s.DecRef(ctx)
   432  			// Not a unix socket.
   433  			continue
   434  		}
   435  		sops := sfile.FileOperations.(*unix.SocketOperations)
   436  
   437  		addr, err := sops.Endpoint().GetLocalAddress()
   438  		if err != nil {
   439  			log.Warningf("Failed to retrieve socket name from %+v: %v", sfile, err)
   440  			addr.Addr = "<unknown>"
   441  		}
   442  
   443  		sockFlags := 0
   444  		if ce, ok := sops.Endpoint().(transport.ConnectingEndpoint); ok {
   445  			if ce.Listening() {
   446  				// For unix domain sockets, linux reports a single flag
   447  				// value if the socket is listening, of __SO_ACCEPTCON.
   448  				sockFlags = linux.SO_ACCEPTCON
   449  			}
   450  		}
   451  
   452  		// In the socket entry below, the value for the 'Num' field requires
   453  		// some consideration. Linux prints the address to the struct
   454  		// unix_sock representing a socket in the kernel, but may redact the
   455  		// value for unprivileged users depending on the kptr_restrict
   456  		// sysctl.
   457  		//
   458  		// One use for this field is to allow a privileged user to
   459  		// introspect into the kernel memory to determine information about
   460  		// a socket not available through procfs, such as the socket's peer.
   461  		//
   462  		// On gvisor, returning a pointer to our internal structures would
   463  		// be pointless, as it wouldn't match the memory layout for struct
   464  		// unix_sock, making introspection difficult. We could populate a
   465  		// struct unix_sock with the appropriate data, but even that
   466  		// requires consideration for which kernel version to emulate, as
   467  		// the definition of this struct changes over time.
   468  		//
   469  		// For now, we always redact this pointer.
   470  		fmt.Fprintf(&buf, "%#016p: %08X %08X %08X %04X %02X %5d",
   471  			(*unix.SocketOperations)(nil), // Num, pointer to kernel socket struct.
   472  			sfile.ReadRefs()-1,            // RefCount, don't count our own ref.
   473  			0,                             // Protocol, always 0 for UDS.
   474  			sockFlags,                     // Flags.
   475  			sops.Endpoint().Type(),        // Type.
   476  			sops.State(),                  // State.
   477  			sfile.InodeID(),               // Inode.
   478  		)
   479  
   480  		// Path
   481  		if len(addr.Addr) != 0 {
   482  			if addr.Addr[0] == 0 {
   483  				// Abstract path.
   484  				fmt.Fprintf(&buf, " @%s", string(addr.Addr[1:]))
   485  			} else {
   486  				fmt.Fprintf(&buf, " %s", string(addr.Addr))
   487  			}
   488  		}
   489  		fmt.Fprintf(&buf, "\n")
   490  
   491  		s.DecRef(ctx)
   492  	}
   493  
   494  	minI := 0
   495  	if h != nil {
   496  		minI = h.(int) + 1
   497  	}
   498  	var data []seqfile.SeqData
   499  	if minI <= 0 {
   500  		data = append(data, seqfile.SeqData{
   501  			Buf:    []byte("Num       RefCount Protocol Flags    Type St Inode Path\n"),
   502  			Handle: 0,
   503  		})
   504  	}
   505  	if minI <= 1 {
   506  		data = append(data, seqfile.SeqData{
   507  			Buf:    buf.Bytes(),
   508  			Handle: 1,
   509  		})
   510  	}
   511  	return data, 0
   512  }
   513  
   514  func networkToHost16(n uint16) uint16 {
   515  	// n is in network byte order, so is big-endian. The most-significant byte
   516  	// should be stored in the lower address.
   517  	//
   518  	// We manually inline binary.BigEndian.Uint16() because Go does not support
   519  	// non-primitive consts, so binary.BigEndian is a (mutable) var, so calls to
   520  	// binary.BigEndian.Uint16() require a read of binary.BigEndian and an
   521  	// interface method call, defeating inlining.
   522  	buf := [2]byte{byte(n >> 8 & 0xff), byte(n & 0xff)}
   523  	return hostarch.ByteOrder.Uint16(buf[:])
   524  }
   525  
   526  func writeInetAddr(w io.Writer, family int, i linux.SockAddr) {
   527  	switch family {
   528  	case linux.AF_INET:
   529  		var a linux.SockAddrInet
   530  		if i != nil {
   531  			a = *i.(*linux.SockAddrInet)
   532  		}
   533  
   534  		// linux.SockAddrInet.Port is stored in the network byte order and is
   535  		// printed like a number in host byte order. Note that all numbers in host
   536  		// byte order are printed with the most-significant byte first when
   537  		// formatted with %X. See get_tcp4_sock() and udp4_format_sock() in Linux.
   538  		port := networkToHost16(a.Port)
   539  
   540  		// linux.SockAddrInet.Addr is stored as a byte slice in big-endian order
   541  		// (i.e. most-significant byte in index 0). Linux represents this as a
   542  		// __be32 which is a typedef for an unsigned int, and is printed with
   543  		// %X. This means that for a little-endian machine, Linux prints the
   544  		// least-significant byte of the address first. To emulate this, we first
   545  		// invert the byte order for the address using hostarch.ByteOrder.Uint32,
   546  		// which makes it have the equivalent encoding to a __be32 on a little
   547  		// endian machine. Note that this operation is a no-op on a big endian
   548  		// machine. Then similar to Linux, we format it with %X, which will print
   549  		// the most-significant byte of the __be32 address first, which is now
   550  		// actually the least-significant byte of the original address in
   551  		// linux.SockAddrInet.Addr on little endian machines, due to the conversion.
   552  		addr := hostarch.ByteOrder.Uint32(a.Addr[:])
   553  
   554  		fmt.Fprintf(w, "%08X:%04X ", addr, port)
   555  	case linux.AF_INET6:
   556  		var a linux.SockAddrInet6
   557  		if i != nil {
   558  			a = *i.(*linux.SockAddrInet6)
   559  		}
   560  
   561  		port := networkToHost16(a.Port)
   562  		addr0 := hostarch.ByteOrder.Uint32(a.Addr[0:4])
   563  		addr1 := hostarch.ByteOrder.Uint32(a.Addr[4:8])
   564  		addr2 := hostarch.ByteOrder.Uint32(a.Addr[8:12])
   565  		addr3 := hostarch.ByteOrder.Uint32(a.Addr[12:16])
   566  		fmt.Fprintf(w, "%08X%08X%08X%08X:%04X ", addr0, addr1, addr2, addr3, port)
   567  	}
   568  }
   569  
   570  func commonReadSeqFileDataTCP(ctx context.Context, n seqfile.SeqHandle, k *kernel.Kernel, h seqfile.SeqHandle, fa int, header []byte) ([]seqfile.SeqData, int64) {
   571  	// t may be nil here if our caller is not part of a task goroutine. This can
   572  	// happen for example if we're here for "sentryctl cat". When t is nil,
   573  	// degrade gracefully and retrieve what we can.
   574  	t := kernel.TaskFromContext(ctx)
   575  
   576  	var buf bytes.Buffer
   577  	for _, se := range k.ListSockets() {
   578  		s := se.Sock.Get()
   579  		if s == nil {
   580  			log.Debugf("Couldn't resolve weakref with ID %v in socket table, racing with destruction?", se.ID)
   581  			continue
   582  		}
   583  		sfile := s.(*fs.File)
   584  		sops, ok := sfile.FileOperations.(socket.Socket)
   585  		if !ok {
   586  			panic(fmt.Sprintf("Found non-socket file in socket table: %+v", sfile))
   587  		}
   588  		if family, stype, _ := sops.Type(); !(family == fa && stype == linux.SOCK_STREAM) {
   589  			s.DecRef(ctx)
   590  			// Not tcp4 sockets.
   591  			continue
   592  		}
   593  
   594  		// Linux's documentation for the fields below can be found at
   595  		// https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt.
   596  		// For Linux's implementation, see net/ipv4/tcp_ipv4.c:get_tcp4_sock().
   597  		// Note that the header doesn't contain labels for all the fields.
   598  
   599  		// Field: sl; entry number.
   600  		fmt.Fprintf(&buf, "%4d: ", se.ID)
   601  
   602  		// Field: local_adddress.
   603  		var localAddr linux.SockAddr
   604  		if t != nil {
   605  			if local, _, err := sops.GetSockName(t); err == nil {
   606  				localAddr = local
   607  			}
   608  		}
   609  		writeInetAddr(&buf, fa, localAddr)
   610  
   611  		// Field: rem_address.
   612  		var remoteAddr linux.SockAddr
   613  		if t != nil {
   614  			if remote, _, err := sops.GetPeerName(t); err == nil {
   615  				remoteAddr = remote
   616  			}
   617  		}
   618  		writeInetAddr(&buf, fa, remoteAddr)
   619  
   620  		// Field: state; socket state.
   621  		fmt.Fprintf(&buf, "%02X ", sops.State())
   622  
   623  		// Field: tx_queue, rx_queue; number of packets in the transmit and
   624  		// receive queue. Unimplemented.
   625  		fmt.Fprintf(&buf, "%08X:%08X ", 0, 0)
   626  
   627  		// Field: tr, tm->when; timer active state and number of jiffies
   628  		// until timer expires. Unimplemented.
   629  		fmt.Fprintf(&buf, "%02X:%08X ", 0, 0)
   630  
   631  		// Field: retrnsmt; number of unrecovered RTO timeouts.
   632  		// Unimplemented.
   633  		fmt.Fprintf(&buf, "%08X ", 0)
   634  
   635  		// Field: uid.
   636  		uattr, err := sfile.Dirent.Inode.UnstableAttr(ctx)
   637  		if err != nil {
   638  			log.Warningf("Failed to retrieve unstable attr for socket file: %v", err)
   639  			fmt.Fprintf(&buf, "%5d ", 0)
   640  		} else {
   641  			creds := auth.CredentialsFromContext(ctx)
   642  			fmt.Fprintf(&buf, "%5d ", uint32(uattr.Owner.UID.In(creds.UserNamespace).OrOverflow()))
   643  		}
   644  
   645  		// Field: timeout; number of unanswered 0-window probes.
   646  		// Unimplemented.
   647  		fmt.Fprintf(&buf, "%8d ", 0)
   648  
   649  		// Field: inode.
   650  		fmt.Fprintf(&buf, "%8d ", sfile.InodeID())
   651  
   652  		// Field: refcount. Don't count the ref we obtain while deferencing
   653  		// the weakref to this socket.
   654  		fmt.Fprintf(&buf, "%d ", sfile.ReadRefs()-1)
   655  
   656  		// Field: Socket struct address. Redacted due to the same reason as
   657  		// the 'Num' field in /proc/net/unix, see netUnix.ReadSeqFileData.
   658  		fmt.Fprintf(&buf, "%#016p ", (*socket.Socket)(nil))
   659  
   660  		// Field: retransmit timeout. Unimplemented.
   661  		fmt.Fprintf(&buf, "%d ", 0)
   662  
   663  		// Field: predicted tick of soft clock (delayed ACK control data).
   664  		// Unimplemented.
   665  		fmt.Fprintf(&buf, "%d ", 0)
   666  
   667  		// Field: (ack.quick<<1)|ack.pingpong, Unimplemented.
   668  		fmt.Fprintf(&buf, "%d ", 0)
   669  
   670  		// Field: sending congestion window, Unimplemented.
   671  		fmt.Fprintf(&buf, "%d ", 0)
   672  
   673  		// Field: Slow start size threshold, -1 if threshold >= 0xFFFF.
   674  		// Unimplemented, report as large threshold.
   675  		fmt.Fprintf(&buf, "%d", -1)
   676  
   677  		fmt.Fprintf(&buf, "\n")
   678  
   679  		s.DecRef(ctx)
   680  	}
   681  
   682  	minI := 0
   683  	if h != nil {
   684  		minI = h.(int) + 1
   685  	}
   686  	var data []seqfile.SeqData
   687  	if minI <= 0 {
   688  		data = append(data, seqfile.SeqData{
   689  			Buf:    header,
   690  			Handle: 0,
   691  		})
   692  	}
   693  	if minI <= 1 {
   694  		data = append(data, seqfile.SeqData{
   695  			Buf:    buf.Bytes(),
   696  			Handle: 1,
   697  		})
   698  	}
   699  	return data, 0
   700  }
   701  
   702  // netTCP implements seqfile.SeqSource for /proc/net/tcp.
   703  //
   704  // +stateify savable
   705  type netTCP struct {
   706  	k *kernel.Kernel
   707  }
   708  
   709  // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate.
   710  func (*netTCP) NeedsUpdate(generation int64) bool {
   711  	return true
   712  }
   713  
   714  // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
   715  func (n *netTCP) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
   716  	header := []byte("  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     \n")
   717  	return commonReadSeqFileDataTCP(ctx, n, n.k, h, linux.AF_INET, header)
   718  }
   719  
   720  // netTCP6 implements seqfile.SeqSource for /proc/net/tcp6.
   721  //
   722  // +stateify savable
   723  type netTCP6 struct {
   724  	k *kernel.Kernel
   725  }
   726  
   727  // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate.
   728  func (*netTCP6) NeedsUpdate(generation int64) bool {
   729  	return true
   730  }
   731  
   732  // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
   733  func (n *netTCP6) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
   734  	header := []byte("  sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode\n")
   735  	return commonReadSeqFileDataTCP(ctx, n, n.k, h, linux.AF_INET6, header)
   736  }
   737  
   738  // netUDP implements seqfile.SeqSource for /proc/net/udp.
   739  //
   740  // +stateify savable
   741  type netUDP struct {
   742  	k *kernel.Kernel
   743  }
   744  
   745  // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate.
   746  func (*netUDP) NeedsUpdate(generation int64) bool {
   747  	return true
   748  }
   749  
   750  // ReadSeqFileData implements seqfile.SeqSource.ReadSeqFileData.
   751  func (n *netUDP) ReadSeqFileData(ctx context.Context, h seqfile.SeqHandle) ([]seqfile.SeqData, int64) {
   752  	// t may be nil here if our caller is not part of a task goroutine. This can
   753  	// happen for example if we're here for "sentryctl cat". When t is nil,
   754  	// degrade gracefully and retrieve what we can.
   755  	t := kernel.TaskFromContext(ctx)
   756  
   757  	var buf bytes.Buffer
   758  	for _, se := range n.k.ListSockets() {
   759  		s := se.Sock.Get()
   760  		if s == nil {
   761  			log.Debugf("Couldn't resolve weakref with ID %v in socket table, racing with destruction?", se.ID)
   762  			continue
   763  		}
   764  		sfile := s.(*fs.File)
   765  		sops, ok := sfile.FileOperations.(socket.Socket)
   766  		if !ok {
   767  			panic(fmt.Sprintf("Found non-socket file in socket table: %+v", sfile))
   768  		}
   769  		if family, stype, _ := sops.Type(); family != linux.AF_INET || stype != linux.SOCK_DGRAM {
   770  			s.DecRef(ctx)
   771  			// Not udp4 socket.
   772  			continue
   773  		}
   774  
   775  		// For Linux's implementation, see net/ipv4/udp.c:udp4_format_sock().
   776  
   777  		// Field: sl; entry number.
   778  		fmt.Fprintf(&buf, "%5d: ", se.ID)
   779  
   780  		// Field: local_adddress.
   781  		var localAddr linux.SockAddrInet
   782  		if t != nil {
   783  			if local, _, err := sops.GetSockName(t); err == nil {
   784  				localAddr = *local.(*linux.SockAddrInet)
   785  			}
   786  		}
   787  		writeInetAddr(&buf, linux.AF_INET, &localAddr)
   788  
   789  		// Field: rem_address.
   790  		var remoteAddr linux.SockAddrInet
   791  		if t != nil {
   792  			if remote, _, err := sops.GetPeerName(t); err == nil {
   793  				remoteAddr = *remote.(*linux.SockAddrInet)
   794  			}
   795  		}
   796  		writeInetAddr(&buf, linux.AF_INET, &remoteAddr)
   797  
   798  		// Field: state; socket state.
   799  		fmt.Fprintf(&buf, "%02X ", sops.State())
   800  
   801  		// Field: tx_queue, rx_queue; number of packets in the transmit and
   802  		// receive queue. Unimplemented.
   803  		fmt.Fprintf(&buf, "%08X:%08X ", 0, 0)
   804  
   805  		// Field: tr, tm->when. Always 0 for UDP.
   806  		fmt.Fprintf(&buf, "%02X:%08X ", 0, 0)
   807  
   808  		// Field: retrnsmt. Always 0 for UDP.
   809  		fmt.Fprintf(&buf, "%08X ", 0)
   810  
   811  		// Field: uid.
   812  		uattr, err := sfile.Dirent.Inode.UnstableAttr(ctx)
   813  		if err != nil {
   814  			log.Warningf("Failed to retrieve unstable attr for socket file: %v", err)
   815  			fmt.Fprintf(&buf, "%5d ", 0)
   816  		} else {
   817  			creds := auth.CredentialsFromContext(ctx)
   818  			fmt.Fprintf(&buf, "%5d ", uint32(uattr.Owner.UID.In(creds.UserNamespace).OrOverflow()))
   819  		}
   820  
   821  		// Field: timeout. Always 0 for UDP.
   822  		fmt.Fprintf(&buf, "%8d ", 0)
   823  
   824  		// Field: inode.
   825  		fmt.Fprintf(&buf, "%8d ", sfile.InodeID())
   826  
   827  		// Field: ref; reference count on the socket inode. Don't count the ref
   828  		// we obtain while deferencing the weakref to this socket.
   829  		fmt.Fprintf(&buf, "%d ", sfile.ReadRefs()-1)
   830  
   831  		// Field: Socket struct address. Redacted due to the same reason as
   832  		// the 'Num' field in /proc/net/unix, see netUnix.ReadSeqFileData.
   833  		fmt.Fprintf(&buf, "%#016p ", (*socket.Socket)(nil))
   834  
   835  		// Field: drops; number of dropped packets. Unimplemented.
   836  		fmt.Fprintf(&buf, "%d", 0)
   837  
   838  		fmt.Fprintf(&buf, "\n")
   839  
   840  		s.DecRef(ctx)
   841  	}
   842  
   843  	minI := 0
   844  	if h != nil {
   845  		minI = h.(int) + 1
   846  	}
   847  	var data []seqfile.SeqData
   848  	if minI <= 0 {
   849  		data = append(data, seqfile.SeqData{
   850  			Buf:    []byte("  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode ref pointer drops             \n"),
   851  			Handle: 0,
   852  		})
   853  	}
   854  	if minI <= 1 {
   855  		data = append(data, seqfile.SeqData{
   856  			Buf:    buf.Bytes(),
   857  			Handle: 1,
   858  		})
   859  	}
   860  	return data, 0
   861  }
   862  
   863  // LINT.ThenChange(../../fsimpl/proc/task_net.go)