Skip to content

Commit 7a45c00

Browse files
committed
Implement IPC hooks in OS memory provider
Signed-off-by: Lukasz Dorau <lukasz.dorau@intel.com>
1 parent 33881e4 commit 7a45c00

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

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

752863
umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) {
753864
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)