mirror of
https://github.com/dart-lang/sdk
synced 2024-10-03 00:44:41 +00:00
Trim abstract unix socket path length
Fixes https://github.com/dart-lang/sdk/issues/46149 TEST=unix_socket_test Change-Id: Icc5273941f880f581cc2621431b5cecb7782c71e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/201441 Commit-Queue: Zach Anderson <zra@google.com> Reviewed-by: Alexander Aprelev <aam@google.com> Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
parent
f827c53315
commit
5dc1f8db8c
7
BUILD.gn
7
BUILD.gn
|
@ -61,6 +61,10 @@ group("runtime") {
|
|||
"utils/dds:dds",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_linux || is_android) {
|
||||
deps += [ "runtime/bin:abstract_socket_test" ]
|
||||
}
|
||||
}
|
||||
|
||||
# A separate target and not included in group("runtime"). This way the target\
|
||||
|
@ -82,6 +86,9 @@ group("runtime_precompiled") {
|
|||
"runtime/bin:dart_precompiled_runtime",
|
||||
"runtime/bin:process_test",
|
||||
]
|
||||
if (is_linux || is_android) {
|
||||
deps += [ "runtime/bin:abstract_socket_test" ]
|
||||
}
|
||||
}
|
||||
|
||||
group("create_sdk") {
|
||||
|
|
|
@ -875,6 +875,11 @@ executable("process_test") {
|
|||
sources = [ "process_test.cc" ]
|
||||
}
|
||||
|
||||
executable("abstract_socket_test") {
|
||||
sources = [ "abstract_socket_test.cc" ]
|
||||
include_dirs = [ ".." ]
|
||||
}
|
||||
|
||||
executable("run_vm_tests") {
|
||||
if (target_os == "fuchsia") {
|
||||
testonly = true
|
||||
|
|
104
runtime/bin/abstract_socket_test.cc
Normal file
104
runtime/bin/abstract_socket_test.cc
Normal file
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// This is a utility program for testing that a Dart program can connect to an
|
||||
// abstract UNIX socket created by a non-Dart program. It creates such a socket
|
||||
// accepts one connection, echoes back the first message it receives, and then
|
||||
// closes the connection and UNIX socket.
|
||||
|
||||
#include "platform/globals.h"
|
||||
#if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
const intptr_t kOffsetOfPtr = 32;
|
||||
|
||||
#define OFFSET_OF(type, field) \
|
||||
(reinterpret_cast<intptr_t>( \
|
||||
&(reinterpret_cast<type*>(kOffsetOfPtr)->field)) - \
|
||||
kOffsetOfPtr) // NOLINT
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
struct sockaddr_un addr;
|
||||
char* socket_path;
|
||||
int server_socket;
|
||||
char buf[1024];
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Usage: abstract_socket_test <address>\n\n"
|
||||
"<address> should be an abstract UNIX socket address like @hidden\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
socket_path = argv[1];
|
||||
if (socket_path[0] != '@') {
|
||||
fprintf(stderr,
|
||||
"The first argument should be an abstract socket "
|
||||
"address and start with '@'\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if ((server_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
||||
perror("socket error");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sun_family = AF_UNIX;
|
||||
addr.sun_path[0] = '\0';
|
||||
strncpy(addr.sun_path + 1, socket_path + 1, sizeof(addr.sun_path) - 2);
|
||||
|
||||
int address_length =
|
||||
OFFSET_OF(struct sockaddr_un, sun_path) + strlen(socket_path);
|
||||
if (bind(server_socket, (struct sockaddr*)&addr, address_length) == -1) {
|
||||
perror("bind error");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (listen(server_socket, 5) == -1) {
|
||||
perror("listen error");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int client_socket;
|
||||
if ((client_socket = accept(server_socket, NULL, NULL)) == -1) {
|
||||
perror("accept error");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int read_count;
|
||||
while ((read_count = read(client_socket, buf, sizeof(buf))) > 0) {
|
||||
int write_count = 0;
|
||||
while (write_count < read_count) {
|
||||
int w;
|
||||
if ((w = write(client_socket, buf, read_count)) < 0) {
|
||||
perror("write");
|
||||
exit(-1);
|
||||
}
|
||||
write_count += w;
|
||||
}
|
||||
}
|
||||
if (read_count == -1) {
|
||||
perror("read");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
close(client_socket);
|
||||
close(server_socket);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int main() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
|
|
@ -42,8 +42,26 @@ intptr_t SocketAddress::GetAddrLength(const RawAddr& addr) {
|
|||
return sizeof(struct sockaddr_in6);
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_UNIX:
|
||||
return sizeof(struct sockaddr_un);
|
||||
case AF_UNIX: {
|
||||
// For an abstract UNIX socket, trailing null bytes in the name are
|
||||
// meaningful. That is, the bytes '\0/tmp/dbus-xxxx' are a different name
|
||||
// than '\0/tmp/dbus-xxxx\0\0\0...'. The length of the address structure
|
||||
// passed to connect() etc. tells those calls how many bytes of the name
|
||||
// to look at. Therefore, when computing the length of the address in
|
||||
// this case, any trailing null bytes are trimmed.
|
||||
// TODO(dart:io): Support abstract UNIX socket addresses that have
|
||||
// trailing null bytes on purpose.
|
||||
// https://github.com/dart-lang/sdk/issues/46158
|
||||
intptr_t nulls = 0;
|
||||
if (addr.un.sun_path[0] == '\0') {
|
||||
intptr_t i = sizeof(addr.un.sun_path) - 1;
|
||||
while (addr.un.sun_path[i] == '\0') {
|
||||
nulls++;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return sizeof(struct sockaddr_un) - nulls;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
|
|
|
@ -223,7 +223,7 @@ intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
|||
intptr_t backlog) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (NO_RETRY_EXPECTED(bind(fd, (struct sockaddr*)&addr.un,
|
||||
sizeof(struct sockaddr_un))) < 0) {
|
||||
SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -163,6 +163,47 @@ Future testAbstractAddress() async {
|
|||
await completer.future;
|
||||
}
|
||||
|
||||
String getAbstractSocketTestFileName() {
|
||||
var executable = Platform.executable;
|
||||
var dirIndex = executable.lastIndexOf('dart');
|
||||
var buffer = new StringBuffer(executable.substring(0, dirIndex));
|
||||
buffer.write('abstract_socket_test');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
Future testShortAbstractAddress() async {
|
||||
if (!Platform.isLinux && !Platform.isAndroid) {
|
||||
return;
|
||||
}
|
||||
Process? process;
|
||||
try {
|
||||
var socketAddress = '@hidden';
|
||||
var abstractSocketServer = getAbstractSocketTestFileName();
|
||||
process = await Process.start(abstractSocketServer, [socketAddress]);
|
||||
var serverAddress =
|
||||
InternetAddress(socketAddress, type: InternetAddressType.unix);
|
||||
Socket client = await Socket.connect(serverAddress, 0);
|
||||
List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
List<int> data = [];
|
||||
var completer = Completer<void>();
|
||||
client.listen(data.addAll, onDone: () {
|
||||
Expect.listEquals(sendData, data);
|
||||
completer.complete();
|
||||
});
|
||||
client.add(sendData);
|
||||
await client.close();
|
||||
await completer.future;
|
||||
client.destroy();
|
||||
var exitCode = await process.exitCode;
|
||||
process = null;
|
||||
Expect.equals(exitCode, 0);
|
||||
} catch (e, st) {
|
||||
Expect.fail('Failed with exception:\n$e\n$st');
|
||||
} finally {
|
||||
process?.kill(ProcessSignal.sigkill);
|
||||
}
|
||||
}
|
||||
|
||||
Future testExistingFile(String name) async {
|
||||
// Test that a leftover file(In case of previous process being killed and
|
||||
// finalizer doesn't clean up the file) will be cleaned up and bind() should
|
||||
|
@ -398,6 +439,7 @@ void main() async {
|
|||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testHttpServer('${dir.path}');
|
||||
});
|
||||
await testShortAbstractAddress();
|
||||
} catch (e) {
|
||||
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
|
||||
Expect.fail("Unexpected exception $e is thrown");
|
||||
|
|
|
@ -165,6 +165,47 @@ Future testAbstractAddress() async {
|
|||
await completer.future;
|
||||
}
|
||||
|
||||
String getAbstractSocketTestFileName() {
|
||||
var executable = Platform.executable;
|
||||
var dirIndex = executable.lastIndexOf('dart');
|
||||
var buffer = new StringBuffer(executable.substring(0, dirIndex));
|
||||
buffer.write('abstract_socket_test');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
Future testShortAbstractAddress() async {
|
||||
if (!Platform.isLinux && !Platform.isAndroid) {
|
||||
return;
|
||||
}
|
||||
Process process;
|
||||
try {
|
||||
var socketAddress = '@hidden';
|
||||
var abstractSocketServer = getAbstractSocketTestFileName();
|
||||
process = await Process.start(abstractSocketServer, [socketAddress]);
|
||||
var serverAddress =
|
||||
InternetAddress(socketAddress, type: InternetAddressType.unix);
|
||||
Socket client = await Socket.connect(serverAddress, 0);
|
||||
List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
List<int> data = [];
|
||||
var completer = Completer<void>();
|
||||
client.listen(data.addAll, onDone: () {
|
||||
Expect.listEquals(sendData, data);
|
||||
completer.complete();
|
||||
});
|
||||
client.add(sendData);
|
||||
await client.close();
|
||||
await completer.future;
|
||||
client.destroy();
|
||||
var exitCode = await process.exitCode;
|
||||
process = null;
|
||||
Expect.equals(exitCode, 0);
|
||||
} catch (e, st) {
|
||||
Expect.fail('Failed with exception:\n$e\n$st');
|
||||
} finally {
|
||||
process?.kill(ProcessSignal.sigkill);
|
||||
}
|
||||
}
|
||||
|
||||
Future testExistingFile(String name) async {
|
||||
// Test that a leftover file(In case of previous process being killed and
|
||||
// finalizer doesn't clean up the file) will be cleaned up and bind() should
|
||||
|
@ -400,6 +441,7 @@ void main() async {
|
|||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testHttpServer('${dir.path}');
|
||||
});
|
||||
await testShortAbstractAddress();
|
||||
} catch (e) {
|
||||
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
|
||||
Expect.fail("Unexpected exception $e is thrown");
|
||||
|
|
Loading…
Reference in a new issue