1515package transport
1616
1717import (
18+ "time"
1819 "unsafe"
1920
2021 "golang.org/x/sys/unix"
22+ "gvisor.dev/gvisor/pkg/log"
2123)
2224
25+ var usingRootCredsLogger = log .BasicRateLimitedLogger (time .Minute )
26+
2327// fdReadVec receives from fd to bufs.
2428//
2529// If the total length of bufs is > maxlen, fdReadVec will do a partial read
@@ -72,9 +76,9 @@ func fdReadVec(fd int, bufs [][]byte, control []byte, peek bool, maxlen int64) (
7276
7377// fdWriteVec sends from bufs to fd.
7478//
75- // If the total length of bufs is > maxlen && truncate, fdWriteVec will do a
76- // partial write and err will indicate why the message was truncated.
77- func fdWriteVec (fd int , bufs [][]byte , maxlen int64 , truncate bool ) (int64 , int64 , error ) {
79+ // If the total length of bufs is > maxlen && truncate, fdWriteVec will do
80+ // a partial write and err will indicate why the message was truncated.
81+ func fdWriteVec (fd int , bufs [][]byte , maxlen int64 , truncate bool , creds bool ) (int64 , int64 , error ) {
7882 length , iovecs , intermediate , err := buildIovec (bufs , maxlen , truncate )
7983 if err != nil && len (iovecs ) == 0 {
8084 // No partial write to do, return error immediately.
@@ -92,6 +96,36 @@ func fdWriteVec(fd int, bufs [][]byte, maxlen int64, truncate bool) (int64, int6
9296 msg .Iovlen = uint64 (len (iovecs ))
9397 }
9498
99+ if creds {
100+ // We can't pass arbitrary application credentials to the host. Pass the
101+ // sentry's credentials instead.
102+ cmsgSlice := make ([]byte , unix .CmsgSpace (unix .SizeofUcred ))
103+ cmsg := (* unix .Cmsghdr )(unsafe .Pointer (& cmsgSlice [0 ]))
104+ cmsg .Level = unix .SOL_SOCKET
105+ cmsg .Type = unix .SCM_CREDENTIALS
106+ cmsgLen := unix .CmsgLen (unix .SizeofUcred )
107+ cmsg .SetLen (cmsgLen )
108+ cmsgData := (* unix .Ucred )(unsafe .Pointer (& cmsgSlice [unix .CmsgLen (0 )]))
109+ // Collect owner information for fd. Gete(uid|gid) are forbidden by the
110+ // sentry's seccomp filters.
111+ s := unix.Stat_t {}
112+ if err := unix .Fstat (fd , & s ); err != nil {
113+ return 0 , length , err
114+ }
115+ if s .Uid == 0 || s .Gid == 0 {
116+ usingRootCredsLogger .Warningf ("gVisor does not support setting UID or GID to root in SCM credentials sent from the sentry" )
117+ return 0 , length , unix .EINVAL
118+ }
119+ pid , _ , err := unix .RawSyscall (unix .SYS_GETPID , 0 , 0 , 0 )
120+ if err != 0 {
121+ return 0 , length , err
122+ }
123+ * cmsgData = unix.Ucred {Pid : int32 (pid ), Uid : s .Uid , Gid : s .Gid }
124+
125+ msg .Control = & cmsgSlice [0 ]
126+ msg .SetControllen (cmsgLen )
127+ }
128+
95129 n , _ , e := unix .RawSyscall (unix .SYS_SENDMSG , uintptr (fd ), uintptr (unsafe .Pointer (& msg )), unix .MSG_DONTWAIT | unix .MSG_NOSIGNAL )
96130 if e != 0 {
97131 // N.B. prioritize the syscall error over the buildIovec error.
@@ -100,3 +134,11 @@ func fdWriteVec(fd int, bufs [][]byte, maxlen int64, truncate bool) (int64, int6
100134
101135 return int64 (n ), length , err
102136}
137+
138+ func passcredsEnabled (fd int ) bool {
139+ enabled , err := unix .GetsockoptInt (fd , unix .SOL_SOCKET , unix .SO_PASSCRED )
140+ if err != nil {
141+ return false
142+ }
143+ return enabled != 0
144+ }
0 commit comments