Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
0004  * All rights reserved.
0005  *
0006  * Check whether PTRACE_GET_SYSCALL_INFO semantics implemented in the kernel
0007  * matches userspace expectations.
0008  */
0009 
0010 #include "../kselftest_harness.h"
0011 #include <err.h>
0012 #include <signal.h>
0013 #include <asm/unistd.h>
0014 #include "linux/ptrace.h"
0015 
0016 static int
0017 kill_tracee(pid_t pid)
0018 {
0019     if (!pid)
0020         return 0;
0021 
0022     int saved_errno = errno;
0023 
0024     int rc = kill(pid, SIGKILL);
0025 
0026     errno = saved_errno;
0027     return rc;
0028 }
0029 
0030 static long
0031 sys_ptrace(int request, pid_t pid, unsigned long addr, unsigned long data)
0032 {
0033     return syscall(__NR_ptrace, request, pid, addr, data);
0034 }
0035 
0036 #define LOG_KILL_TRACEE(fmt, ...)               \
0037     do {                            \
0038         kill_tracee(pid);               \
0039         TH_LOG("wait #%d: " fmt,            \
0040                ptrace_stop, ##__VA_ARGS__);     \
0041     } while (0)
0042 
0043 TEST(get_syscall_info)
0044 {
0045     static const unsigned long args[][7] = {
0046         /* a sequence of architecture-agnostic syscalls */
0047         {
0048             __NR_chdir,
0049             (unsigned long) "",
0050             0xbad1fed1,
0051             0xbad2fed2,
0052             0xbad3fed3,
0053             0xbad4fed4,
0054             0xbad5fed5
0055         },
0056         {
0057             __NR_gettid,
0058             0xcaf0bea0,
0059             0xcaf1bea1,
0060             0xcaf2bea2,
0061             0xcaf3bea3,
0062             0xcaf4bea4,
0063             0xcaf5bea5
0064         },
0065         {
0066             __NR_exit_group,
0067             0,
0068             0xfac1c0d1,
0069             0xfac2c0d2,
0070             0xfac3c0d3,
0071             0xfac4c0d4,
0072             0xfac5c0d5
0073         }
0074     };
0075     const unsigned long *exp_args;
0076 
0077     pid_t pid = fork();
0078 
0079     ASSERT_LE(0, pid) {
0080         TH_LOG("fork: %m");
0081     }
0082 
0083     if (pid == 0) {
0084         /* get the pid before PTRACE_TRACEME */
0085         pid = getpid();
0086         ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 0, 0, 0)) {
0087             TH_LOG("PTRACE_TRACEME: %m");
0088         }
0089         ASSERT_EQ(0, kill(pid, SIGSTOP)) {
0090             /* cannot happen */
0091             TH_LOG("kill SIGSTOP: %m");
0092         }
0093         for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
0094             syscall(args[i][0],
0095                 args[i][1], args[i][2], args[i][3],
0096                 args[i][4], args[i][5], args[i][6]);
0097         }
0098         /* unreachable */
0099         _exit(1);
0100     }
0101 
0102     const struct {
0103         unsigned int is_error;
0104         int rval;
0105     } *exp_param, exit_param[] = {
0106         { 1, -ENOENT }, /* chdir */
0107         { 0, pid }  /* gettid */
0108     };
0109 
0110     unsigned int ptrace_stop;
0111 
0112     for (ptrace_stop = 0; ; ++ptrace_stop) {
0113         struct ptrace_syscall_info info = {
0114             .op = 0xff  /* invalid PTRACE_SYSCALL_INFO_* op */
0115         };
0116         const size_t size = sizeof(info);
0117         const int expected_none_size =
0118             (void *) &info.entry - (void *) &info;
0119         const int expected_entry_size =
0120             (void *) &info.entry.args[6] - (void *) &info;
0121         const int expected_exit_size =
0122             (void *) (&info.exit.is_error + 1) -
0123             (void *) &info;
0124         int status;
0125         long rc;
0126 
0127         ASSERT_EQ(pid, wait(&status)) {
0128             /* cannot happen */
0129             LOG_KILL_TRACEE("wait: %m");
0130         }
0131         if (WIFEXITED(status)) {
0132             pid = 0;    /* the tracee is no more */
0133             ASSERT_EQ(0, WEXITSTATUS(status));
0134             break;
0135         }
0136         ASSERT_FALSE(WIFSIGNALED(status)) {
0137             pid = 0;    /* the tracee is no more */
0138             LOG_KILL_TRACEE("unexpected signal %u",
0139                     WTERMSIG(status));
0140         }
0141         ASSERT_TRUE(WIFSTOPPED(status)) {
0142             /* cannot happen */
0143             LOG_KILL_TRACEE("unexpected wait status %#x", status);
0144         }
0145 
0146         switch (WSTOPSIG(status)) {
0147         case SIGSTOP:
0148             ASSERT_EQ(0, ptrace_stop) {
0149                 LOG_KILL_TRACEE("unexpected signal stop");
0150             }
0151             ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, pid, 0,
0152                         PTRACE_O_TRACESYSGOOD)) {
0153                 LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m");
0154             }
0155             ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
0156                               pid, size,
0157                               (unsigned long) &info))) {
0158                 LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
0159             }
0160             ASSERT_EQ(expected_none_size, rc) {
0161                 LOG_KILL_TRACEE("signal stop mismatch");
0162             }
0163             ASSERT_EQ(PTRACE_SYSCALL_INFO_NONE, info.op) {
0164                 LOG_KILL_TRACEE("signal stop mismatch");
0165             }
0166             ASSERT_TRUE(info.arch) {
0167                 LOG_KILL_TRACEE("signal stop mismatch");
0168             }
0169             ASSERT_TRUE(info.instruction_pointer) {
0170                 LOG_KILL_TRACEE("signal stop mismatch");
0171             }
0172             ASSERT_TRUE(info.stack_pointer) {
0173                 LOG_KILL_TRACEE("signal stop mismatch");
0174             }
0175             break;
0176 
0177         case SIGTRAP | 0x80:
0178             ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
0179                               pid, size,
0180                               (unsigned long) &info))) {
0181                 LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
0182             }
0183             switch (ptrace_stop) {
0184             case 1: /* entering chdir */
0185             case 3: /* entering gettid */
0186             case 5: /* entering exit_group */
0187                 exp_args = args[ptrace_stop / 2];
0188                 ASSERT_EQ(expected_entry_size, rc) {
0189                     LOG_KILL_TRACEE("entry stop mismatch");
0190                 }
0191                 ASSERT_EQ(PTRACE_SYSCALL_INFO_ENTRY, info.op) {
0192                     LOG_KILL_TRACEE("entry stop mismatch");
0193                 }
0194                 ASSERT_TRUE(info.arch) {
0195                     LOG_KILL_TRACEE("entry stop mismatch");
0196                 }
0197                 ASSERT_TRUE(info.instruction_pointer) {
0198                     LOG_KILL_TRACEE("entry stop mismatch");
0199                 }
0200                 ASSERT_TRUE(info.stack_pointer) {
0201                     LOG_KILL_TRACEE("entry stop mismatch");
0202                 }
0203                 ASSERT_EQ(exp_args[0], info.entry.nr) {
0204                     LOG_KILL_TRACEE("entry stop mismatch");
0205                 }
0206                 ASSERT_EQ(exp_args[1], info.entry.args[0]) {
0207                     LOG_KILL_TRACEE("entry stop mismatch");
0208                 }
0209                 ASSERT_EQ(exp_args[2], info.entry.args[1]) {
0210                     LOG_KILL_TRACEE("entry stop mismatch");
0211                 }
0212                 ASSERT_EQ(exp_args[3], info.entry.args[2]) {
0213                     LOG_KILL_TRACEE("entry stop mismatch");
0214                 }
0215                 ASSERT_EQ(exp_args[4], info.entry.args[3]) {
0216                     LOG_KILL_TRACEE("entry stop mismatch");
0217                 }
0218                 ASSERT_EQ(exp_args[5], info.entry.args[4]) {
0219                     LOG_KILL_TRACEE("entry stop mismatch");
0220                 }
0221                 ASSERT_EQ(exp_args[6], info.entry.args[5]) {
0222                     LOG_KILL_TRACEE("entry stop mismatch");
0223                 }
0224                 break;
0225             case 2: /* exiting chdir */
0226             case 4: /* exiting gettid */
0227                 exp_param = &exit_param[ptrace_stop / 2 - 1];
0228                 ASSERT_EQ(expected_exit_size, rc) {
0229                     LOG_KILL_TRACEE("exit stop mismatch");
0230                 }
0231                 ASSERT_EQ(PTRACE_SYSCALL_INFO_EXIT, info.op) {
0232                     LOG_KILL_TRACEE("exit stop mismatch");
0233                 }
0234                 ASSERT_TRUE(info.arch) {
0235                     LOG_KILL_TRACEE("exit stop mismatch");
0236                 }
0237                 ASSERT_TRUE(info.instruction_pointer) {
0238                     LOG_KILL_TRACEE("exit stop mismatch");
0239                 }
0240                 ASSERT_TRUE(info.stack_pointer) {
0241                     LOG_KILL_TRACEE("exit stop mismatch");
0242                 }
0243                 ASSERT_EQ(exp_param->is_error,
0244                       info.exit.is_error) {
0245                     LOG_KILL_TRACEE("exit stop mismatch");
0246                 }
0247                 ASSERT_EQ(exp_param->rval, info.exit.rval) {
0248                     LOG_KILL_TRACEE("exit stop mismatch");
0249                 }
0250                 break;
0251             default:
0252                 LOG_KILL_TRACEE("unexpected syscall stop");
0253                 abort();
0254             }
0255             break;
0256 
0257         default:
0258             LOG_KILL_TRACEE("unexpected stop signal %#x",
0259                     WSTOPSIG(status));
0260             abort();
0261         }
0262 
0263         ASSERT_EQ(0, sys_ptrace(PTRACE_SYSCALL, pid, 0, 0)) {
0264             LOG_KILL_TRACEE("PTRACE_SYSCALL: %m");
0265         }
0266     }
0267 
0268     ASSERT_EQ(ARRAY_SIZE(args) * 2, ptrace_stop);
0269 }
0270 
0271 TEST_HARNESS_MAIN