Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit 6ccd555

Browse files
authored
Disable socket inheritance on Windows and macOS (#32903)
* Disable socket inheritance on Windows and macOS We already disabled it on Linux. Doing the same for Windows and macOS. * Add test for socket non-inheritance * Disable new test on netfx
1 parent 207a50b commit 6ccd555

File tree

11 files changed

+150
-23
lines changed

11 files changed

+150
-23
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Net.Sockets;
7+
using System.Runtime.InteropServices;
8+
9+
internal static partial class Interop
10+
{
11+
internal static partial class Winsock
12+
{
13+
// Used as last parameter to WSASocket call.
14+
[Flags]
15+
internal enum SocketConstructorFlags
16+
{
17+
WSA_FLAG_OVERLAPPED = 0x01,
18+
WSA_FLAG_MULTIPOINT_C_ROOT = 0x02,
19+
WSA_FLAG_MULTIPOINT_C_LEAF = 0x04,
20+
WSA_FLAG_MULTIPOINT_D_ROOT = 0x08,
21+
WSA_FLAG_MULTIPOINT_D_LEAF = 0x10,
22+
WSA_FLAG_NO_HANDLE_INHERIT = 0x80,
23+
}
24+
}
25+
}

src/Common/src/Interop/Windows/Winsock/Interop.WSASocketW.SafeCloseSocket.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,6 @@ internal static partial class Interop
1010
{
1111
internal static partial class Winsock
1212
{
13-
// Used as last parameter to WSASocket call.
14-
[Flags]
15-
internal enum SocketConstructorFlags
16-
{
17-
WSA_FLAG_OVERLAPPED = 0x01,
18-
WSA_FLAG_MULTIPOINT_C_ROOT = 0x02,
19-
WSA_FLAG_MULTIPOINT_C_LEAF = 0x04,
20-
WSA_FLAG_MULTIPOINT_D_ROOT = 0x08,
21-
WSA_FLAG_MULTIPOINT_D_LEAF = 0x10,
22-
}
23-
2413
[DllImport(Interop.Libraries.Ws2_32, CharSet = CharSet.Unicode, SetLastError = true)]
2514
internal static extern SafeCloseSocket.InnerSafeCloseSocket WSASocketW(
2615
[In] AddressFamily addressFamily,

src/Common/src/System/Net/SafeCloseSocket.Windows.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ private SocketError InnerReleaseHandle()
217217

218218
internal static InnerSafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
219219
{
220-
InnerSafeCloseSocket result = Interop.Winsock.WSASocketW(addressFamily, socketType, protocolType, IntPtr.Zero, 0, Interop.Winsock.SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
220+
InnerSafeCloseSocket result = Interop.Winsock.WSASocketW(addressFamily, socketType, protocolType, IntPtr.Zero, 0, Interop.Winsock.SocketConstructorFlags.WSA_FLAG_OVERLAPPED | Interop.Winsock.SocketConstructorFlags.WSA_FLAG_NO_HANDLE_INHERIT);
221221
if (result.IsInvalid)
222222
{
223223
result.SetHandleAsInvalid();

src/Common/src/System/Net/SocketProtocolSupportPal.Windows.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private static bool IsProtocolSupported(AddressFamily af)
6363

6464
try
6565
{
66-
s = Interop.Winsock.WSASocketW(af, SocketType.Dgram, 0, IntPtr.Zero, 0, 0);
66+
s = Interop.Winsock.WSASocketW(af, SocketType.Dgram, 0, IntPtr.Zero, 0, (int)Interop.Winsock.SocketConstructorFlags.WSA_FLAG_NO_HANDLE_INHERIT);
6767

6868
if (s == IntPtr.Zero)
6969
{

src/Native/Unix/System.Native/pal_networking.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1978,7 +1978,15 @@ int32_t SystemNative_Socket(int32_t addressFamily, int32_t socketType, int32_t p
19781978
platformSocketType |= SOCK_CLOEXEC;
19791979
#endif
19801980
*createdSocket = socket(platformAddressFamily, platformSocketType, platformProtocolType);
1981-
return *createdSocket != -1 ? Error_SUCCESS : SystemNative_ConvertErrorPlatformToPal(errno);
1981+
if (*createdSocket == -1)
1982+
{
1983+
return SystemNative_ConvertErrorPlatformToPal(errno);
1984+
}
1985+
1986+
#ifndef SOCK_CLOEXEC
1987+
fcntl(ToFileDescriptor(*createdSocket), F_SETFD, FD_CLOEXEC); // ignore any failures; this is best effort
1988+
#endif
1989+
return Error_SUCCESS;
19821990
}
19831991

19841992
int32_t SystemNative_GetAtOutOfBandMark(intptr_t socket, int32_t* atMark)

src/System.Net.NameResolution/src/System.Net.NameResolution.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,9 @@
103103
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.WSASocketW.cs">
104104
<Link>Interop\Windows\Winsock\Interop.WSASocketW.cs</Link>
105105
</Compile>
106+
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs">
107+
<Link>Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs</Link>
108+
</Compile>
106109
<Compile Include="$(CommonPath)\System\Net\Sockets\ProtocolFamily.cs">
107110
<Link>Common\System\Net\Sockets\ProtocolFamily.cs</Link>
108111
</Compile>
@@ -198,4 +201,4 @@
198201
<Reference Include="System.Threading.Overlapped" />
199202
<Reference Include="System.Threading.Tasks" />
200203
</ItemGroup>
201-
</Project>
204+
</Project>

src/System.Net.NameResolution/tests/PalTests/System.Net.NameResolution.Pal.Tests.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,9 @@
108108
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.WSASocketW.cs">
109109
<Link>Interop\Windows\Winsock\Interop.WSASocketW.cs</Link>
110110
</Compile>
111+
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs">
112+
<Link>Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs</Link>
113+
</Compile>
111114
<Compile Include="$(CommonPath)\System\Net\Sockets\ProtocolFamily.cs">
112115
<Link>Common\System\Net\Sockets\ProtocolFamily.cs</Link>
113116
</Compile>
@@ -183,4 +186,4 @@
183186
<Link>Interop\Unix\System.Native\Interop.SocketAddress.cs</Link>
184187
</Compile>
185188
</ItemGroup>
186-
</Project>
189+
</Project>

src/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@
206206
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.WSASocketW.SafeCloseSocket.cs">
207207
<Link>Interop\Windows\Winsock\Interop.WSASocketW.SafeCloseSocket.cs</Link>
208208
</Compile>
209+
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs">
210+
<Link>Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs</Link>
211+
</Compile>
209212
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\WSABuffer.cs">
210213
<Link>Interop\Windows\Winsock\WSABuffer.cs</Link>
211214
</Compile>
@@ -358,4 +361,4 @@
358361
<ItemGroup Condition="'$(TargetsLinux)' == 'true'">
359362
<Reference Include="System.Threading.Timer" />
360363
</ItemGroup>
361-
</Project>
364+
</Project>

src/System.Net.Ping/src/System.Net.Ping.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@
123123
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.WSASocketW.cs">
124124
<Link>Common\Interop\Windows\Winsock\Interop.WSASocketW.cs</Link>
125125
</Compile>
126+
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs">
127+
<Link>Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs</Link>
128+
</Compile>
126129
<!-- System.Net.Internals -->
127130
<Compile Include="$(CommonPath)\System\Net\Sockets\SocketType.cs">
128131
<Link>Common\System\Net\Sockets\SocketType.cs</Link>
@@ -151,4 +154,4 @@
151154
<Reference Include="System.IO.FileSystem" />
152155
<Reference Include="System.Runtime.InteropServices.RuntimeInformation" />
153156
</ItemGroup>
154-
</Project>
157+
</Project>

src/System.Net.Sockets/src/System.Net.Sockets.csproj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,9 @@
228228
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.WSASocketW.SafeCloseSocket.cs">
229229
<Link>Interop\Windows\Winsock\Interop.WSASocketW.SafeCloseSocket.cs</Link>
230230
</Compile>
231+
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs">
232+
<Link>Interop\Windows\Winsock\Interop.SocketConstructorFlags.cs</Link>
233+
</Compile>
231234
<Compile Include="$(CommonPath)\Interop\Windows\Winsock\SafeNativeOverlapped.cs">
232235
<Link>Interop\Windows\Winsock\SafeNativeOverlapped.cs</Link>
233236
</Compile>
@@ -403,4 +406,4 @@
403406
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
404407
<Reference Include="System.Threading.ThreadPool" />
405408
</ItemGroup>
406-
</Project>
409+
</Project>

src/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System.Diagnostics;
6+
using System.IO;
7+
using System.IO.Pipes;
8+
using System.Threading.Tasks;
59
using Xunit;
610

711
namespace System.Net.Sockets.Tests
812
{
9-
public class CreateSocket
13+
public class CreateSocket : RemoteExecutorTestBase
1014
{
1115
public static object[][] DualModeSuccessInputs = {
1216
new object[] { SocketType.Stream, ProtocolType.Tcp },
@@ -89,9 +93,95 @@ public void Ctor_Failure(AddressFamily addressFamily, SocketType socketType, Pro
8993
[ConditionalTheory(nameof(SupportsRawSockets))]
9094
public void Ctor_Raw_Success(AddressFamily addressFamily, ProtocolType protocolType)
9195
{
92-
using (new Socket(addressFamily, SocketType.Raw, protocolType))
93-
{
94-
}
96+
using (new Socket(addressFamily, SocketType.Raw, protocolType))
97+
{
98+
}
99+
}
100+
101+
[SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Sockets are still inheritable on netfx: https://github.com/dotnet/corefx/pull/32903")]
102+
[Theory]
103+
[InlineData(true, 0)] // Accept
104+
[InlineData(false, 0)]
105+
[InlineData(true, 1)] // AcceptAsync
106+
[InlineData(false, 1)]
107+
[InlineData(true, 2)] // Begin/EndAccept
108+
[InlineData(false, 2)]
109+
public void CtorAndAccept_SocketNotKeptAliveViaInheritance(bool validateClientOuter, int acceptApiOuter)
110+
{
111+
// Run the test in another process so as to not have trouble with other tests
112+
// launching child processes that might impact inheritance.
113+
RemoteInvoke((validateClientString, acceptApiString) =>
114+
{
115+
bool validateClient = bool.Parse(validateClientString);
116+
int acceptApi = int.Parse(acceptApiString);
117+
118+
// Create a listening server.
119+
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
120+
{
121+
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
122+
listener.Listen(int.MaxValue);
123+
EndPoint ep = listener.LocalEndPoint;
124+
125+
// Create a client and connect to that listener.
126+
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
127+
{
128+
client.Connect(ep);
129+
130+
// Accept the connection using one of multiple accept mechanisms.
131+
Socket server =
132+
acceptApi == 0 ? listener.Accept() :
133+
acceptApi == 1 ? listener.AcceptAsync().GetAwaiter().GetResult() :
134+
acceptApi == 2 ? Task.Factory.FromAsync(listener.BeginAccept, listener.EndAccept, null).GetAwaiter().GetResult() :
135+
throw new Exception($"Unexpected {nameof(acceptApi)}: {acceptApi}");
136+
137+
// Get streams for the client and server, and create a pipe that we'll use
138+
// to communicate with a child process.
139+
using (var serverStream = new NetworkStream(server, ownsSocket: true))
140+
using (var clientStream = new NetworkStream(client, ownsSocket: true))
141+
using (var serverPipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable))
142+
{
143+
// Create a child process that blocks waiting to receive a signal on the anonymous pipe.
144+
// The whole purpose of the child is to test whether handles are inherited, so we
145+
// keep the child process alive until we're done validating that handles close as expected.
146+
using (RemoteInvoke(clientPipeHandle =>
147+
{
148+
using (var clientPipe = new AnonymousPipeClientStream(PipeDirection.In, clientPipeHandle))
149+
{
150+
Assert.Equal(42, clientPipe.ReadByte());
151+
}
152+
}, serverPipe.GetClientHandleAsString()))
153+
{
154+
if (validateClient) // Validate that the child isn't keeping alive the "new Socket" for the client
155+
{
156+
// Send data from the server to client, then validate the client gets EOF when the server closes.
157+
serverStream.WriteByte(84);
158+
Assert.Equal(84, clientStream.ReadByte());
159+
serverStream.Close();
160+
Assert.Equal(-1, clientStream.ReadByte());
161+
}
162+
else // Validate that the child isn't keeping alive the "listener.Accept" for the server
163+
{
164+
// Send data from the client to server, then validate the server gets EOF when the client closes.
165+
clientStream.WriteByte(84);
166+
Assert.Equal(84, serverStream.ReadByte());
167+
clientStream.Close();
168+
Assert.Equal(-1, serverStream.ReadByte());
169+
}
170+
171+
// And validate that we after closing the listening socket, we're not able to connect.
172+
listener.Dispose();
173+
using (var tmpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
174+
{
175+
Assert.ThrowsAny<SocketException>(() => tmpClient.Connect(ep));
176+
}
177+
178+
// Let the child process terminate.
179+
serverPipe.WriteByte(42);
180+
}
181+
}
182+
}
183+
}
184+
}, validateClientOuter.ToString(), acceptApiOuter.ToString()).Dispose();
95185
}
96186
}
97187
}

0 commit comments

Comments
 (0)