Skip to content

Commit f4a3ba5

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

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
@@ -720,6 +720,117 @@ static umf_result_t os_allocation_merge(void *provider, void *lowPtr,
720720
return UMF_RESULT_SUCCESS;
721721
}
722722

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

743854
umf_memory_provider_ops_t *umfOsMemoryProviderOps(void) {
744855
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)