Skip to content

Commit df63928

Browse files
ldorauszadam
authored andcommitted
Implement IPC hooks in OS memory provider
Signed-off-by: Lukasz Dorau <[email protected]>
1 parent 5ee1bb0 commit df63928

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
@@ -730,6 +730,117 @@ static umf_result_t os_allocation_merge(void *provider, void *lowPtr,
730730
return UMF_RESULT_SUCCESS;
731731
}
732732

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

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

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)