Skip to content

Commit 08ffca8

Browse files
committed
Implement IPC hooks in OS memory provider
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent a8769ff commit 08ffca8

File tree

4 files changed

+182
-5
lines changed

4 files changed

+182
-5
lines changed

src/provider/provider_os_memory.c

Lines changed: 116 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,117 @@ static umf_result_t os_allocation_merge(void *provider, void *lowPtr,
723723
return UMF_RESULT_SUCCESS;
724724
}
725725

726+
typedef struct os_ipc_data_t {
727+
int pid;
728+
int fd;
729+
size_t fd_offset;
730+
size_t size;
731+
} os_ipc_data_t;
732+
733+
static umf_result_t os_get_ipc_handle_size(void *provider, size_t *size) {
734+
(void)provider; // unused
735+
736+
if (size == NULL) {
737+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
738+
}
739+
740+
*size = sizeof(os_ipc_data_t);
741+
return UMF_RESULT_SUCCESS;
742+
}
743+
744+
static umf_result_t os_get_ipc_handle(void *provider, const void *ptr,
745+
size_t size, void *providerIpcData) {
746+
if (provider == NULL || ptr == NULL || providerIpcData == NULL) {
747+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
748+
}
749+
750+
os_memory_provider_t *os_provider = (os_memory_provider_t *)provider;
751+
if (os_provider->fd <= 0) {
752+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
753+
}
754+
755+
void *value = critnib_get(os_provider->fd_offset_map, (uintptr_t)ptr);
756+
if (value == NULL) {
757+
LOG_ERR("os_get_ipc_handle(): getting a value from the IPC cache "
758+
"failed (addr=%p)",
759+
ptr);
760+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
761+
}
762+
763+
os_ipc_data_t *os_ipc_data = (os_ipc_data_t *)providerIpcData;
764+
os_ipc_data->pid = os_getpid();
765+
os_ipc_data->fd = os_provider->fd;
766+
os_ipc_data->fd_offset = (size_t)value - 1;
767+
os_ipc_data->size = size;
768+
769+
return UMF_RESULT_SUCCESS;
770+
}
771+
772+
static umf_result_t os_put_ipc_handle(void *provider, void *providerIpcData) {
773+
if (provider == NULL || providerIpcData == NULL) {
774+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
775+
}
776+
777+
os_memory_provider_t *os_provider = (os_memory_provider_t *)provider;
778+
os_ipc_data_t *os_ipc_data = (os_ipc_data_t *)providerIpcData;
779+
780+
if (os_ipc_data->fd != os_provider->fd || os_ipc_data->pid != os_getpid()) {
781+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
782+
}
783+
784+
return UMF_RESULT_SUCCESS;
785+
}
786+
787+
static umf_result_t os_open_ipc_handle(void *provider, void *providerIpcData,
788+
void **ptr) {
789+
if (provider == NULL || providerIpcData == NULL || ptr == NULL) {
790+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
791+
}
792+
793+
os_memory_provider_t *os_provider = (os_memory_provider_t *)provider;
794+
os_ipc_data_t *os_ipc_data = (os_ipc_data_t *)providerIpcData;
795+
umf_result_t ret = UMF_RESULT_SUCCESS;
796+
int fd;
797+
798+
umf_result_t umf_result =
799+
os_duplicate_fd(os_ipc_data->pid, os_ipc_data->fd, &fd);
800+
if (umf_result != UMF_RESULT_SUCCESS) {
801+
LOG_PERR("duplicating file descriptor failed");
802+
return umf_result;
803+
}
804+
805+
*ptr = os_mmap(NULL, os_ipc_data->size, os_provider->protection,
806+
os_provider->visibility, fd, os_ipc_data->fd_offset);
807+
if (*ptr == NULL) {
808+
os_store_last_native_error(UMF_OS_RESULT_ERROR_ALLOC_FAILED, errno);
809+
LOG_PERR("memory mapping failed");
810+
ret = UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
811+
}
812+
813+
(void)os_close_fd(fd);
814+
815+
return ret;
816+
}
817+
818+
static umf_result_t os_close_ipc_handle(void *provider, void *ptr,
819+
size_t size) {
820+
if (provider == NULL || ptr == NULL) {
821+
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
822+
}
823+
824+
errno = 0;
825+
int ret = os_munmap(ptr, size);
826+
// ignore error when size == 0
827+
if (ret && (size > 0)) {
828+
os_store_last_native_error(UMF_OS_RESULT_ERROR_FREE_FAILED, errno);
829+
LOG_PERR("memory unmapping failed");
830+
831+
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
832+
}
833+
834+
return UMF_RESULT_SUCCESS;
835+
}
836+
726837
static umf_memory_provider_ops_t UMF_OS_MEMORY_PROVIDER_OPS = {
727838
.version = UMF_VERSION_CURRENT,
728839
.initialize = os_initialize,
@@ -737,11 +848,11 @@ static umf_memory_provider_ops_t UMF_OS_MEMORY_PROVIDER_OPS = {
737848
.ext.purge_force = os_purge_force,
738849
.ext.allocation_merge = os_allocation_merge,
739850
.ext.allocation_split = os_allocation_split,
740-
.ipc.get_ipc_handle_size = NULL,
741-
.ipc.get_ipc_handle = NULL,
742-
.ipc.put_ipc_handle = NULL,
743-
.ipc.open_ipc_handle = NULL,
744-
.ipc.close_ipc_handle = NULL};
851+
.ipc.get_ipc_handle_size = os_get_ipc_handle_size,
852+
.ipc.get_ipc_handle = os_get_ipc_handle,
853+
.ipc.put_ipc_handle = os_put_ipc_handle,
854+
.ipc.open_ipc_handle = os_open_ipc_handle,
855+
.ipc.close_ipc_handle = os_close_ipc_handle};
745856

