From da7706c1d37fb8f6250989136a781fd078e4fdbb Mon Sep 17 00:00:00 2001 From: Patryk Kaminski Date: Fri, 3 Jan 2025 15:21:25 +0100 Subject: [PATCH] Add info about ptrace permissions Update our documentation with better info about ptrace - IPC users should be aware of required permissions. Add proposed, two possible solutions into our docs. Also, update our examples and tests to work without global change of ptrace_scope. Co-authored-by: sergey.vinogradov@intel.com --- .github/workflows/reusable_basic.yml | 3 --- .github/workflows/reusable_fast.yml | 4 ---- .github/workflows/reusable_proxy_lib.yml | 3 --- .github/workflows/reusable_sanitizers.yml | 4 ---- README.md | 25 ++++++++++++----------- examples/ipc_ipcapi/ipc_ipcapi_anon_fd.sh | 14 +++---------- examples/ipc_ipcapi/ipc_ipcapi_producer.c | 19 ++++++++++++++++- scripts/qemu/run-tests.sh | 4 +--- src/utils/utils_posix_common.c | 7 +++---- test/common/ipc_common.c | 10 ++++++++- test/ipc_os_prov_anon_fd.sh | 17 +-------------- test/providers/ipc_level_zero_prov.sh | 17 +-------------- 12 files changed, 49 insertions(+), 78 deletions(-) diff --git a/.github/workflows/reusable_basic.yml b/.github/workflows/reusable_basic.yml index 83542efbb..25d33e2b3 100644 --- a/.github/workflows/reusable_basic.yml +++ b/.github/workflows/reusable_basic.yml @@ -145,9 +145,6 @@ jobs: - name: Install libhwloc run: .github/scripts/install_hwloc.sh - - name: Set ptrace value for IPC test - run: sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" - - name: Get UMF version run: | VERSION=$(git describe --tags --abbrev=0 | grep -oP '\d+\.\d+\.\d+') diff --git a/.github/workflows/reusable_fast.yml b/.github/workflows/reusable_fast.yml index 5673727ac..58a172a74 100644 --- a/.github/workflows/reusable_fast.yml +++ b/.github/workflows/reusable_fast.yml @@ -88,10 +88,6 @@ jobs: sudo apt-get install -y cmake libnuma-dev libtbb-dev .github/scripts/install_hwloc.sh # install hwloc-2.3.0 instead of hwloc-2.1.0 present in the OS package - - name: Set ptrace value for IPC test (on Linux only) - if: ${{ matrix.os == 'ubuntu-latest' || matrix.os == 'ubuntu-20.04' }} - run: sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" - - name: Configure CMake if: matrix.simple_cmake == 'OFF' run: > diff --git a/.github/workflows/reusable_proxy_lib.yml b/.github/workflows/reusable_proxy_lib.yml index 27a66267d..a1f5975fa 100644 --- a/.github/workflows/reusable_proxy_lib.yml +++ b/.github/workflows/reusable_proxy_lib.yml @@ -34,9 +34,6 @@ jobs: sudo apt-get update sudo apt-get install -y cmake libhwloc-dev libtbb-dev lcov - - name: Set ptrace value for IPC test - run: sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" - - name: Configure build run: > cmake diff --git a/.github/workflows/reusable_sanitizers.yml b/.github/workflows/reusable_sanitizers.yml index 93752ff84..25458da51 100644 --- a/.github/workflows/reusable_sanitizers.yml +++ b/.github/workflows/reusable_sanitizers.yml @@ -40,10 +40,6 @@ jobs: sudo apt-get update sudo apt-get install -y intel-oneapi-ippcp-devel intel-oneapi-ipp-devel intel-oneapi-common-oneapi-vars intel-oneapi-compiler-dpcpp-cpp - - - name: Set ptrace value for IPC test - run: sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" - - name: Configure build run: > ${{ matrix.compiler.cxx == 'icpx' && '. /opt/intel/oneapi/setvars.sh &&' || ''}} diff --git a/README.md b/README.md index b16f35ff6..5bd0b9b2f 100644 --- a/README.md +++ b/README.md @@ -159,11 +159,12 @@ OS memory provider supports two types of memory mappings (set by the `visibility IPC API requires the `UMF_MEM_MAP_SHARED` memory `visibility` mode (`UMF_RESULT_ERROR_INVALID_ARGUMENT` is returned otherwise). -IPC API uses the file descriptor duplication. It requires using `pidfd_getfd(2)` to obtain -a duplicate of another process's file descriptor (`pidfd_getfd(2)` is supported since Linux 5.6). -Permission to duplicate another process's file descriptor is governed by a ptrace access mode -`PTRACE_MODE_ATTACH_REALCREDS` check (see `ptrace(2)`) that can be changed using -the `/proc/sys/kernel/yama/ptrace_scope` interface in the following way: +IPC API uses file descriptor duplication, which requires the `pidfd_getfd(2)` system call to obtain +a duplicate of another process's file descriptor. This system call is supported since Linux 5.6. +Required permission ("restricted ptrace") is governed by the `PTRACE_MODE_ATTACH_REALCREDS` check +(see `ptrace(2)`). To allow file descriptor duplication in a binary that opens IPC handle, you can call +`prctl(PR_SET_PTRACER, ...)` in the producer binary that gets the IPC handle. +Alternatively you can change the `ptrace_scope` globally in the system, e.g.: ```sh sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" @@ -194,16 +195,16 @@ Packages required for tests (Linux-only yet): A memory provider that provides memory from L0 device. -IPC API uses the file descriptor duplication. It requires using `pidfd_getfd(2)` to obtain -a duplicate of another process's file descriptor (`pidfd_getfd(2)` is supported since Linux 5.6). -Permission to duplicate another process's file descriptor is governed by a ptrace access mode -`PTRACE_MODE_ATTACH_REALCREDS` check (see `ptrace(2)`) that can be changed using -the `/proc/sys/kernel/yama/ptrace_scope` interface in the following way: +IPC API uses file descriptor duplication, which requires the `pidfd_getfd(2)` system call to obtain +a duplicate of another process's file descriptor. This system call is supported since Linux 5.6. +Required permission ("restricted ptrace") is governed by the `PTRACE_MODE_ATTACH_REALCREDS` check +(see `ptrace(2)`). To allow file descriptor duplication in a binary that opens IPC handle, you can call +`prctl(PR_SET_PTRACER, ...)` in the producer binary that gets the IPC handle. +Alternatively you can change the `ptrace_scope` globally in the system, e.g.: ```sh sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" ``` - ##### Requirements 1) Linux or Windows OS @@ -359,7 +360,7 @@ The memory used by the proxy memory allocator is mmap'ed: 1) with the `MAP_PRIVATE` flag by default or 2) with the `MAP_SHARED` flag if the `UMF_PROXY` environment variable contains one of two following strings: `page.disposition=shared-shm` or `page.disposition=shared-fd`. These two options differ in a mechanism used during IPC: - `page.disposition=shared-shm` - IPC uses the named shared memory. An SHM name is generated using the `umf_proxy_lib_shm_pid_$PID` pattern, where `$PID` is the PID of the process. It creates the `/dev/shm/umf_proxy_lib_shm_pid_$PID` file. - - `page.disposition=shared-fd` - IPC uses the file descriptor duplication. It requires using `pidfd_getfd(2)` to obtain a duplicate of another process's file descriptor. Permission to duplicate another process's file descriptor is governed by a ptrace access mode `PTRACE_MODE_ATTACH_REALCREDS` check (see `ptrace(2)`) that can be changed using the `/proc/sys/kernel/yama/ptrace_scope` interface. `pidfd_getfd(2)` is supported since Linux 5.6. + - `page.disposition=shared-fd` - IPC API uses file descriptor duplication, which requires the `pidfd_getfd(2)` system call to obtain a duplicate of another process's file descriptor. This system call is supported since Linux 5.6. Required permission ("restricted ptrace") is governed by the `PTRACE_MODE_ATTACH_REALCREDS` check (see `ptrace(2)`). To allow file descriptor duplication in a binary that opens IPC handle, you can call `prctl(PR_SET_PTRACER, ...)` in the producer binary that gets the IPC handle. Alternatively you can change the `ptrace_scope` globally in the system, e.g.: `sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope"`. **Size threshold** diff --git a/examples/ipc_ipcapi/ipc_ipcapi_anon_fd.sh b/examples/ipc_ipcapi/ipc_ipcapi_anon_fd.sh index 615271eeb..2eb9409da 100755 --- a/examples/ipc_ipcapi/ipc_ipcapi_anon_fd.sh +++ b/examples/ipc_ipcapi/ipc_ipcapi_anon_fd.sh @@ -1,5 +1,5 @@ # -# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024-2025 Intel Corporation # # Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -16,16 +16,8 @@ PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) # to obtain a duplicate of another process's file descriptor. # Permission to duplicate another process's file descriptor # is governed by a ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check (see ptrace(2)) -# that can be changed using the /proc/sys/kernel/yama/ptrace_scope interface. -PTRACE_SCOPE_FILE="/proc/sys/kernel/yama/ptrace_scope" -VAL=0 -if [ -f $PTRACE_SCOPE_FILE ]; then - PTRACE_SCOPE_VAL=$(cat $PTRACE_SCOPE_FILE) - if [ $PTRACE_SCOPE_VAL -ne $VAL ]; then - echo "SKIP: ptrace_scope is not set to 0 (classic ptrace permissions) - skipping the test" - exit 125 # skip code defined in CMakeLists.txt - fi -fi +# In the producer binary used in this example prctl(PR_SET_PTRACER, getppid()) is used +# to allow consumer to duplicate file descriptor of producer. UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" diff --git a/examples/ipc_ipcapi/ipc_ipcapi_producer.c b/examples/ipc_ipcapi/ipc_ipcapi_producer.c index 4157e8284..9082302ac 100644 --- a/examples/ipc_ipcapi/ipc_ipcapi_producer.c +++ b/examples/ipc_ipcapi/ipc_ipcapi_producer.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation * * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -69,6 +70,21 @@ int main(int argc, char *argv[]) { int port = atoi(argv[1]); + // The prctl() function with PR_SET_PTRACER is used here to allow parent process and its children + // to ptrace the current process. This is necessary because UMF's memory providers on Linux (except CUDA) + // use the pidfd_getfd(2) system call to duplicate another process's file descriptor, which is + // governed by ptrace permissions. By default on Ubuntu /proc/sys/kernel/yama/ptrace_scope is + // set to 1 ("restricted ptrace"), which prevents pidfd_getfd from working unless ptrace_scope + // is set to 0. + // To overcome this limitation without requiring users to change the ptrace_scope + // setting (which requires root privileges), we use prctl() to allow the consumer process + // to copy producer's file descriptor, even when ptrace_scope is set to 1. + ret = prctl(PR_SET_PTRACER, getppid()); + if (ret == -1) { + perror("PR_SET_PTRACER may be not supported. prctl() call failed"); + goto err_end; + } + umf_memory_provider_handle_t OS_memory_provider = NULL; umf_os_memory_provider_params_handle_t os_params = NULL; enum umf_result_t umf_result; @@ -259,6 +275,7 @@ int main(int argc, char *argv[]) { err_destroy_OS_params: umfOsMemoryProviderParamsDestroy(os_params); +err_end: if (ret == 0) { fprintf(stderr, "[producer] Shutting down (status OK) ...\n"); } else if (ret == 1) { diff --git a/scripts/qemu/run-tests.sh b/scripts/qemu/run-tests.sh index 9d855590b..341e2f9ab 100755 --- a/scripts/qemu/run-tests.sh +++ b/scripts/qemu/run-tests.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024-2025 Intel Corporation # Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -23,8 +23,6 @@ UMF_DIR=$(pwd) # Drop caches, restores free memory on NUMA nodes echo password | sudo sync; echo password | sudo sh -c "/usr/bin/echo 3 > /proc/sys/vm/drop_caches" -# Set ptrace value for IPC test -echo password | sudo bash -c "echo 0 > /proc/sys/kernel/yama/ptrace_scope" numactl -H diff --git a/src/utils/utils_posix_common.c b/src/utils/utils_posix_common.c index 4a60cbb1f..613b8ea41 100644 --- a/src/utils/utils_posix_common.c +++ b/src/utils/utils_posix_common.c @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation * * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -91,9 +91,8 @@ umf_result_t utils_duplicate_fd(int pid, int fd_in, int *fd_out) { return UMF_RESULT_ERROR_NOT_SUPPORTED; #else // pidfd_getfd(2) is used to obtain a duplicate of another process's file descriptor. - // Permission to duplicate another process's file descriptor - // is governed by a ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check (see ptrace(2)) - // that can be changed using the /proc/sys/kernel/yama/ptrace_scope interface. + // Calling prctl(PR_SET_PTRACER, getppid()) in a producer binary that creates IPC handle + // allows file descriptor duplication for parent process and its children. // pidfd_getfd(2) is supported since Linux 5.6 // pidfd_open(2) is supported since Linux 5.3 errno = 0; diff --git a/test/common/ipc_common.c b/test/common/ipc_common.c index 140927079..1590dd3c4 100644 --- a/test/common/ipc_common.c +++ b/test/common/ipc_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation * * Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -336,6 +337,12 @@ int run_producer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, int producer_socket = -1; char consumer_message[MSG_SIZE]; + ret = prctl(PR_SET_PTRACER, getppid()); + if (ret == -1) { + perror("PR_SET_PTRACER may be not supported. prctl() call failed"); + goto err_end; + } + // create OS memory provider umf_result = umfMemoryProviderCreate(provider_ops, provider_params, &provider); @@ -528,6 +535,7 @@ int run_producer(int port, umf_memory_pool_ops_t *pool_ops, void *pool_params, err_umfMemoryProviderDestroy: umfMemoryProviderDestroy(provider); +err_end: if (ret == 0) { fprintf(stderr, "[producer] Shutting down (status OK) ...\n"); } else if (ret == 1) { diff --git a/test/ipc_os_prov_anon_fd.sh b/test/ipc_os_prov_anon_fd.sh index c5738e989..a42d820a2 100755 --- a/test/ipc_os_prov_anon_fd.sh +++ b/test/ipc_os_prov_anon_fd.sh @@ -1,5 +1,5 @@ # -# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024-2025 Intel Corporation # # Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -12,21 +12,6 @@ set -e # port should be a number from the range <1024, 65535> PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) -# The ipc_os_prov_anon_fd example requires using pidfd_getfd(2) -# to obtain a duplicate of another process's file descriptor. -# Permission to duplicate another process's file descriptor -# is governed by a ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check (see ptrace(2)) -# that can be changed using the /proc/sys/kernel/yama/ptrace_scope interface. -PTRACE_SCOPE_FILE="/proc/sys/kernel/yama/ptrace_scope" -VAL=0 -if [ -f $PTRACE_SCOPE_FILE ]; then - PTRACE_SCOPE_VAL=$(cat $PTRACE_SCOPE_FILE) - if [ $PTRACE_SCOPE_VAL -ne $VAL ]; then - echo "SKIP: ptrace_scope is not set to 0 (classic ptrace permissions) - skipping the test" - exit 125 # skip code defined in CMakeLists.txt - fi -fi - UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" echo "Starting ipc_os_prov_anon_fd CONSUMER on port $PORT ..." diff --git a/test/providers/ipc_level_zero_prov.sh b/test/providers/ipc_level_zero_prov.sh index d6bcef4f3..4d2967725 100755 --- a/test/providers/ipc_level_zero_prov.sh +++ b/test/providers/ipc_level_zero_prov.sh @@ -1,5 +1,5 @@ # -# Copyright (C) 2024 Intel Corporation +# Copyright (C) 2024-2025 Intel Corporation # # Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception @@ -12,21 +12,6 @@ set -e # port should be a number from the range <1024, 65535> PORT=$(( 1024 + ( $$ % ( 65535 - 1024 )))) -# The ipc_level_zero_prov test requires using pidfd_getfd(2) -# to obtain a duplicate of another process's file descriptor. -# Permission to duplicate another process's file descriptor -# is governed by a ptrace access mode PTRACE_MODE_ATTACH_REALCREDS check (see ptrace(2)) -# that can be changed using the /proc/sys/kernel/yama/ptrace_scope interface. -PTRACE_SCOPE_FILE="/proc/sys/kernel/yama/ptrace_scope" -VAL=0 -if [ -f $PTRACE_SCOPE_FILE ]; then - PTRACE_SCOPE_VAL=$(cat $PTRACE_SCOPE_FILE) - if [ $PTRACE_SCOPE_VAL -ne $VAL ]; then - echo "SKIP: ptrace_scope is not set to 0 (classic ptrace permissions) - skipping the test" - exit 125 # skip code defined in CMakeLists.txt - fi -fi - UMF_LOG_VAL="level:debug;flush:debug;output:stderr;pid:yes" echo "Starting ipc_level_zero_prov CONSUMER on port $PORT ..."