gitlab.com/Raven-IO/raven-delve@v1.22.4/service/internal/sameuser/sameuser_linux.go (about) 1 package sameuser 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "log" 8 "net" 9 "os" 10 "strings" 11 12 "gitlab.com/Raven-IO/raven-delve/pkg/logflags" 13 ) 14 15 // for testing 16 var ( 17 uid = os.Getuid() 18 readFile = os.ReadFile 19 ) 20 21 type errConnectionNotFound struct { 22 filename string 23 } 24 25 func (e *errConnectionNotFound) Error() string { 26 return fmt.Sprintf("connection not found in %s", e.filename) 27 } 28 29 func sameUserForHexLocalAddr(filename, localAddr, remoteAddr string) (bool, error) { 30 b, err := readFile(filename) 31 if err != nil { 32 return false, err 33 } 34 for _, line := range strings.Split(strings.TrimSpace(string(b)), "\n") { 35 // The format contains whitespace padding (%4d, %5u), so we use 36 // fmt.Sscanf instead of splitting on whitespace. 37 var ( 38 sl int 39 readLocalAddr, readRemoteAddr string 40 state int 41 queue, timer string 42 retransmit int 43 remoteUID uint 44 ) 45 // Note that we must use %d where the kernel format uses %4d or %5u: 46 // - %4d fails to parse for large number of entries (len(sl) > 4) 47 // - %u is not understood by the fmt package (%U is something else) 48 // - %5d cuts off longer uids (e.g. 149098 on gLinux) 49 n, err := fmt.Sscanf(line, "%d: %s %s %02X %s %s %08X %d", 50 &sl, &readLocalAddr, &readRemoteAddr, &state, &queue, &timer, &retransmit, &remoteUID) 51 if n != 8 || err != nil { 52 continue // invalid line (e.g. header line) 53 } 54 if readLocalAddr != remoteAddr || readRemoteAddr != localAddr { 55 // this check is deliberately crossed, the (readLocalAddr, 56 // readRemoteAddr) pair is from the point of view of the client, the 57 // (localAddr, remoteAddr) is from the point of view of the server. 58 continue 59 } 60 same := uid == int(remoteUID) 61 if !same && logflags.Any() { 62 log.Printf("connection from different user (remote: %d, local: %d) detected: %v", remoteUID, uid, line) 63 } 64 return same, nil 65 } 66 return false, &errConnectionNotFound{filename} 67 } 68 69 func addrToHex4(addr *net.TCPAddr) string { 70 // For details about the format, see the kernel side implementation: 71 // https://elixir.bootlin.com/linux/v5.2.2/source/net/ipv4/tcp_ipv4.c#L2375 72 b := addr.IP.To4() 73 return fmt.Sprintf("%02X%02X%02X%02X:%04X", b[3], b[2], b[1], b[0], addr.Port) 74 } 75 76 func addrToHex6(addr *net.TCPAddr) string { 77 a16 := addr.IP.To16() 78 // For details about the format, see the kernel side implementation: 79 // https://elixir.bootlin.com/linux/v5.2.2/source/net/ipv6/tcp_ipv6.c#L1792 80 words := make([]uint32, 4) 81 if err := binary.Read(bytes.NewReader(a16), binary.LittleEndian, words); err != nil { 82 panic(err) 83 } 84 return fmt.Sprintf("%08X%08X%08X%08X:%04X", words[0], words[1], words[2], words[3], addr.Port) 85 } 86 87 func sameUserForRemoteAddr4(localAddr, remoteAddr *net.TCPAddr) (bool, error) { 88 r, err := sameUserForHexLocalAddr("/proc/net/tcp", addrToHex4(localAddr), addrToHex4(remoteAddr)) 89 if _, isNotFound := err.(*errConnectionNotFound); isNotFound { 90 // See Issue #1835 91 r, err2 := sameUserForHexLocalAddr("/proc/net/tcp6", "0000000000000000FFFF0000"+addrToHex4(localAddr), "0000000000000000FFFF0000"+addrToHex4(remoteAddr)) 92 if err2 == nil { 93 return r, nil 94 } 95 } 96 return r, err 97 } 98 99 func sameUserForRemoteAddr6(localAddr, remoteAddr *net.TCPAddr) (bool, error) { 100 return sameUserForHexLocalAddr("/proc/net/tcp6", addrToHex6(localAddr), addrToHex6(remoteAddr)) 101 } 102 103 func sameUserForRemoteAddr(localAddr, remoteAddr *net.TCPAddr) (bool, error) { 104 if remoteAddr.IP.To4() == nil { 105 return sameUserForRemoteAddr6(localAddr, remoteAddr) 106 } 107 return sameUserForRemoteAddr4(localAddr, remoteAddr) 108 } 109 110 func CanAccept(listenAddr, localAddr, remoteAddr net.Addr) bool { 111 laddr, ok := listenAddr.(*net.TCPAddr) 112 if !ok || !laddr.IP.IsLoopback() { 113 return true 114 } 115 remoteAddrTCP := remoteAddr.(*net.TCPAddr) 116 localAddrTCP := localAddr.(*net.TCPAddr) 117 118 same, err := sameUserForRemoteAddr(localAddrTCP, remoteAddrTCP) 119 if err != nil { 120 log.Printf("cannot check remote address: %v", err) 121 } 122 if !same { 123 if logflags.Any() { 124 log.Printf("closing connection from different user (%v): connections to localhost are only accepted from the same UNIX user for security reasons", remoteAddrTCP) 125 } else { 126 fmt.Fprintf(os.Stderr, "closing connection from different user (%v): connections to localhost are only accepted from the same UNIX user for security reasons\n", remoteAddrTCP) 127 } 128 return false 129 } 130 return true 131 }