-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathRunnerSecretRegistrationNotifier.cs
More file actions
150 lines (132 loc) · 5.24 KB
/
Copy pathRunnerSecretRegistrationNotifier.cs
File metadata and controls
150 lines (132 loc) · 5.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
using System;
using System.Collections.Generic;
using Microsoft.Win32.SafeHandles;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
namespace GitHub.Runner.Common
{
public sealed class RunnerSecretRegistrationNotifier : ISecretRegistrationNotifier
{
private const AddressFamily VsockAddressFamily = (AddressFamily)40;
internal bool IsLinux { get; }
private readonly Socket _vsock;
private readonly object _vsockSendLock = new object();
public RunnerSecretRegistrationNotifier()
{
IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
_vsock = IsLinux ? TryCreateConnectedVsock() : null;
}
public void NotifySecretRegistration(List<string> secrets, List<string> secretRegexes)
{
if (_vsock == null)
{
return;
}
try
{
string jsonPayload = JsonSerializer.Serialize(new
{
RunnerSecrets = new
{
secrets = secrets ?? new List<string>(),
secretRegexes = secretRegexes ?? new List<string>()
}
});
byte[] payloadBytes = Encoding.UTF8.GetBytes(jsonPayload);
byte[] lengthPrefix = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(payloadBytes.Length));
lock (_vsockSendLock)
{
SendAll(_vsock, lengthPrefix);
SendAll(_vsock, payloadBytes);
}
}
catch
{
// Notification delivery is best-effort and must never break secret masking.
}
}
private static Socket TryCreateConnectedVsock()
{
Socket socket = null;
try
{
SafeSocketHandle nativeSocket = NativeSocket((int)VsockAddressFamily, (int)SocketType.Stream, 0);
if (nativeSocket.IsInvalid)
{
int error = Marshal.GetLastPInvokeError();
nativeSocket.Dispose();
throw new SocketException(error);
}
socket = new Socket(nativeSocket);
socket.Connect(new HostVsockEndPoint(2, 9999));
return socket;
}
catch
{
socket?.Dispose();
return null;
}
}
[DllImport("libc", SetLastError = true, EntryPoint = "socket")]
private static extern SafeSocketHandle NativeSocket(int domain, int type, int protocol);
private static void SendAll(Socket socket, byte[] buffer)
{
int offset = 0;
while (offset < buffer.Length)
{
int bytesSent = socket.Send(buffer, offset, buffer.Length - offset, SocketFlags.None);
if (bytesSent <= 0)
{
throw new SocketException((int)SocketError.ConnectionReset);
}
offset += bytesSent;
}
}
private sealed class HostVsockEndPoint : EndPoint
{
private const int SocketAddressSize = 16;
private readonly uint _cid;
private readonly uint _port;
public HostVsockEndPoint(uint cid, uint port)
{
_cid = cid;
_port = port;
}
public override AddressFamily AddressFamily => VsockAddressFamily;
public override SocketAddress Serialize()
{
SocketAddress socketAddress = new SocketAddress(AddressFamily.Unspecified, SocketAddressSize);
// sockaddr_vm layout: family(0-1), reserved1(2-3), port(4-7), cid(8-11)
ushort family = (ushort)AddressFamily;
socketAddress[0] = (byte)(family & 0xFF);
socketAddress[1] = (byte)((family >> 8) & 0xFF);
socketAddress[2] = 0;
socketAddress[3] = 0;
socketAddress[4] = (byte)(_port & 0xFF);
socketAddress[5] = (byte)((_port >> 8) & 0xFF);
socketAddress[6] = (byte)((_port >> 16) & 0xFF);
socketAddress[7] = (byte)((_port >> 24) & 0xFF);
socketAddress[8] = (byte)(_cid & 0xFF);
socketAddress[9] = (byte)((_cid >> 8) & 0xFF);
socketAddress[10] = (byte)((_cid >> 16) & 0xFF);
socketAddress[11] = (byte)((_cid >> 24) & 0xFF);
return socketAddress;
}
public override EndPoint Create(SocketAddress socketAddress)
{
uint port = (uint)socketAddress[4]
| ((uint)socketAddress[5] << 8)
| ((uint)socketAddress[6] << 16)
| ((uint)socketAddress[7] << 24);
uint cid = (uint)socketAddress[8]
| ((uint)socketAddress[9] << 8)
| ((uint)socketAddress[10] << 16)
| ((uint)socketAddress[11] << 24);
return new HostVsockEndPoint(cid, port);
}
}
}
}