Skip to content

Commit 157e235

Browse files
committed
Implement IPC hooks in OS memory provider
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 73df2cb commit 157e235

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
@@ -726,6 +726,117 @@ static umf_result_t os_allocation_merge(void *provider, void *lowPtr,
726726
return UMF_RESULT_SUCCESS;
727727
}
728728

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

749860
umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) {
750861
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
@@ -190,3 +190,49 @@ int os_purge(void *addr, size_t length, int advice) {
190190
void os_strerror(int errnum, char *buf, size_t buflen) {
191191
strerror_r(errnum, buf, buflen);
192192
}
193+
194+
int os_getpid(void) { return getpid(); }
195+
196+
umf_result_t os_duplicate_fd(int pid, int fd_in, int *fd_out) {
197+
// pidfd_getfd(2) is used to obtain a duplicate of another process's file descriptor.
198+
// Permission to duplicate another process's file descriptor
199+
// is governed by a ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check (see ptrace(2))
200+
// that can be changed using the /proc/sys/kernel/yama/ptrace_scope interface.
201+
// pidfd_getfd(2) is supported since Linux 5.6
202+
// pidfd_open(2) is supported since Linux 5.3
203+
#if defined(__NR_pidfd_open) && defined(__NR_pidfd_getfd)
204+
errno = 0;
205+
int pid_fd = syscall(SYS_pidfd_open, pid, 0);
206+
if (pid_fd == -1) {
207+
LOG_PDEBUG("SYS_pidfd_open");
208+
return UMF_RESULT_ERROR_UNKNOWN;
209+
}
210+
211+
int fd_dup = syscall(SYS_pidfd_getfd, pid_fd, fd_in, 0);
212+
close(pid_fd);
213+
if (fd_dup == -1) {
214+
LOG_PDEBUG("SYS_pidfd_getfd");
215+
return UMF_RESULT_ERROR_UNKNOWN;
216+
}
217+
218+
*fd_out = fd_dup;
219+
220+
return UMF_RESULT_SUCCESS;
221+
#else
222+
// TODO: find another way to obtain a duplicate of another process's file descriptor
223+
(void)pid; // unused
224+
(void)fd_in; // unused
225+
(void)fd_out; // unused
226+
errno = ENOTSUP;
227+
return UMF_RESULT_ERROR_NOT_SUPPORTED; // unsupported
228+
#endif /* defined(__NR_pidfd_open) && defined(__NR_pidfd_getfd) */
229+
}
230+
231+
umf_result_t os_close_fd(int fd) {
232+
if (close(fd)) {
233+
LOG_PERR("close() failed");
234+
return UMF_RESULT_ERROR_UNKNOWN;
235+
}
236+
237+
return UMF_RESULT_SUCCESS;
238+
}

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)