746857
umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) {
747858
return &UMF_OS_MEMORY_PROVIDER_OPS;

src/provider/provider_os_memory_internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ size_t os_get_page_size(void);
4848

4949
void os_strerror(int errnum, char *buf, size_t buflen);
5050

51+
int os_getpid(void);
52+
53+
umf_result_t os_duplicate_fd(int pid, int fd_in, int *fd_out);
54+
55+
umf_result_t os_close_fd(int fd);
56+
5157
#ifdef __cplusplus
5258
}
5359
#endif

src/provider/provider_os_memory_linux.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,49 @@ int os_purge(void *addr, size_t length, int advice) {
171171
void os_strerror(int errnum, char *buf, size_t buflen) {
172172
strerror_r(errnum, buf, buflen);
173173
}
174+
175+
int os_getpid(void) { return getpid(); }
176+
177+
umf_result_t os_duplicate_fd(int pid, int fd_in, int *fd_out) {
178+
// pidfd_getfd(2) is used to obtain a duplicate of another process's file descriptor.
179+
// Permission to duplicate another process's file descriptor
180+
// is governed by a ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check (see ptrace(2))
181+
// that can be changed using the /proc/sys/kernel/yama/ptrace_scope interface.
182+
// pidfd_getfd(2) is supported since Linux 5.6
183+
// pidfd_open(2) is supported since Linux 5.3
184+
#if defined(__NR_pidfd_open) && defined(__NR_pidfd_getfd)
185+
errno = 0;
186+
int pid_fd = syscall(SYS_pidfd_open, pid, 0);
187+
if (pid_fd == -1) {
188+
LOG_PDEBUG("SYS_pidfd_open");
189+
return UMF_RESULT_ERROR_UNKNOWN;
190+
}
191+
192+
int fd_dup = syscall(SYS_pidfd_getfd, pid_fd, fd_in, 0);
193+
close(pid_fd);
194+
if (fd_dup == -1) {
195+
LOG_PDEBUG("SYS_pidfd_getfd");
196+
return UMF_RESULT_ERROR_UNKNOWN;
197+
}
198+
199+
*fd_out = fd_dup;
200+
201+
return UMF_RESULT_SUCCESS;
202+
#else
203+
// TODO: find another way to obtain a duplicate of another process's file descriptor
204+
(void)pid; // unused
205+
(void)fd_in; // unused
206+
(void)fd_out; // unused
207+
errno = ENOTSUP;
208+
return UMF_RESULT_ERROR_NOT_SUPPORTED; // unsupported
209+
#endif /* defined(__NR_pidfd_open) && defined(__NR_pidfd_getfd) */
210+
}
211+
212+
umf_result_t os_close_fd(int fd) {
213+
if (close(fd)) {
214+
LOG_PERR("close() failed");
215+
return UMF_RESULT_ERROR_UNKNOWN;
216+
}
217+
218+
return UMF_RESULT_SUCCESS;
219+
}

src/provider/provider_os_memory_windows.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,17 @@ size_t os_get_page_size(void) {
115115
void os_strerror(int errnum, char *buf, size_t buflen) {
116116
strerror_s(buf, buflen, errnum);
117117
}
118+
119+
int os_getpid(void) { return GetCurrentProcessId(); }
120+
121+
umf_result_t os_duplicate_fd(int pid, int fd_in, int *fd_out) {
122+
(void)pid; // unused
123+
(void)fd_in; // unused
124+
(void)fd_out; // unused
125+
return UMF_RESULT_ERROR_NOT_SUPPORTED; // unsupported
126+
}
127+
128+
umf_result_t os_close_fd(int fd) {
129+
(void)fd; // unused
130+
return UMF_RESULT_ERROR_NOT_SUPPORTED; // unsupported
131+
}

0 commit comments

Comments
 (0)