Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/scripts/coccinelle/tests/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 1 kB image not shown  

Quelle  get_syscall_info.c   Sprache: unbekannt

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
 * All rights reserved.
 *
 * Check whether PTRACE_GET_SYSCALL_INFO semantics implemented in the kernel
 * matches userspace expectations.
 */


#include "../kselftest_harness.h"
#include <err.h>
#include <signal.h>
#include <asm/unistd.h>
#include "linux/ptrace.h"

static int
kill_tracee(pid_t pid)
{
 if (!pid)
  return 0;

 int saved_errno = errno;

 int rc = kill(pid, SIGKILL);

 errno = saved_errno;
 return rc;
}

static long
sys_ptrace(int request, pid_t pid, unsigned long addr, unsigned long data)
{
 return syscall(__NR_ptrace, request, pid, addr, data);
}

#define LOG_KILL_TRACEE(fmt, ...)    \
 do {       \
  kill_tracee(pid);    \
  TH_LOG("wait #%d: " fmt,   \
         ptrace_stop, ##__VA_ARGS__);  \
 } while (0)

TEST(get_syscall_info)
{
 static const unsigned long args[][7] = {
  /* a sequence of architecture-agnostic syscalls */
  {
   __NR_chdir,
   (unsigned long"",
   0xbad1fed1,
   0xbad2fed2,
   0xbad3fed3,
   0xbad4fed4,
   0xbad5fed5
  },
  {
   __NR_gettid,
   0xcaf0bea0,
   0xcaf1bea1,
   0xcaf2bea2,
   0xcaf3bea3,
   0xcaf4bea4,
   0xcaf5bea5
  },
  {
   __NR_exit_group,
   0,
   0xfac1c0d1,
   0xfac2c0d2,
   0xfac3c0d3,
   0xfac4c0d4,
   0xfac5c0d5
  }
 };
 const unsigned long *exp_args;

 pid_t pid = fork();

 ASSERT_LE(0, pid) {
  TH_LOG("fork: %m");
 }

 if (pid == 0) {
  /* get the pid before PTRACE_TRACEME */
  pid = getpid();
  ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 000)) {
   TH_LOG("PTRACE_TRACEME: %m");
  }
  ASSERT_EQ(0, kill(pid, SIGSTOP)) {
   /* cannot happen */
   TH_LOG("kill SIGSTOP: %m");
  }
  for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
   syscall(args[i][0],
    args[i][1], args[i][2], args[i][3],
    args[i][4], args[i][5], args[i][6]);
  }
  /* unreachable */
  _exit(1);
 }

 const struct {
  unsigned int is_error;
  int rval;
 } *exp_param, exit_param[] = {
  { 1, -ENOENT }, /* chdir */
  { 0, pid } /* gettid */
 };

 unsigned int ptrace_stop;

 for (ptrace_stop = 0; ; ++ptrace_stop) {
  struct ptrace_syscall_info info = {
   .op = 0xff /* invalid PTRACE_SYSCALL_INFO_* op */
  };
  const size_t size = sizeof(info);
  const int expected_none_size =
   (void *) &info.entry - (void *) &info;
  const int expected_entry_size =
   (void *) &info.entry.args[6] - (void *) &info;
  const int expected_exit_size =
   (void *) (&info.exit.is_error + 1) -
   (void *) &info;
  int status;
  long rc;

  ASSERT_EQ(pid, wait(&status)) {
   /* cannot happen */
   LOG_KILL_TRACEE("wait: %m");
  }
  if (WIFEXITED(status)) {
   pid = 0/* the tracee is no more */
   ASSERT_EQ(0, WEXITSTATUS(status));
   break;
  }
  ASSERT_FALSE(WIFSIGNALED(status)) {
   pid = 0/* the tracee is no more */
   LOG_KILL_TRACEE("unexpected signal %u",
     WTERMSIG(status));
  }
  ASSERT_TRUE(WIFSTOPPED(status)) {
   /* cannot happen */
   LOG_KILL_TRACEE("unexpected wait status %#x", status);
  }

  switch (WSTOPSIG(status)) {
  case SIGSTOP:
   ASSERT_EQ(0, ptrace_stop) {
    LOG_KILL_TRACEE("unexpected signal stop");
   }
   ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, pid, 0,
      PTRACE_O_TRACESYSGOOD)) {
    LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m");
   }
   ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
            pid, size,
            (unsigned long) &info))) {
    LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
   }
   ASSERT_EQ(expected_none_size, rc) {
    LOG_KILL_TRACEE("signal stop mismatch");
   }
   ASSERT_EQ(PTRACE_SYSCALL_INFO_NONE, info.op) {
    LOG_KILL_TRACEE("signal stop mismatch");
   }
   ASSERT_TRUE(info.arch) {
    LOG_KILL_TRACEE("signal stop mismatch");
   }
   ASSERT_TRUE(info.instruction_pointer) {
    LOG_KILL_TRACEE("signal stop mismatch");
   }
   ASSERT_TRUE(info.stack_pointer) {
    LOG_KILL_TRACEE("signal stop mismatch");
   }
   break;

  case SIGTRAP | 0x80:
   ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
            pid, size,
            (unsigned long) &info))) {
    LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
   }
   switch (ptrace_stop) {
   case 1/* entering chdir */
   case 3/* entering gettid */
   case 5/* entering exit_group */
    exp_args = args[ptrace_stop / 2];
    ASSERT_EQ(expected_entry_size, rc) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_EQ(PTRACE_SYSCALL_INFO_ENTRY, info.op) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_TRUE(info.arch) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_TRUE(info.instruction_pointer) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_TRUE(info.stack_pointer) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_EQ(exp_args[0], info.entry.nr) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_EQ(exp_args[1], info.entry.args[0]) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_EQ(exp_args[2], info.entry.args[1]) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_EQ(exp_args[3], info.entry.args[2]) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_EQ(exp_args[4], info.entry.args[3]) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_EQ(exp_args[5], info.entry.args[4]) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    ASSERT_EQ(exp_args[6], info.entry.args[5]) {
     LOG_KILL_TRACEE("entry stop mismatch");
    }
    break;
   case 2/* exiting chdir */
   case 4/* exiting gettid */
    exp_param = &exit_param[ptrace_stop / 2 - 1];
    ASSERT_EQ(expected_exit_size, rc) {
     LOG_KILL_TRACEE("exit stop mismatch");
    }
    ASSERT_EQ(PTRACE_SYSCALL_INFO_EXIT, info.op) {
     LOG_KILL_TRACEE("exit stop mismatch");
    }
    ASSERT_TRUE(info.arch) {
     LOG_KILL_TRACEE("exit stop mismatch");
    }
    ASSERT_TRUE(info.instruction_pointer) {
     LOG_KILL_TRACEE("exit stop mismatch");
    }
    ASSERT_TRUE(info.stack_pointer) {
     LOG_KILL_TRACEE("exit stop mismatch");
    }
    ASSERT_EQ(exp_param->is_error,
       info.exit.is_error) {
     LOG_KILL_TRACEE("exit stop mismatch");
    }
    ASSERT_EQ(exp_param->rval, info.exit.rval) {
     LOG_KILL_TRACEE("exit stop mismatch");
    }
    break;
   default:
    LOG_KILL_TRACEE("unexpected syscall stop");
    abort();
   }
   break;

  default:
   LOG_KILL_TRACEE("unexpected stop signal %#x",
     WSTOPSIG(status));
   abort();
  }

  ASSERT_EQ(0, sys_ptrace(PTRACE_SYSCALL, pid, 00)) {
   LOG_KILL_TRACEE("PTRACE_SYSCALL: %m");
  }
 }

 ASSERT_EQ(ARRAY_SIZE(args) * 2, ptrace_stop);
}

TEST_HARNESS_MAIN

Messung V0.5 in Prozent
C=94 H=86 G=89

[Dauer der Verarbeitung: 0.10 Sekunden, vorverarbeitet 2026-06-05]