/* * UNKNOWN_FD is an fd number that should never exist in the child, as it is * used to check the negative case.
*/ #define UNKNOWN_FD 111 #define UID_NOBODY 65535
staticint __child(int sk, int memfd)
{ int ret; char buf;
/* * Ensure we don't leave around a bunch of orphaned children if our * tests fail.
*/
ret = prctl(PR_SET_PDEATHSIG, SIGKILL); if (ret) {
fprintf(stderr, "%s: Child could not set DEATHSIG\n",
strerror(errno)); return -1;
}
ret = send(sk, &memfd, sizeof(memfd), 0); if (ret != sizeof(memfd)) {
fprintf(stderr, "%s: Child failed to send fd number\n",
strerror(errno)); return -1;
}
/* * The fixture setup is completed at this point. The tests will run. * * This blocking recv enables the parent to message the child. * Either we will read 'P' off of the sk, indicating that we need * to disable ptrace, or we will read a 0, indicating that the other * side has closed the sk. This occurs during fixture teardown time, * indicating that the child should exit.
*/ while ((ret = recv(sk, &buf, sizeof(buf), 0)) > 0) { if (buf == 'P') {
ret = prctl(PR_SET_DUMPABLE, 0); if (ret < 0) {
fprintf(stderr, "%s: Child failed to disable ptrace\n",
strerror(errno)); return -1;
}
} else {
fprintf(stderr, "Child received unknown command %c\n",
buf); return -1;
}
ret = send(sk, &buf, sizeof(buf), 0); if (ret != 1) {
fprintf(stderr, "%s: Child failed to ack\n",
strerror(errno)); return -1;
}
} if (ret < 0) {
fprintf(stderr, "%s: Child failed to read from socket\n",
strerror(errno)); return -1;
}
return 0;
}
staticint child(int sk)
{ int memfd, ret;
memfd = sys_memfd_create("test", 0); if (memfd < 0) {
fprintf(stderr, "%s: Child could not create memfd\n",
strerror(errno));
ret = -1;
} else {
ret = __child(sk, memfd);
close(memfd);
}
close(sk); return ret;
}
FIXTURE(child)
{ /* * remote_fd is the number of the FD which we are trying to retrieve * from the child.
*/ int remote_fd; /* pid points to the child which we are fetching FDs from */
pid_t pid; /* pidfd is the pidfd of the child */ int pidfd; /* * sk is our side of the socketpair used to communicate with the child. * When it is closed, the child will exit.
*/ int sk; bool ignore_child_result;
};
/* * Wait for the child to complete setup. It'll send the remote memfd's * number when ready.
*/
ret = recv(sk_pair[0], &self->remote_fd, sizeof(self->remote_fd), 0);
ASSERT_EQ(sizeof(self->remote_fd), ret);
}
ret = wait_for_pid(self->pid); if (!self->ignore_child_result)
EXPECT_EQ(0, ret);
}
TEST_F(child, disable_ptrace)
{ int uid, fd; char c;
/* * Turn into nobody if we're root, to avoid CAP_SYS_PTRACE * * The tests should run in their own process, so even this test fails, * it shouldn't result in subsequent tests failing.
*/
uid = getuid(); if (uid == 0)
ASSERT_EQ(0, seteuid(UID_NOBODY));
/* * It used to be that pidfd_getfd() could race with the exiting thread * between exit_files() and release_task(), and get a non-null task * with a NULL files struct, and you'd get EBADF, which was slightly * confusing.
*/
errno = 0;
EXPECT_EQ(sys_pidfd_getfd(self->pidfd, self->remote_fd, 0), -1);
EXPECT_EQ(errno, ESRCH);
}
#if __NR_pidfd_getfd == -1 int main(void)
{
fprintf(stderr, "__NR_pidfd_getfd undefined. The pidfd_getfd syscall is unavailable. Test aborting\n"); return KSFT_SKIP;
} #else
TEST_HARNESS_MAIN #endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.