Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
666 changes: 664 additions & 2 deletions agent/cmd/cuinterpose/coordinator.c

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions agent/cmd/cuinterpose/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,76 @@
#ifndef CUINTERPOSER_PROTOCOL_H
#define CUINTERPOSER_PROTOCOL_H

#include <stdint.h>

#define CUINTERPOSER_MAGIC 0x44564d4dU
#define CUINTERPOSER_VERSION 1U
#define CUINTERPOSER_SOCKET_PREFIX "cuinterposer-"
#define CUINTERPOSER_ID_SIZE 33U
#define CUINTERPOSER_ALLOCATION_ID_SIZE 16U
#define CUINTERPOSER_TOKEN_SIZE 16U
#define CUINTERPOSER_MAX_ACCESS 8U
#define CUINTERPOSER_MAX_RECORDS 4096U
#define CUINTERPOSER_POSIX_HANDLE_TYPE 1U

enum cuinterposer_operation {
CUINTERPOSER_IDENTIFY = 1,
CUINTERPOSER_INSPECT = 2,
CUINTERPOSER_PREPARE = 3,
CUINTERPOSER_RESTORE_CREATORS = 4,
CUINTERPOSER_RESTORE_IMPORTERS = 5,
CUINTERPOSER_EXPORT = 6,
};

enum cuinterposer_record_kind {
CUINTERPOSER_ALLOCATION = 1,
CUINTERPOSER_MAPPING = 2,
};

enum cuinterposer_record_flags {
CUINTERPOSER_CREATOR = 1U << 0,
CUINTERPOSER_APPLICATION_HANDLE_LIVE = 1U << 1,
};

struct cuinterposer_header {
uint32_t magic;
uint16_t version;
uint16_t operation;
int32_t status;
uint32_t count;
uint64_t payload_size;
char participant_id[CUINTERPOSER_ID_SIZE];
char message[96];
uint8_t authorization[CUINTERPOSER_TOKEN_SIZE];
uint8_t allocation_id[CUINTERPOSER_ALLOCATION_ID_SIZE];
uint8_t reserved[71];
};

struct cuinterposer_access {
int32_t location_type;
int32_t location_id;
uint64_t flags;
};

struct cuinterposer_record {
uint32_t kind;
uint32_t flags;
uint8_t allocation_id[CUINTERPOSER_ALLOCATION_ID_SIZE];
uint64_t address;
uint64_t size;
uint64_t offset;
uint64_t allocation_size;
int32_t allocation_type;
uint32_t requested_handle_types;
int32_t allocation_location_type;
int32_t allocation_location_id;
uint32_t access_count;
uint32_t application_handle_count;
struct cuinterposer_access access[CUINTERPOSER_MAX_ACCESS];
};

_Static_assert(sizeof(struct cuinterposer_header) == 256, "cuinterposer header layout changed");
_Static_assert(sizeof(struct cuinterposer_access) == 16, "cuinterposer access layout changed");
_Static_assert(sizeof(struct cuinterposer_record) == 208, "cuinterposer record layout changed");

#endif
184 changes: 184 additions & 0 deletions agent/cmd/cuinterpose/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,188 @@
* SPDX-License-Identifier: Apache-2.0
*/

#define _GNU_SOURCE

#include "util.h"

#include <errno.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <sys/random.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>

int
write_all(int fd, const void* value, size_t size)
{
const uint8_t* current = value;

while (size != 0) {
ssize_t count = write(fd, current, size);
if (count < 0 && errno == EINTR)
continue;
if (count <= 0)
return -1;
current += count;
size -= (size_t)count;
}
return 0;
}

int
read_all(int fd, void* value, size_t size)
{
uint8_t* current = value;

while (size != 0) {
ssize_t count = read(fd, current, size);
if (count < 0 && errno == EINTR)
continue;
if (count <= 0)
return -1;
current += count;
size -= (size_t)count;
}
return 0;
}

int
pread_all(int fd, void* value, size_t size)
{
uint8_t* current = value;
off_t offset = 0;

while (size != 0) {
ssize_t count = pread(fd, current, size, offset);
if (count < 0 && errno == EINTR)
continue;
if (count <= 0)
return -1;
current += count;
offset += count;
size -= (size_t)count;
}
return 0;
}

int
random_bytes(void* output, size_t size)
{
unsigned char* current = output;

while (size != 0) {
ssize_t count = getrandom(current, size, 0);
if (count < 0 && errno == EINTR)
continue;
if (count <= 0)
return -1;
current += count;
size -= (size_t)count;
}
return 0;
}

