Merge "Add wrappers for pidfd_{open,getfd,send_signal}."

This commit is contained in:
Josh Gao 2021-03-01 21:06:17 +00:00 committed by Gerrit Code Review
commit 974721431d
10 changed files with 287 additions and 6 deletions

View file

@ -1113,6 +1113,7 @@ cc_library_static {
"bionic/open.cpp",
"bionic/pathconf.cpp",
"bionic/pause.cpp",
"bionic/pidfd.cpp",
"bionic/pipe.cpp",
"bionic/poll.cpp",
"bionic/posix_fadvise.cpp",

View file

@ -72,5 +72,3 @@ int semtimedop_time64(int, sembuf*, size_t, const timespec64*) lp32
int rt_sigtimedwait_time64(const sigset64_t*, siginfo_t*, const timespec64*, size_t) lp32
int futex_time64(int*, int, int, const timespec64*, int*, int) lp32
int sched_rr_get_interval_time64(pid_t, timespec64*) lp32
# Since Linux 5.3, not in glibc.
int pidfd_open(pid_t pid, unsigned int flags) all

View file

@ -358,3 +358,8 @@ int __gettimeofday:gettimeofday(struct timeval*, struct timezone*) all
# <sys/random.h>
ssize_t getrandom(void*, size_t, unsigned) all
# <sys/pidfd.h>
int __pidfd_open:pidfd_open(pid_t, unsigned int) all
int __pidfd_getfd:pidfd_getfd(int, int, unsigned int) all
int pidfd_send_signal(int, int, siginfo_t*, unsigned int) all

42
libc/bionic/pidfd.cpp Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2021 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/pidfd.h>
#include "private/bionic_fdtrack.h"
extern "C" int __pidfd_open(pid_t pid, unsigned int flags);
extern "C" int __pidfd_getfd(int pidfd, int targetfd, unsigned int flags);
int pidfd_open(pid_t pid, unsigned int flags) {
return FDTRACK_CREATE(__pidfd_open(pid, flags));
}
int pidfd_getfd(int pidfd, int targetfd, unsigned int flags) {
return FDTRACK_CREATE(__pidfd_getfd(pidfd, targetfd, flags));
}

76
libc/include/sys/pidfd.h Normal file
View file

@ -0,0 +1,76 @@
/*
* Copyright (C) 2021 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#pragma once
/**
* @file sys/pidfd.h
* @brief File descriptors representing processes.
*/
#include <sys/cdefs.h>
#include <sys/types.h>
#include <bits/signal_types.h>
__BEGIN_DECLS
/**
* [pidfd_open(2)](https://man7.org/linux/man-pages/man2/pidfd_open.2.html)
* opens a file descriptor that refers to a process. This file descriptor will
* have the close-on-exec flag set by default.
*
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*
* Available since API level 31.
*/
int pidfd_open(pid_t __pid, unsigned int __flags) __INTRODUCED_IN(31);
/**
* [pidfd_getfd(2)](https://man7.org/linux/man-pages/man2/pidfd_open.2.html)
* dups a file descriptor from another process. This file descriptor will have
* the close-on-exec flag set by default.
*
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*
* Available since API level 31.
*/
int pidfd_getfd(int __pidfd, int __targetfd, unsigned int __flags) __INTRODUCED_IN(31);
/**
* [pidfd_send_signal(2)](https://man7.org/linux/man-pages/man2/pidfd_send_signal.2.html)
* sends a signal to another process.
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*
* Available since API level 31.
*/
int pidfd_send_signal(int __pidfd, int __sig, siginfo_t *__info, unsigned int __flags) __INTRODUCED_IN(31);
__END_DECLS

View file

@ -1558,6 +1558,9 @@ LIBC_S { # introduced=S
__libc_register_dynamic_tls_listeners;
ffsl;
ffsll;
pidfd_getfd;
pidfd_open;
pidfd_send_signal;
process_madvise;
} LIBC_R;

View file

@ -375,6 +375,7 @@ cc_test_library {
"netinet_ip_icmp_test.cpp",
"netinet_udp_test.cpp",
"nl_types_test.cpp",
"pidfd_test.cpp",
"poll_test.cpp",
"prio_ctor_test.cpp",
"pthread_test.cpp",

View file

@ -338,3 +338,19 @@ SUCH DAMAGE.
-------------------------------------------------------------------
Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-------------------------------------------------------------------

View file

@ -28,6 +28,8 @@
#include <unistd.h>
#if defined(__BIONIC__)
#include <sys/pidfd.h>
#include "platform/bionic/fdtrack.h"
#include "platform/bionic/reserved_signals.h"
#endif
@ -61,9 +63,7 @@ std::vector<android_fdtrack_event> FdtrackRun(void (*func)()) {
events.clear();
android_fdtrack_hook_t previous = nullptr;
android_fdtrack_hook_t hook = [](android_fdtrack_event* event) {
events.push_back(*event);
};
android_fdtrack_hook_t hook = [](android_fdtrack_event* event) { events.push_back(*event); };
if (!android_fdtrack_compare_exchange_hook(&previous, hook)) {
errx(1, "failed to exchange hook: previous hook was %p", previous);
@ -178,7 +178,7 @@ void SetFdResult(std::vector<int>* output, std::vector<int> fds) {
static std::vector<int> expected_fds; \
auto events = FdtrackRun([]() { SetFdResult(&expected_fds, expression); }); \
for (auto& fd : expected_fds) { \
ASSERT_NE(-1, fd); \
ASSERT_NE(-1, fd) << strerror(errno); \
} \
if (events.size() != expected_fds.size()) { \
fprintf(stderr, "too many events received: expected %zu, got %zu:\n", expected_fds.size(), \
@ -211,6 +211,37 @@ FDTRACK_TEST(open, open("/dev/null", O_WRONLY | O_CLOEXEC));
FDTRACK_TEST(openat, openat(AT_EMPTY_PATH, "/dev/null", O_WRONLY | O_CLOEXEC));
FDTRACK_TEST(socket, socket(AF_UNIX, SOCK_STREAM, 0));
FDTRACK_TEST(pidfd_open, ({
int rc = pidfd_open(getpid(), 0);
if (rc == -1) {
ASSERT_EQ(ENOSYS, errno);
GTEST_SKIP() << "pidfd_open not available";
}
rc;
}));
FDTRACK_TEST(pidfd_getfd, ({
android_fdtrack_set_enabled(false);
int pidfd_self = pidfd_open(getpid(), 0);
if (pidfd_self == -1) {
ASSERT_EQ(ENOSYS, errno);
GTEST_SKIP() << "pidfd_open not available";
}
android_fdtrack_set_enabled(true);
int rc = pidfd_getfd(pidfd_self, STDIN_FILENO, 0);
if (rc == -1) {
ASSERT_EQ(ENOSYS, errno);
GTEST_SKIP() << "pidfd_getfd not available";
}
android_fdtrack_set_enabled(false);
close(pidfd_self);
android_fdtrack_set_enabled(true);
rc;
}));
FDTRACK_TEST(dup, dup(STDOUT_FILENO));
FDTRACK_TEST(dup2, dup2(STDOUT_FILENO, STDERR_FILENO));
FDTRACK_TEST(dup3, dup3(STDOUT_FILENO, STDERR_FILENO, 0));

108
tests/pidfd_test.cpp Normal file
View file

@ -0,0 +1,108 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#if defined(__BIONIC__)
#include <sys/pidfd.h>
#endif
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include "BionicDeathTest.h"
using android::base::unique_fd;
using namespace std::chrono_literals;
using pidfd_DeathTest = BionicDeathTest;
TEST(pidfd, pidfd_open) {
#if defined(__BIONIC__)
pid_t child = fork();
ASSERT_NE(-1, child);
if (child == 0) {
_exit(42);
}
unique_fd pidfd(pidfd_open(child, 0));
if (pidfd.get() == -1) {
ASSERT_EQ(ENOSYS, errno);
GTEST_SKIP() << "pidfd_open not available";
}
siginfo_t siginfo;
int rc = waitid(P_PIDFD, pidfd.get(), &siginfo, WEXITED);
if (rc == -1) {
ASSERT_EQ(EINVAL, errno) << strerror(errno);
GTEST_SKIP() << "P_PIDFD not available";
}
ASSERT_EQ(child, siginfo.si_pid);
#endif
}
TEST(pidfd, pidfd_getfd) {
#if defined(__BIONIC__)
unique_fd r, w;
ASSERT_TRUE(android::base::Pipe(&r, &w));
unique_fd self(pidfd_open(getpid(), 0));
if (self.get() == -1) {
ASSERT_EQ(ENOSYS, errno);
GTEST_SKIP() << "pidfd_open not available";
}
unique_fd dup(pidfd_getfd(self.get(), r.get(), 0));
if (dup.get() == -1) {
ASSERT_EQ(ENOSYS, errno) << strerror(errno);
GTEST_SKIP() << "pidfd_getfd not available";
}
ASSERT_NE(r.get(), dup.get());
ASSERT_EQ(3, write(w.get(), "foo", 3));
char buf[4];
ASSERT_EQ(3, read(dup.get(), buf, sizeof(buf)));
ASSERT_EQ(0, memcmp(buf, "foo", 3));
#endif
}
TEST_F(pidfd_DeathTest, pidfd_send_signal) {
#if defined(__BIONIC__)
unique_fd self(pidfd_open(getpid(), 0));
if (self.get() == -1) {
ASSERT_EQ(ENOSYS, errno);
GTEST_SKIP() << "pidfd_open not available";
}
if (pidfd_send_signal(self.get(), 0, nullptr, 0) == -1) {
ASSERT_EQ(ENOSYS, errno);
GTEST_SKIP() << "pidfd_send_signal not available";
}
ASSERT_EXIT(({
// gtest will fork a child off for ASSERT_EXIT: `self` refers to the parent.
unique_fd child(pidfd_open(getpid(), 0));
pidfd_send_signal(child.get(), SIGINT, nullptr, 0);
}),
testing::KilledBySignal(SIGINT), "");
#endif
}