int
random_id(char output[CUINTERPOSER_ID_SIZE])
{
uint8_t value[16];
size_t index;

if (random_bytes(value, sizeof(value)) != 0)
return -1;
for (index = 0; index < sizeof(value); index++)
snprintf(output + index * 2, CUINTERPOSER_ID_SIZE - index * 2, "%02x", value[index]);
return 0;
}

bool
is_lower_hex_id(const char value[CUINTERPOSER_ID_SIZE])
{
size_t index;

if (value == NULL)
return false;
for (index = 0; index < CUINTERPOSER_ID_SIZE - 1; index++) {
if (!((value[index] >= '0' && value[index] <= '9') || (value[index] >= 'a' && value[index] <= 'f')))
return false;
}
return value[CUINTERPOSER_ID_SIZE - 1] == '\0';
}

bool
header_strings_terminated(const struct cuinterposer_header* header)
{
return memchr(header->participant_id, '\0', sizeof(header->participant_id)) != NULL &&
memchr(header->message, '\0', sizeof(header->message)) != NULL;
}

void
header_error(struct cuinterposer_header* header, const char* message)
{
header->status = -1;
snprintf(header->message, sizeof(header->message), "%s", message);
}

int
set_socket_timeouts(int fd, int seconds)
{
struct timeval timeout = {.tv_sec = seconds};

return setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) == 0 &&
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == 0
? 0
: -1;
}

int
send_header(int fd, const struct cuinterposer_header* header, int passed_fd)
{
char control[CMSG_SPACE(sizeof(int))] = {0};
struct iovec vector = {.iov_base = (void*)header, .iov_len = sizeof(*header)};
struct msghdr message = {.msg_iov = &vector, .msg_iovlen = 1};
ssize_t count;

if (passed_fd >= 0) {
struct cmsghdr* item;
message.msg_control = control;
message.msg_controllen = sizeof(control);
item = CMSG_FIRSTHDR(&message);
item->cmsg_level = SOL_SOCKET;
item->cmsg_type = SCM_RIGHTS;
item->cmsg_len = CMSG_LEN(sizeof(int));
memcpy(CMSG_DATA(item), &passed_fd, sizeof(passed_fd));
}
do {
count = sendmsg(fd, &message, MSG_NOSIGNAL);
} while (count < 0 && errno == EINTR);
return count == (ssize_t)sizeof(*header) ? 0 : -1;
}

int
receive_header(int fd, struct cuinterposer_header* header, int* passed_fd)
{
char control[CMSG_SPACE(sizeof(int))] = {0};
struct iovec vector = {.iov_base = header, .iov_len = sizeof(*header)};
struct msghdr message = {
.msg_iov = &vector,
.msg_iovlen = 1,
.msg_control = control,
.msg_controllen = sizeof(control),
};
struct cmsghdr* item;
ssize_t count;

*passed_fd = -1;
do {
count = recvmsg(fd, &message, MSG_WAITALL | MSG_CMSG_CLOEXEC);
} while (count < 0 && errno == EINTR);
if (count != (ssize_t)sizeof(*header) || (message.msg_flags & (MSG_TRUNC | MSG_CTRUNC)) != 0)
return -1;
item = CMSG_FIRSTHDR(&message);
if (item != NULL && item->cmsg_level == SOL_SOCKET && item->cmsg_type == SCM_RIGHTS &&
item->cmsg_len == CMSG_LEN(sizeof(int)))
memcpy(passed_fd, CMSG_DATA(item), sizeof(*passed_fd));
return item == NULL || CMSG_NXTHDR(&message, item) == NULL ? 0 : -1;
}
17 changes: 17 additions & 0 deletions agent/cmd/cuinterpose/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,21 @@
#ifndef CUINTERPOSER_UTIL_H
#define CUINTERPOSER_UTIL_H

#include <stdbool.h>
#include <stddef.h>

#include "protocol.h"

int write_all(int fd, const void* value, size_t size);
int read_all(int fd, void* value, size_t size);
int pread_all(int fd, void* value, size_t size);
int random_bytes(void* output, size_t size);
int random_id(char output[CUINTERPOSER_ID_SIZE]);
bool is_lower_hex_id(const char value[CUINTERPOSER_ID_SIZE]);
bool header_strings_terminated(const struct cuinterposer_header* header);
void header_error(struct cuinterposer_header* header, const char* message);
int set_socket_timeouts(int fd, int seconds);
int send_header(int fd, const struct cuinterposer_header* header, int passed_fd);
int receive_header(int fd, struct cuinterposer_header* header, int* passed_fd);

#endif
Loading
Loading