Provided by: manpages-ru-dev_4.27.0-1_all bug

НАИМЕНОВАНИЕ

       ptrace - трассировка процесса

БИБЛИОТЕКА

       Стандартная библиотека языка C (libc, -lc)

ОБЗОР

       #include <sys/ptrace.h>

       long ptrace(enum __ptrace_request op, pid_t pid,
                   void *addr, void *data);

ОПИСАНИЕ

       Системный   вызов  ptrace()  позволяет  указать  какому  процессу  («трассировщику»)  можно  наблюдать  и
       контролировать выполнение другого процесса («трассироемого»),  просматривать  и  изменять  его  память  и
       регистры. Обычно, он используется для реализации отладочных точек прерывания и для отслеживания системных
       вызовов.

       Сначала,  трассировщик  должен  присоединиться  к  трассируемой нити. Присоединение и последующие команды
       выполняются для нитей: в  многонитевом  процессе  трассировщик  может  подключаться  как  к  каждой  нити
       (трассировщики могут быть у разных нитей разными), так и не подключаться к некоторым нитям вовсе. Поэтому
       на  самом  деле  «трассируемая  нить»   всегда  означает  «(одну)  нить», а не «процесс в целом (возможно
       многонитевой)». Команды ptrace всегда посылаются определённой трассируемой нити с помощью вызова

           ptrace(PTRACE_foo, pid, …)

       где pid — идентификатор соответствующей нити Linux.

       Заметим, что в этой странице «многонитевой процесс» означает группу нитей, состоящую из нитей,  созданных
       с помощью clone(2) с флагом CLONE_THREAD.

       Процесс  может  начать  трассировку с вызова fork(2), в получившемся дочернем процессе выполнить действие
       PTRACE_TRACEME, после чего (обычно) выполнить execve(2). Или же один процесс может начать отладку другого
       процесса при помощи PTRACE_ATTACH или PTRACE_SEIZE.

       While being traced, the tracee will stop each time a signal is delivered, even if  the  signal  is  being
       ignored.  (An exception is SIGKILL, which has its usual effect.)  The tracer will be notified at its next
       call  to  waitpid(2)   (or  one of the related "wait" system calls); that call will return a status value
       containing information that indicates the cause of the stop in the tracee.  While the tracee is  stopped,
       the  tracer  can  use various ptrace operations to inspect and modify the tracee.  The tracer then causes
       the tracee to continue, optionally ignoring the delivered signal (or even delivering a  different  signal
       instead).

       Если  флаг  PTRACE_O_TRACEEXEC  не  действует,  то все успешные вызовы execve(2) трассируемой нитью будут
       приводить к отправки сигнала SIGTRAP, давая таким образом родителю шанс перехватить управление  до  того,
       как начнёт выполняться новая программа.

       По  окончании трассировки трассировщик может заставить трассируемую нить продолжить свою работу в обычном
       не трассируемом режиме с помощью PTRACE_DETACH.

       The value of op determines the operation to be performed:

       PTRACE_TRACEME
              Indicate that this process is to be traced by its parent.  A process probably shouldn't make  this
              operation if its parent isn't expecting to trace it.  (pid, addr, and data are ignored.)

              The PTRACE_TRACEME operation is used only by the tracee; the remaining operations are used only by
              the  tracer.   In  the following operations, pid specifies the thread ID of the tracee to be acted
              on.  For operations other than PTRACE_ATTACH, PTRACE_SEIZE, PTRACE_INTERRUPT, and PTRACE_KILL, the
              tracee must be stopped.

       PTRACE_PEEKTEXT
       PTRACE_PEEKDATA
              Read a word at the address addr in the tracee's memory, returning the word as the  result  of  the
              ptrace()   call.   Linux  does  not  have  separate  text  and  data  address spaces, so these two
              operations are currently equivalent.  (data is ignored; but see NOTES.)

       PTRACE_PEEKUSER
              Читает слово по смещению addr из области USER трассируемой нити,  которая  содержит  информацию  о
              регистрах  и  процессе  (смотрите  <sys/userh>).  Слово  возвращается в качестве результата вызова
              ptrace(). Обычно, смещение должно быть выровнено по границе слова,  хотя  это  может  зависеть  от
              архитектуры системы. Смотрите ЗАМЕЧАНИЯ (значение data игнорируется; но смотрите ЗАМЕЧАНИЯ).

       PTRACE_POKETEXT
       PTRACE_POKEDATA
              Copy  the  word  data  to  the  address  addr  in the tracee's memory.  As for PTRACE_PEEKTEXT and
              PTRACE_PEEKDATA, these two operations are currently equivalent.

       PTRACE_POKEUSER
              Копирует слово data по смещению addr в область USER трассирумой нити. Как и  для  PTRACE_PEEKUSER,
              смещение  должно  быть  выровнено  по  границе  слова. Для того, чтобы сохранить целостность ядра,
              некоторые изменения в область USER вносить запрещено.

       PTRACE_GETREGS
       PTRACE_GETFPREGS
              Копирует, соответственно, регистры общего назначения или регистры сопроцессора трассируемой нити в
              память трассировщика по адресу data. Формат передаваемой структуры  описан  в  файле  <sys/user.h>
              (значение  addr  игнорируется).  Заметим, что в системах SPARC предназначение data и addr поменяны
              местами; то есть data игнорируется,  а  регистры  копируются  по  адресу  addr.  PTRACE_GETREGS  и
              PTRACE_GETFPREGS есть не на всех архитектурах.

       PTRACE_GETREGSET (начиная с Linux 2.6.34)
              Читает  регистры  трассируемой  нити.  В  addr  указывается, в зависящей от архитектуры форме, тип
              читаемых регистров. Значение NT_PRSTATUS (равно 1)  обычно  служит  для  чтения  регистров  общего
              назначения.  Если  в  ЦП  есть,  например, векторные регистры и для плавающей запятой, то их можно
              получить назначив addr соответствующую константу NT_foo. Значение data указывает на struct  iovec,
              которая  описывает  расположение  буфера  назначения  и длину. При возврате ядро изменяет iov.len,
              возвращая реальное количество возвращаемых байт.

       PTRACE_SETREGS
       PTRACE_SETFPREGS
              Копирует,  соответственно,  регистры  общего  назначения  или  регистры  для   плавающей   запятой
              трассируемой  нити  из  памяти  трассировщика  по  адресу  data. Как и в случае c PTRACE_POKEUSER,
              изменения некоторых регистров общего назначения запрещены (значение addr  игнорируется).  Заметим,
              что в системах SPARC предназначение data и addr переставлены местами; то есть data игнорируется, а
              регистры  копируются из памяти, на которую указывает адрес addr. PTRACE_SETREGS и PTRACE_SETFPREGS
              есть не для всех архитектур.

       PTRACE_SETREGSET (начиная с Linux 2.6.34)
              Изменяет регистры трассируемой нити. Значение addr и data аналогичны PTRACE_GETREGSET.

       PTRACE_GETSIGINFO (начиная с Linux 2.3.99-pre6)
              Получает информацию о сигнале, который вызвал остановку. Копирует  структуру  siginfo_t  (смотрите
              sigaction(2))  из  трассируемой  нити  в  память  трассировщика  по  адресу  data  (значение  addr
              игнорируется).

       PTRACE_SETSIGINFO (начиная с Linux 2.3.99-pre6)
              Устанавливает информацию о сигнале. Копирует структуру siginfo_t,  расположенную  по  адресу  data
              трассировщика,  в  память  трассируемой  нити.  Влияет  только  на сигналы, которые обычно были бы
              доставлены трассируемой нити  и  были  пойманы  трассировщиком.  Затруднительно  отличить  обычные
              сигналы от созданных самим ptrace() (значение addr игнорируется).

       PTRACE_PEEKSIGINFO (начиная с Linux 3.10)
              Получает  структуры  siginfo_t  не удаляя сигналы из очереди. Значение addr указывает на структуру
              ptrace_peeksiginfo_args, которая задаёт начальную позицию, из  которой  нужно  начать  копирование
              сигналов,  а  также  их  количество.  Структуры  siginfo_t копируются в буфер, указываемый в data.
              Возвращаемое значение содержит количество скопированных сигналов (ноль означает,  что  сигналов  в
              указанной  позиции нет). Внутри возвращаемых структур siginfo в поле si_code включается информация
              (__SI_CHLD, __SI_FAULT  и  т.  д.),  которая  по-другому  никак  не  выдаётся  в  пользовательское
              пространство.

           struct ptrace_peeksiginfo_args {
               u64 off;    /* начальная позиция в очереди, с которой
                              начинается копирование сигналов */
               u32 flags;  /* PTRACE_PEEKSIGINFO_SHARED или 0 */
               s32 nr;     /* количество копируемых сигналов */
           };

              В  настоящее  время  определён  только  один флаг, PTRACE_PEEKSIGINFO_SHARED, служащий для выборки
              сигналов из общей очереди сигналов процессов. Если этот флаг не указан,  то  сигналы  читаются  из
              очереди указанной нити.

       PTRACE_GETSIGMASK (начиная с Linux 3.11)
              Помещает  копию  маски  блокированных сигналов (смотрите sigprocmask(2)) в буфер, указанный в data
              (должен быть указателем на  буфер  с  типом  sigset_t).  Аргумент  addr  содержит  размер  буфера,
              указанного в data (т. е. sizeof(sigset_t)).

       PTRACE_SETSIGMASK (начиная с Linux 3.11)
              Изменяет  маску блокированных сигналов (смотрите sigprocmask(2)) на значение из буфера, указанного
              в data (должен быть указателем на буфер с типом sigset_t). Аргумент addr содержит  размер  буфера,
              указанного в data (т. е. sizeof(sigset_t)).

       PTRACE_SETOPTIONS (начиная с Linux 2.4.6; см. предостережения в разделе ДЕФЕКТЫ)
              Устанавливает  флаги ptrace из data (значение addr игнорируется). Значение data воспринимается как
              битовая маска, в которой задаются следующие флаги:

              PTRACE_O_EXITKILL (начиная с Linux 3.8)
                     Посылать сигнал SIGKILL трассируемому, если трассировщик существует. Этот параметр  полезен
                     для надзирателей ptrace, которые хотят убедиться, что трассируемые никогда не выйдут из-под
                     контроля трассировщика.

              PTRACE_O_TRACECLONE (начиная с Linux 2.5.46)
                     Останавливать  трассируемую  нить  при  следующем вызове clone(2) и автоматически запускать
                     трассировку только что склонированного процесса,  который  начнёт  выполнение  с  обработки
                     сигнала  SIGSTOP  или  PTRACE_EVENT_STOP,  если используется PTRACE_SEIZE. Вызов waitpid(2)
                     вернёт трассировщику значение status, которое равно

                       status>>8 == (SIGTRAP | (PTRACE_EVENT_CLONE<<8))

                     Значение PID нового процесса можно получить с помощью PTRACE_GETEVENTMSG.

                     В некоторых случаях вызовы clone(2) могут быть не пойманы. Если трассируемая нить  вызывает
                     clone(2)  с  флагом  CLONE_VFORK,  то  будет  доставлен PTRACE_EVENT_VFORK, если установлен
                     PTRACE_O_TRACEVFORK; в  противном  случае,  если  трассируемая  нить  вызывает  clone(2)  с
                     установленным  сигналом  выхода  равным SIGCHLD, то будет доставлен PTRACE_EVENT_FORK, если
                     установлен PTRACE_O_TRACEFORK.

              PTRACE_O_TRACEEXEC (начиная с Linux 2.5.46)
                     Останавливать трассируемую нить при следующем  вызове  execve().  Вызов  waitpid(2)  вернёт
                     трассировщику значение status, которое равно

                       status>>8 == (SIGTRAP | (PTRACE_EVENT_EXEC<<8))

                     Если  исполняемая нить не является лидером группы нитей, то идентификатор нити сбрасывается
                     в значение идентификатора лидера группы нитей перед его остановкой. Начиная  с  Linux  3.0,
                     предыдущий идентификатор нити может быть получен с помощью PTRACE_GETEVENTMSG.

              PTRACE_O_TRACEEXIT (начиная с Linux 2.5.60)
                     Останавливать   трассируемую  нить  при  его  завершении  (exit).  Вызов  waitpid()  вернёт
                     трассировщику значение status, которое равно

                       status>>8 == (SIGTRAP | (PTRACE_EVENT_EXIT<<8))

                     Значение кода завершения трассируемой нити можно получить с помощью PTRACE_GETEVENTMSG.

                     Остановка трассируемой нити будет  выполнена  в  начальный  момент  завершения,  когда  ещё
                     доступны  регистры,  что  позволяет  трассировщику  увидеть  откуда  выполнялось завершение
                     (обычное уведомление о завершении выполняется после того как процесс уже завершил  работу).
                     Хотя  в  этот  момент  ещё  доступен  контекст,  трассировщик  уже  не  может предотвратить
                     завершение.

              PTRACE_O_TRACEFORK (начиная с Linux 2.5.46)
                     Останавливать трассируемую нить при следующем  вызове  fork(2)  и  автоматически  запускать
                     трассировку  только  что  созданного  с  помощью fork процесса, который начнёт выполнение с
                     обработки сигнала SIGSTOP или  PTRACE_EVENT_STOP,  если  используется  PTRACE_SEIZE.  Вызов
                     waitpid(2) вернёт трассировщику значение status, которое равно

                       status>>8 == (SIGTRAP | (PTRACE_EVENT_FORK<<8))

                     Значение PID нового процесса можно получить с помощью PTRACE_GETEVENTMSG.

              PTRACE_O_TRACESYSGOOD (начиная с Linux 2.4.6)
                     При  доставке  сигналов ловушек системных вызовов, устанавливать бит 7 в номере сигнала (т.
                     е., доставляется SIGTRAP|0x80). Это позволяет трассировщику легко отличить обычные  ловушки
                     от тех, которые были вызваны системным вызовом.

              PTRACE_O_TRACEVFORK (начиная с Linux 2.5.46)
                     Останавливать  трассируемую  нить  при  следующем вызове vfork(2) и автоматически запускать
                     трассировку только что созданного с помощью vfork процесса,  который  начнёт  выполнение  с
                     обработки  сигнала  SIGSTOP  или  PTRACE_EVENT_STOP,  если используется PTRACE_SEIZE. Вызов
                     waitpid(2) вернёт трассировщику значение status, которое равно

                       status>>8 == (SIGTRAP | (PTRACE_EVENT_VFORK<<8))

                     Значение PID нового процесса можно получить с помощью PTRACE_GETEVENTMSG.

              PTRACE_O_TRACEVFORKDONE (начиная с Linux 2.5.60)
                     Останавливать трассируемую нить при следующем  вызове  vfork(2).  Вызов  waitpid(2)  вернёт
                     трассировщику значение status, которое равно

                       status>>8 == (SIGTRAP | (PTRACE_EVENT_VFORK_DONE<<8))

                     Значение   PID   нового  процесса  можно  получить  (начиная  с  Linux  2.6.18)  с  помощью
                     PTRACE_GETEVENTMSG.

              PTRACE_O_TRACESECCOMP (начиная с Linux 3.5)
                     Останавливать трассируемую нить при  возникновении  правила  seccomp(2)  SECCOMP_RET_TRACE.
                     Вызов waitpid(2) вернёт трассировщику значение status, которое равно

                       status>>8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP<<8))

                     Так  как  это  останавливает PTRACE_EVENT, это похоже на syscall-enter-stop. Дополнительную
                     информацию смотрите в замечании  к  PTRACE_EVENT_SECCOMP  ниже.  Данные  сообщения  события
                     seccomp  (из  части  SECCOMP_RET_DATA  правила фильтрации seccomp) можно получить с помощью
                     PTRACE_GETEVENTMSG.

              PTRACE_O_SUSPEND_SECCOMP (начиная с Linux 4.3)
                     Приостановить защиты seccomp трассируемого. Это применяется независимо от  режима  и  может
                     быть  использовано когда трассируемый ещё не установил фильтры seccomp. То есть, корректным
                     действием будет  приостановка  защит  seccomp  трассируемого,  до  того  как  их  установит
                     трассируемый, позволить трассируемому установить фильтры, и затем очистить этот флаг, когда
                     нужно  возобновить  работу  фильтров. Установка этого параметра требует, чтобы трассировщик
                     имел мандат CAP_SYS_ADMIN, не было установлено никаких защит seccomp и  не  установлен  сам
                     PTRACE_O_SUSPEND_SECCOMP.

       PTRACE_GETEVENTMSG (начиная с Linux 2.5.46)
              Возвращает  сообщения  (с  типом  unsigned  long)  о событии ptrace, которое только что произошло,
              помещая его по адресу data в  памяти  трассировщика.  Для  PTRACE_EVENT_EXIT  это  код  завершения
              трассируемой   нити.   Для   PTRACE_EVENT_FORK,   PTRACE_EVENT_VFORK,   PTRACE_EVENT_VFORK_DONE  и
              PTRACE_EVENT_CLONE это PID нового  процесса.  Для  PTRACE_EVENT_SECCOMP  это  SECCOMP_RET_DATA  из
              фильтра seccomp(2), связанного со сработавшим правилом (значение addr игнорируется).

       PTRACE_CONT
              Возобновляет  работу  остановленной  трассируемой  нити.  Если значение data не равно нулю, то оно
              считается номером сигнала, который надо доставить трассируемой нити; в противном случае сигнал  не
              передаётся.   Таким   образом,   например,  трассировщик  может  контролировать  передачу  сигнала
              трассируемой нити (значение addr игнорируется).

       PTRACE_SYSCALL
       PTRACE_SINGLESTEP
              Аналогично PTRACE_CONT они  перезапускают  остановленную  трассируемую  нить,  но  указывают,  что
              процесс  должен  быть  остановлен  перед входом/выходом из системного вызова, или после исполнения
              одной инструкции, соответственно (трассируемая нить  также,  как  обычно,  будет  остановлена  при
              получении  сигнала). С точки зрения трассировщика кажется, что трассируемая нить остановлена из-за
              получения сигнала SIGTRAP. Так, PTRACE_SYSCALL например, позволяет изучить  содержимое  аргументов
              перед  системным  вызовом,  а  при следующем PTRACE_SYSCALL можно просмотреть результат исполнения
              системного вызова. Аргумент data используется как в PTRACE_CONT (значение addr игнорируется).

       PTRACE_SET_SYSCALL (начиная с Linux 2.6.16)
              When in syscall-enter-stop, change the number of the system call that is about to be  executed  to
              the  number  specified  in  the  data  argument.  The addr argument is ignored.  This operation is
              currently supported only on arm (and arm64, though only for  backwards  compatibility),  but  most
              other  architectures have other means of accomplishing this (usually by changing the register that
              the userland code passed the system call number in).

       PTRACE_SYSEMU
       PTRACE_SYSEMU_SINGLESTEP (since Linux 2.6.14)
              For PTRACE_SYSEMU, continue and stop on entry to the next system call, which will not be executed.
              See the documentation on syscall-stops below.  For PTRACE_SYSEMU_SINGLESTEP, do the same but  also
              singlestep  if not a system call.  This call is used by programs like User Mode Linux that want to
              emulate all the tracee's system calls.  The data argument is treated as for PTRACE_CONT.  The addr
              argument is ignored.  These operations are currently supported only on x86.

       PTRACE_LISTEN (начиная с Linux 3.4)
              Перезапускает  остановленную  трассируемую  нить,  но  её  выполнение  не  начинается.  Полученное
              состояние  трассируемой  нити  подобно  процессу,  который  был  остановлен по SIGSTOP (или другим
              останавливающим  сигналом).  Дополнительную  информацию  смотрите   в   подразделе   «group-stop».
              PTRACE_LISTEN работает только для трассируемых нитей, присоединённых с помощью PTRACE_SEIZE.

       PTRACE_KILL
              Посылает трассируемой нити сигнал SIGKILL для его уничтожения (значения addr и data игнорируются).

              Это  действие  устарело;  не  используйте  его! Вместо него отправляйте SIGKILL напрямую с помощью
              kill(2) или tgkill(2). Проблема с действием PTRACE_KILL в том, что оно требует, чтобы трассируемая
              нить была режиме signal-delivery-stop, в противном случае оно может не  сработать  (т.  е.,  может
              завершиться  без  ошибок,  но  трассируемая нить не будет уничтожена). В отличие от него, отправка
              SIGKILL напрямую не имеет данного ограничения.

       PTRACE_INTERRUPT (начиная с Linux 3.4)
              Остановить трассируемый объект. Если трассируемый объект выполняется или спит в пространстве  ядра
              и  действует  PTRACE_SYSCALL,  то  системный  вызов  прерывается  и сообщается о syscall-exit-stop
              (прерванный  системный  вызов  перезапускается  при  перезапуске  трассируемого   объекта).   Если
              трассируемый  объект был уже остановлен по сигналу и ему был послан PTRACE_LISTEN, то трассируемый
              объект останавливается с PTRACE_EVENT_STOP и WSTOPSIG(status) возвращает сигнал остановки. Если  в
              этот  же  момент  генерируется  любое  другое  событие  ptrace-stop  (например, если трассируемому
              посылается сигнал), то возникает ptrace-stop. Если  ничего  из  вышеперечисленного  не  происходит
              (например,  если  трассируемый  выполняется  в пространстве пользователя), то он останавливается с
              PTRACE_EVENT_STOP и WSTOPSIG(status) == SIGTRAP. PTRACE_INTERRUPT работает только для трассируемых
              объектов, к которым подключились с помощью PTRACE_SEIZE.

       PTRACE_ATTACH
              Выполняет присоединение к процессу  с  указанным  pid,  делая  его  трассируемым  для  вызывающего
              процесса.  Трассируемой нити посылается SIGSTOP, но нет жёсткого правила, что она будет остановлен
              по завершению этого вызова; используйте  waitpid(2)  для  ожидания  остановки  трассируемой  нити.
              Дополнительную  информацию  смотрите  в подразделе «Присоединение и отсоединение» (значения addr и
              data игнорируются).

              Право    выполнять    PTRACE_ATTACH    определяется    проверкой     режима     доступа     ptrace
              PTRACE_MODE_READ_REALCREDS; смотрите ниже.

       PTRACE_SEIZE (начиная с Linux 3.4)
              Выполняет  присоединение  к  процессу,  указанному  в pid, делает его трассируемым для вызывающего
              процесса. В отличие  от  PTRACE_ATTACH,  PTRACE_SEIZE  не  останавливает  процесс.  О  group-stops
              сообщается  как  PTRACE_EVENT_STOP  и  WSTOPSIG(status) возвращает сигнал остановки. Автоматически
              присоединённые потомки останавливаются с PTRACE_EVENT_STOP и WSTOPSIG(status)  возвращает  SIGTRAP
              вместо  доставки  им  сигнала  SIGSTOP. При вызове execve(2) дополнительный SIGTRAP не посылается.
              Только подключённые с помощью PTRACE_SEIZE процессы могут  принимать  команды  PTRACE_INTERRUPT  и
              PTRACE_LISTEN.  Только  что  описанное поведение «захвата» (seized) наследуется потомками, которые
              автоматически    присоединяются    с    помощью    PTRACE_O_TRACEFORK,    PTRACE_O_TRACEVFORK    и
              PTRACE_O_TRACECLONE.  Значение  addr  должно  быть  равно  нулю.  В  data содержится битовая маска
              параметров ptrace, которая применяется сразу же.

              Право    выполнять    PTRACE_SEIZE    определяется     проверкой     режима     доступа     ptrace
              PTRACE_MODE_READ_REALCREDS; смотрите ниже.

       PTRACE_SECCOMP_GET_FILTER (начиная с Linux 4.4)
              Эта операция позволяет трассировщику получить дамп классических фильтров BPF трассируемого.

              Значение   addr   имеет  тип  integer  и  задаёт  индекс  фильтра  для  дампа.  Индекс  последнего
              установленного фильтра равен 0. Если addr больше количества установленных  фильтров,  то  операция
              завершается ошибкой ENOENT.

              Значение data является указателем на массив struct sock_filter достаточного размера для сохранения
              программы BPF, или NULL, если программа не будет сохраняться.

              При  успешном  выполнении возвращаемое значение — количество инструкций в программе BPF. Если data
              равнялось NULL, то возвращается значение, которое можно использовать для создания  массива  struct
              sock_filter корректного размера, который будет передан в последующем вызове.

              Данная  операция  завершается  ошибкой EACCES, если вызывающий не имеет мандата CAP_SYS_ADMIN, или
              если вызывающий находится в ограничительном  или  фильтрующем  режиме.  Если  фильтр,  на  который
              ссылается  адрес  addr,  не  является  классическим  фильтром BPF, то операция завершается ошибкой
              EMEDIUMTYPE.

              Эта  операция  доступна  только,  если  ядро  собрано  с   параметрами   CONFIG_SECCOMP_FILTER   и
              CONFIG_CHECKPOINT_RESTORE.

       PTRACE_DETACH
              Возобновляет   работу   остановленной   трассируемой  нити,  аналогично  PTRACE_CONT,  но  сначала
              отсоединяется от него. В Linux при помощи этого вызова трассируемая нить  может  быть  отсоединёна
              независимо от того, каким методом была запущена трассировка (значение addr игнорируется).

       PTRACE_GET_THREAD_AREA (начиная с Linux 2.6.0)
              Данная  операция выполняет задачу, подобную get_thread_area(2). Она читает элемент TLS из GDT, чей
              индекс передан в addr, помещает копию элемента в struct user_desc, указанную в data (в отличие  от
              get_thread_area(2), значение entry_number структуры struct user_desc игнорируется).

       PTRACE_SET_THREAD_AREA (начиная с Linux 2.6.0)
              Данная операция выполняет задачу, подобную set_thread_area(2). Она изменяет элемент TLS в GDT, чей
              индекс   указан  в  addr,  данными, переданными в структуре struct user_desc, на которую указывает
              data  (в  отличие  от  set_thread_area(2),  значение  entry_number  структуры   struct   user_desc
              игнорируется;  иначе  говоря,  данная  операция  ptrace  не  может  использоваться  для  выделения
              свободного элемента TLS).

       PTRACE_GET_SYSCALL_INFO (начиная с Linux 5.3)
              Возвращает информацию о системном вызове, который  привёл  к  останову.  Информация  помещается  в
              буфер,  указанный  в  аргументе  data,  который  должен  быть  указателем  на буфер с типом struct
              ptrace_syscall_info. Аргумент addr содержит размер буфера, на который указывает аргумент data  (т.
              е.,  sizeof(struct  ptrace_syscall_info)). Возвращаемое значение равно количеству байт, записанных
              ядром. Если размер записываемых  ядром  данных  больше  значения  из  аргумента  addr,  то  данные
              результата обрезаются.

              Структура ptrace_syscall_info содержит следующие поля:

                  struct ptrace_syscall_info {
                      __u8 op;        /* Type of system call stop */
                      __u32 arch;     /* AUDIT_ARCH_* value; see seccomp(2) */
                      __u64 instruction_pointer; /* CPU instruction pointer */
                      __u64 stack_pointer;    /* CPU stack pointer */
                      union {
                          struct {    /* op == PTRACE_SYSCALL_INFO_ENTRY */
                              __u64 nr;       /* System call number */
                              __u64 args[6];  /* System call arguments */
                          } entry;
                          struct {    /* op == PTRACE_SYSCALL_INFO_EXIT */
                              __s64 rval;     /* System call return value */
                              __u8 is_error;  /* System call error flag;
                                                 Boolean: does rval contain
                                                 an error value (-ERRCODE) or
                                                 a nonerror return value? */
                          } exit;
                          struct {    /* op == PTRACE_SYSCALL_INFO_SECCOMP */
                              __u64 nr;       /* System call number */
                              __u64 args[6];  /* System call arguments */
                              __u32 ret_data; /* SECCOMP_RET_DATA portion
                                                 of SECCOMP_RET_TRACE
                                                 return value */
                          } seccomp;
                      };
                  };

              Поля  op,  arch, instruction_pointer и stack_pointer определены для всех видов остановов системных
              вызовов ptrace. Оставшаяся структура является объединением; из неё нужно читать  только  те  поля,
              которые имеют смысл для конкретного вызова останова системного вызова, указанного в поле op.

              В поле op указывается одно из следующих значений (определены в <linux/ptrace.h>), определяющих тип
              возникшего останова и какая часть объединения заполнена:

              PTRACE_SYSCALL_INFO_ENTRY
                     Компонент объединения entry содержит информацию о входе в останов системного вызова.

              PTRACE_SYSCALL_INFO_EXIT
                     Компонент объединения exit содержит информацию о выходе из останова системного вызова.

              PTRACE_SYSCALL_INFO_SECCOMP
                     Компонент объединения seccomp содержит информацию об останове PTRACE_EVENT_SECCOMP.

              PTRACE_SYSCALL_INFO_NONE
                     Компонент объединения не содержит информации.

              In  case  of  system  call  entry  or  exit stops, the data returned by PTRACE_GET_SYSCALL_INFO is
              limited to type PTRACE_SYSCALL_INFO_NONE unless PTRACE_O_TRACESYSGOOD option  is  set  before  the
              corresponding system call stop has occurred.

   Смерть в момент ptrace
       Когда  (возможно,  многонитевой)  процесс  получает уничтожающий сигнал (из-за того, что обработчик равен
       SIG_DFL и что действием по умолчанию является уничтожение процесса), все нити  завершают  работу  (exit).
       Трассируемые  нити сообщают о своей смерти своим трассировщикам. Уведомления об этом событии доставляется
       с помощью waitpid(2).

       Заметим, что уничтожающий сигнал сначала вызовет вхождение в режим signal-delivery-stop (только для одной
       трассируемой нити), и только после этого будет внедрён трассировщиком (или после того,  как  был  отослан
       нити,  которая не является трассируемой), затем все трассируемые нити в многонитевом процессе завершаются
       по сигналу (термин «signal-delivery-stop» объяснён далее).

       Сигнал SIGKILL не генерирует режим signal-delivery-stop и поэтому трассировщик  не  может  подавить  его.
       Сигнал  SIGKILL  уничтожает  даже  внутри  системных  вызовов  (syscall-exit-stop  не  генерируется перед
       уничтожением по SIGKILL). Конечным результатом SIGKILL всегда является  уничтожение  процесса  (всех  его
       нитей), даже если для некоторых нитей процесса выполняется трассировка.

       Когда  трассируемая  нить  вызывает  _exit(2),  он  сообщает о своём уничтожении своему трассировщику. На
       оставшиеся нити ни какого влияния не оказывается.

       Если какая-нибудь нить вызывает exit_group(2), то каждая трассируемая нить в этой группе нитей сообщает о
       своём уничтожении своему трассировщику.

       Если   установлен   флаг   PTRACE_O_TRACEEXIT,   то   перед   непосредственным   уничтожением   возникает
       PTRACE_EVENT_EXIT.  Это  случается  при  выходе посредством exit(2), exit_group(2) и из-за уничтожения по
       сигналу (за исключением SIGKILL, в зависимости от версии  ядра;  смотрите  ДЕФЕКТЫ  ниже)  и  когда  нити
       многонитевой процесса разрушаются при execve(2).

       The tracer cannot assume that the ptrace-stopped tracee exists.  There are many scenarios when the tracee
       may die while stopped (such as SIGKILL).  Therefore, the tracer must be prepared to handle an ESRCH error
       on  any  ptrace  operation.   Unfortunately,  the  same error is returned if the tracee exists but is not
       ptrace-stopped (for commands which require a stopped tracee), or if it is not traced by the process which
       issued the ptrace call.  The tracer needs to keep track of the stopped/running state of the  tracee,  and
       interpret ESRCH as "tracee died unexpectedly" only if it knows that the tracee has been observed to enter
       ptrace-stop.   Note  that  there  is no guarantee that waitpid(WNOHANG) will reliably report the tracee's
       death status if a ptrace operation returned ESRCH.  waitpid(WNOHANG) may  return  0  instead.   In  other
       words, the tracee may be "not yet fully dead", but already refusing ptrace operations.

       Трассировщик  не  может  предполагать,  что  всегда  поймает завершение существования трассируемой нити с
       помощью WIFEXITED(status) или WIFSIGNALED(status); есть несколько случаев,  когда  этого  не  происходит.
       Например,  если  нить  — не лидер группы нитей — вызывает execve(2) и исчезает; её PID больше не появится
       снова, и все последующие остановки по ptrace будут приходить от PID лидера группы нитей.

   Состояния останова
       Трассируемый может находиться в двух состояниях: выполнения или остановки. В целях ptrace,  трассируемый,
       заблокированный  в  системном  вызове (например, read(2), pause(2) и т.д.), считается выполняющимся, даже
       если он заблокирован уже  долго.  Состояние  трассируемого  после  PTRACE_LISTEN  находится,  отчасти,  в
       «сумеречной  зоне»:  не не в каком-либо из ptrace-stop (команды ptrace не будут с ним работать и он будет
       посылать уведомления waitpid(2)), но он также может считаться за «остановленный», так как он не выполняет
       инструкций (не планируется для этого), и если он был в group-stop до PTRACE_LISTEN, он не будет  отвечать
       на сигналы до тех пор, пока не получит SIGCONT.

       Есть  много  разновидностей  останова,  и  в  обсуждении ptrace они часто объединены. Поэтому очень важно
       использовать точную терминологию.

       В этой справочной странице любое  состояние  останова,  в  котором  трассируемая  нить  готова  выполнить
       действия  ptrace  трассировщика,  называется  ptrace-stop. В свою очередь, ptrace-stop можно разделить на
       signal-delivery-stop, group-stop, syscall-stop, PTRACE_EVENT stops  и  так  далее.  Далее  эти  состояния
       останова будут описаны подробней.

       Когда  выполняющаяся  трассируемая нить входит в ptrace-stop, это видит трассировщик с помощью waitpid(2)
       (или  через  другой  системный  вызов  «wait»).  В  большей  части  текста  данной  справочной   страницы
       предполагается, что трассировщик ждёт с помощью:

           pid = waitpid(pid_or_minus_1, &status, __WALL);

       О  трассируемой  нити  в  состоянии  ptrace-stop сообщается возвратом pid большим 0 и значением истины по
       WIFSTOPPED(status).

       Флаг __WALL не содержит флагов WSTOPPED и WEXITED, но подразумевает их назначение.

       Устанавливать флаг WCONTINUED при вызове waitpid(2) не рекомендуется: состояние «continued»  относится  к
       определённому процессу и его поглощение может запутать реального родителя трассируемой нити.

       Использование  флага  WNOHANG может привести к тому, что waitpid(2) вернёт 0 («не ждать результатов, если
       они не готовы»), даже если трассировщик знает, что должно быть уведомление. Пример:

           errno = 0;
               ptrace(PTRACE_CONT, pid, 0L, 0L);
               if (errno == ESRCH) {
                   /* трассируемая нить мертва */
                   r = waitpid(tracee, &status, __WALL | WNOHANG);
                   /* r может быть 0 ! */
               }

       Существуют следующие разновидности ptrace-stop: signal-delivery-stop, group-stop, остановки PTRACE_EVENT,
       syscall-stop. Все они могут быть получены по waitpid(2) с значением истинным  по  WIFSTOPPED(status).  Их
       можно  различить,  если  проверить  значение  status>>8,  и, если есть неоднозначность этого значения, то
       запросив PTRACE_GETSIGINFO (замечание: для  выполнения  этой  проверки  не  может  использоваться  макрос
       WSTOPSIG(status), так как он возвращает значение (status>>8) & 0xff).

   Signal-delivery-stop
       When  a  (possibly  multithreaded)  process  receives  any  signal  except SIGKILL, the kernel selects an
       arbitrary thread which handles the signal.  (If the signal is generated with tgkill(2), the target thread
       can  be  explicitly  selected  by  the  caller.)   If  the  selected  thread   is   traced,   it   enters
       signal-delivery-stop.   At  this  point,  the  signal  is  not  yet  delivered to the process, and can be
       suppressed by the tracer.  If the tracer doesn't suppress the signal, it passes the signal to the  tracee
       in  the next ptrace restart operation.  This second step of signal delivery is called signal injection in
       this manual page.  Note that if the signal is blocked,  signal-delivery-stop  doesn't  happen  until  the
       signal is unblocked, with the usual exception that SIGSTOP can't be blocked.

       Signal-delivery-stop  наблюдается  трассировщиком  посредством waitpid(2), возвращающим истинное значения
       для WIFSTOPPED(status) с сигналом, который возвращается по  WSTOPSIG(status).  Если  возвращается  сигнал
       SIGTRAP,  то он может быть разновидностью ptrace-stop; смотрите разделы «Syscall-stops» и «execve» далее.
       Если WSTOPSIG(status) возвращает останавливающий сигнал, то это может быть group-stop, смотрите далее.

   Внедрение и подавление сигнала
       После обнаружения трассировщиком signal-delivery-stop, он должен перезапустить трассируемую нить вызовом

           ptrace(PTRACE_restart, pid, 0, sig)

       where PTRACE_restart is one of the restarting ptrace operations.  If sig is  0,  then  a  signal  is  not
       delivered.   Otherwise,  the  signal sig is delivered.  This operation is called signal injection in this
       manual page, to distinguish it from signal-delivery-stop.

       Значение sig может отличаться  от  значения  WSTOPSIG(status):  трассировщик  может  поменять  внедряемый
       сигнал.

       Заметим,  что подавленный сигнал всё равно заставит системные вызовы завершиться как можно скорее. В этом
       случае системные вызовы будут перезапущены: если трассировщик использует  PTRACE_SYSCALL,  то  обнаружит,
       когда   трассируемая   нить   повторно   выполнила   прерванный  системный  вызов  (или  системный  вызов
       restart_syscall(2) для некоторых системных вызовов, которые используют другой механизм перезапуска). Даже
       системные вызовы (такие как poll(2)), которые не перезапускаются по  сигналу,  будут  перезапущены  после
       подавления  сигнала;  однако,  в  ядре  существуют  дефекты,  из-за  которых  некоторые  системные вызовы
       завершаются с ошибкой EINTR, даже если наблюдаемый сигнал не был внедрён в трассируемую нить.

       Перезапускающие  действия  ptrace,  выдаваемые  в  ptrace-stops,  отличные  от  signal-delivery-stop,  не
       гарантируют  внедрения сигнала, даже если значение sig не равно нулю. Об ошибках не сообщается; ненулевое
       значение sig может быть просто проигнорировано. Пользователи ptrace не  должны  пытаться  «создать  новый
       сигнал» таким способом — используйте вместо этого tgkill(2).

       The  fact  that  signal injection operations may be ignored when restarting the tracee after ptrace stops
       that are not signal-delivery-stops is a cause of confusion among ptrace users.  One typical  scenario  is
       that the tracer observes group-stop, mistakes it for signal-delivery-stop, restarts the tracee with

           ptrace(PTRACE_restart, pid, 0, stopsig)

       пытаясь внедрить stopsig, но stopsig игнорируется и трассируемая нить продолжает выполняться.

       Сигнал  SIGCONT  имеет  побочный  эффект  —  пробуждает (все нити) процесс, находящийся в group-stop. Это
       случается перед signal-delivery-stop. Трассировщик не может повлиять на это побочное действие  (он  может
       только  подавить  внедрение  сигнала,  что  приводит  к  тому, что обработчик SIGCONT не будет выполнен в
       трассируемой нити, если он установлен). Фактически,  пробуждение  из  group-stop  может  следовать  после
       signal-delivery-stop  для  сигнала(ов)  отличных  от  SIGCONT, если они ожидают момента доставки SIGCONT.
       Другими словами, SIGCONT может быть не первым сигналом, который обнаруживает трассируемую нить  после  её
       посылки.

       Останавливающие  сигналы  заставляют  процесс  (все  его нити) войти в group-stop. Данный побочный эффект
       возникает после внедрения сигнала, и поэтому может быть отменён трассировщиком.

       В Linux 2.4 и более ранних версиях, сигнал SIGSTOP не может быть внедрён.

       Действие PTRACE_GETSIGINFO может использоваться для получения структуры siginfo_t, которая  соответствует
       доставленному  сигналу.  Для  её  изменения  можно использовать PTRACE_SETSIGINFO. Если PTRACE_SETSIGINFO
       использовалась для изменения siginfo_t, то поле si_signo и параметр sig в перезапускающем действии должны
       совпадать, иначе результат непредсказуем.

   Group-stop
       Когда (возможно многонитевой) процесс получает останавливающий сигнал, все нити останавливаются. Если для
       какой-то нити выполняется трассировка, то она входит в режим  group-stop.  Заметим,  что  останавливающий
       сигнал  сначала  приведёт  к signal-delivery-stop (только в одной трассируемой нити) и только затем будет
       внедрён  трассировщиком  (или  после  того,  как  будет  отправлен  нити,  над  которой  не   выполняется
       трассировка), будет начат group-stop в всех трассируемых нитях многонитевого процесса. Как обычно, каждая
       трассируемая нить сообщает о group-stop соответствующему трассировщику.

       Group-stop  обнаруживается трассировщиком с помощью waitpid(2), который возвращается с истинным значением
       WIFSTOPPED(status) и останавливающим сигналом из WSTOPSIG(status). Тот же результат возвращается  другими
       классами ptrace-stops, поэтому рекомендуется выполнять вызов

           ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo)

       Вызова  можно  избежать,  если  сигнал  не равен SIGSTOP, SIGTSTP, SIGTTIN или SIGTTOU; только эти четыре
       сигнала являются  останавливающими.  Если  трассировщик  видит  что-то  другое,  то  это  не  может  быть
       group-stop.  В  противном  случае,  трассировщику нужно вызвать PTRACE_GETSIGINFO. Если PTRACE_GETSIGINFO
       завершается с ошибкой EINVAL, то это определённо group-stop (возможны другие коды ошибок, например, ESRCH
       («нет такого процесса»), если трассируемая нить уничтожена по SIGKILL).

       Если подключение  к  трассируемому  было  сделано  с  помощью  PTRACE_SEIZE,  то  group-stop  указывается
       PTRACE_EVENT_STOP:   status>>16   ==   PTRACE_EVENT_STOP.   Это   позволяет   обнаружить  group-stop  без
       дополнительного вызова PTRACE_GETSIGINFO.

       Начиная с Linux 2.6.38, после того как трассировщик увидит ptrace-stop трассируемой нити  и  пока  он  не
       перезапустит или завершит её, трассируемая нить не будет выполняться, и не будет посылать уведомления (за
       исключением  уничтожения  по  SIGKILL)  трассировщику,  даже  если  трассировщик  войдёт  в  другой вызов
       waitpid(2).

       The kernel behavior described in the previous paragraph causes a problem  with  transparent  handling  of
       stopping signals.  If the tracer restarts the tracee after group-stop, the stopping signal is effectively
       ignored—the  tracee  doesn't  remain  stopped,  it runs.  If the tracer doesn't restart the tracee before
       entering into the next waitpid(2), future SIGCONT signals will not be reported to the tracer; this  would
       cause the SIGCONT signals to have no effect on the tracee.

       Начиная  с  Linux  3.4,  появился  способ  преодоления  этой проблемы: вместо PTRACE_CONT для перезапуска
       трассируемой нити можно использовать PTRACE_LISTEN,  при  которой  она  не  выполняется,  а  ждёт  нового
       события, и это можно прочитать с помощью waitpid(2) (например, когда был перезапуск по SIGCONT).

   Остановки PTRACE_EVENT
       Если   трассировщик   устанавливает   флаги  PTRACE_O_TRACE_*,  то  трассируемая  нить  будет  входить  в
       ptrace-stop-ы, называемые остановками PTRACE_EVENT.

       PTRACE_EVENT stops are observed by the tracer  as  waitpid(2)   returning  with  WIFSTOPPED(status),  and
       WSTOPSIG(status) returns SIGTRAP (or for PTRACE_EVENT_STOP, returns the stopping signal if tracee is in a
       group-stop).  An additional bit is set in the higher byte of the status word: the value status>>8 will be

           ((PTRACE_EVENT_foo<<8) | SIGTRAP).

       Могут происходить следующие события:

       PTRACE_EVENT_VFORK
              Остановка  перед  возвратом из vfork(2) или clone(2) с флагом CLONE_VFORK. Когда трассируемая нить
              продолжает  выполняться  после  этой  остановки,  она  будет  ждать  выхода/exec   потомка   перед
              продолжением своего исполнения (другими словами, обычное поведение при vfork(2)).

       PTRACE_EVENT_FORK
              Остановка перед возвратом из fork(2) или clone(2) с установленным сигналом выхода SIGCHLD.

       PTRACE_EVENT_CLONE
              Остановка перед возвратом из clone(2).

       PTRACE_EVENT_VFORK_DONE
              Остановка  перед  возвратом  из vfork(2) или clone(2) с установленным флагом CLONE_VFORK, но после
              того, как потомок разблокирует эту трассируемую нить, завершив работу или выполнив exec.

       Для всех четырёх остановок, описанных выше, остановка происходит в родителе (т. е., трассируемой нити), а
       не в только что созданной нити. Для получения ID новой нити может использовать PTRACE_GETEVENTMSG.

       PTRACE_EVENT_EXEC
              Остановка перед возвратом из execve(2). Начиная с  Linux  3.0,  PTRACE_GETEVENTMSG  возвращает  ID
              бывшей нити.

       PTRACE_EVENT_EXIT
              Остановка  перед выходом (включая уничтожение из exit_group(2)), уничтожение от сигнала или выход,
              вызванный execve(2) в многонитевом  процессе.  PTRACE_GETEVENTMSG  возвращает  код  выхода.  Можно
              прочитать   значения   регистров  (в  отличие  от  случая,  когда  происходит  «реальный»  выход).
              Трассируемая нить всё ещё существует; для завершения выхода должно быть выполнено  отсоединение  с
              помощью PTRACE_CONT или PTRACE_DETACH.

       PTRACE_EVENT_STOP
              Остановка  вызвана  командой  PTRACE_INTERRUPT,  или  group-stop,  или  начальным  ptrace-stop при
              присоединении к новому потомку (только если для присоединения использовалась PTRACE_SEIZE).

       PTRACE_EVENT_SECCOMP
              Остановка   вызвана   правилом   seccomp(2)   из-за   элемента   syscall   трассируемого,    когда
              PTRACE_O_TRACESECCOMP  была установлена трассировщиком. Данные сообщения события seccomp (из части
              SECCOMP_RET_DATA фильтрующего  правила  seccomp)  можно  получить  с  помощью  PTRACE_GETEVENTMSG.
              Семантика данного останова подробно описана в отдельном разделе далее.

       PTRACE_GETSIGINFO   при  остановке  PTRACE_EVENT  возвращает  SIGTRAP  в  si_signo,  а  значение  si_code
       устанавливается в (event<<8) | SIGTRAP.

   Syscall-stop
       Если  трассируемый  был  перезапущен  по  PTRACE_SYSCALL  или  PTRACE_SYSEMU,  то  он  входит   в   режим
       syscall-enter-stop  сразу перед тем как войти в какой-либо системный вызов (который не будет выполняться,
       если перезапуск был из-за PTRACE_SYSEMU, независимо от каких-либо изменений в регистрах  на  этот  момент
       или   если   трассируемый   перезапускается   после   своей   остановки).   Неважно  какой  метод  вызвал
       syscall-entry-stop,  если  трассировщик  перезапускает  трассируемого  с   помощью   PTRACE_SYSCALL,   то
       трассируемый входит в syscall-exit-stop при окончании системного вызова, или если он прерывается сигналом
       (то  есть,  signal-delivery-stop  никогда  не  возникает между syscall-enter-stop и syscall-exit-stop; он
       возникает после syscall-exit-stop). Если трассируемый продолжает выполнение с помощью  какого-то  другого
       метода   (включая  PTRACE_SYSEMU),  то  syscall-exit-stop  не  возникает.  Заметим,  что  все  упоминания
       PTRACE_SYSEMU применяются и к PTRACE_SYSEMU_SINGLESTEP.

       Однако даже если трассируемый продолжил выполнение с помощью  PTRACE_SYSCALL,  это  не  гарантирует,  что
       следующая   остановка  будет  syscall-exit-stop.  Также,  трассируемый  может  остановиться  в  остановке
       PTRACE_EVENT (включая остановку seccomp), при выходе  (если  он  вошёл  в  _exit(2)  или  exit_group(2)),
       уничтожении  по  сигналу SIGKILL, или тихом уничтожении (если он является лидером группы нитей, возникает
       execve(2) в другой нити, и эта нить не трассируется тем же трассировщиком; эта ситуация описана далее).

       Syscall-enter-stop и syscall-exit-stop обнаруживаются трассировщиком из waitpid(2), возвращающем истинное
       значение WIFSTOPPED(status) и WSTOPSIG(status) выдающем SIGTRAP. Если трассировщиком был установлен  флаг
       PTRACE_O_TRACESYSGOOD, то WSTOPSIG(status) выдаст значение (SIGTRAP | 0x80).

       Syscall-stop  можно  отличить  от signal-delivery-stop по SIGTRAP, запросив PTRACE_GETSIGINFO в следующих
       случаях:

       si_code <= 0
              SIGTRAP was delivered as a result of a user-space action, for example, a system  call  (tgkill(2),
              kill(2),  sigqueue(3),  etc.),  expiration  of  a  POSIX timer, change of state on a POSIX message
              queue, or completion of an asynchronous I/O operation.

       si_code == SI_KERNEL (0x80)
              SIGTRAP был послан ядром.

       si_code == SIGTRAP или si_code == (SIGTRAP|0x80)
              Это syscall-stop.

       Однако, syscall-stop происходят очень часто (дважды за системный вызов), и  выполнение  PTRACE_GETSIGINFO
       для каждого syscall-stop может быть отчасти накладно.

       Некоторые  архитектуры  позволяют  отличать  эти  случаи  по  значениям  регистров. Например, на x86, при
       syscall-enter-stop rax ==  -ENOSYS.  Так  как  SIGTRAP  (как  и  любой  сигнал)  всегда  возникает  после
       syscall-exit-stop,  и  в  этот  момент  rax  почти  никогда  не  содержит  ENOSYS,  SIGTRAP  выглядит как
       «syscall-stop,  который  не  syscall-enter-stop»;  другими  словами,   это   выглядит   как   «блуждающий
       syscall-exit-stop»  и таким способом может быть обнаружен. Но определение этим способом очень ненадёжно и
       лучше его не использовать.

       Использование флага PTRACE_O_TRACESYSGOOD — рекомендуемый метод различения syscall-stop от похожих на них
       других ptrace-stop, так как это надёжно и не приводит к ухудшению производительности.

       Syscall-enter-stop и syscall-exit-stop неотличимы друг от друга трассировщиком.  Трассировщику  требуется
       отслеживать   последовательность   ptrace-stop,   чтобы   правильно  истолковать  syscall-enter-stop  как
       syscall-exit-stop  или  наоборот.  В  общем,  за  syscall-enter-stop  всегда  следует  syscall-exit-stop,
       PTRACE_EVENT  остановка  или  уничтожение  трассируемого;  никаких других ptrace-stop не может возникнуть
       между ними. Однако заметим, что остановки seccomp (смотрите ниже) могут приводить к syscall-exit-stop без
       предварительного  syscall-entry-stop.  Если  используется  seccomp,  необходима  осторожность  чтобы   не
       посчитать такие остановки за syscall-entry-stop.

       Если   после   syscall-enter-stop   трассировщик   использует   перезапускающее   действие,  отличное  от
       PTRACE_SYSCALL, то syscall-exit-stop не генерируется.

       PTRACE_GETSIGINFO при syscall-stop возвращает SIGTRAP в  si_signo,  значение  si_code  устанавливается  в
       SIGTRAP или (SIGTRAP|0x80).

   PTRACE_EVENT_SECCOMP stops (Linux 3.5 to Linux 4.7)
       Поведение   остановок  PTRACE_EVENT_SECCOMP  и  их  взаимодействие  с  другими  видами  остановок  ptrace
       различается от версии к версии. Здесь описано поведение от их  появления  до  Linux  4.7  (включительно).
       Поведение в более новых версиях описано в следующем разделе.

       Остановка  PTRACE_EVENT_SECCOMP возникает из-за срабатывания правила SECCOMP_RET_TRACE. Она не зависит от
       используемых методов перезапуска системного вызова. Примечательно, что seccomp по прежнему работает даже,
       если  трассируемый  был  перезапущен  с  помощью  PTRACE_SYSEMU  и  этот  системный  вызов  безоговорочно
       пропускается.

       Перезапуск  из этой остановки будет вести себя как если бы остановка возникла прямо перед рассматриваемым
       системным  вызовом.  В  частности,  PTRACE_SYSCALL  и  PTRACE_SYSEMU  как  обычно   вызовут   последующий
       syscall-entry-stop.  Однако,  если после PTRACE_EVENT_SECCOMP номер системного вызова отрицательный, то и
       syscall-entry-stop и сам системный вызов будут пропущены. Это означает, что если номер системного  вызова
       отрицательный  после  PTRACE_EVENT_SECCOMP  и  трассируемый  перезапущен  с  помощью  PTRACE_SYSCALL,  то
       следующая наблюдаемая остановка будет syscall-exit-stop, а не syscall-entry-stop, как можно было ожидать.

   Остановки PTRACE_EVENT_SECCOMP (начиная с Linux 4.8)
       Начиная  с  Linux  4.8,  остановка  PTRACE_EVENT_SECCOMP  была  преобразована  при  возникновении   между
       syscall-entry-stop    и    syscall-exit-stop.   Заметим,   что   seccomp   больше   не   выполняется   (и
       PTRACE_EVENT_SECCOMP не будет выдан), если системный вызов пропускается из-за PTRACE_SYSEMU.

       Функционально,  остановка  PTRACE_EVENT_SECCOMP  работает  как  syscall-entry-stop  (т.  е.,  продолжение
       использования  PTRACE_SYSCALL  приведёт  к  syscall-exit-stop, может измениться номер системного вызова и
       любые другие регистры, видимые выполняемому в будущем системному вызову). Заметим, что это может быть, но
       не обязательно предваряется syscall-entry-stop.

       После остановки PTRACE_EVENT_SECCOMP,  seccomp будет  выполнен  повторно  с  правилом  SECCOMP_RET_TRACE,
       которое  теперь  работает  также как SECCOMP_RET_ALLOW. Точнее говоря, это означает, что если регистры не
       изменились во время остановки PTRACE_EVENT_SECCOMP,то после этого системный вызов будет разрешён.

   Остановки PTRACE_SINGLESTEP
       [Пока не описаны.]

   Информационные и перезапускающие действия ptrace
       Для большинства  действий  ptrace  (все,  за  исключением  PTRACE_ATTACH,  PTRACE_SEIZE,  PTRACE_TRACEME,
       PTRACE_INTERRUPT и PTRACE_KILL) требуется, чтобы трассируемая нить была в режиме ptrace-stop, в противном
       случае они завершаются с ошибкой ESRCH.

       Когда  трассируемая нить в ptrace-stop, трассировщик может читать и записывать данные в трассируемую нить
       с помощью информационных действий. Эти действия оставляют трассируемую нить в состоянии ptrace-stop:

           ptrace(PTRACE_PEEKTEXT/PEEKDATA/PEEKUSER, pid, addr, 0);
           ptrace(PTRACE_POKETEXT/POKEDATA/POKEUSER, pid, addr, long_val);
           ptrace(PTRACE_GETREGS/GETFPREGS, pid, 0, &struct);
           ptrace(PTRACE_SETREGS/SETFPREGS, pid, 0, &struct);
           ptrace(PTRACE_GETREGSET, pid, NT_foo, &iov);
           ptrace(PTRACE_SETREGSET, pid, NT_foo, &iov);
           ptrace(PTRACE_GETSIGINFO, pid, 0, &siginfo);
           ptrace(PTRACE_SETSIGINFO, pid, 0, &siginfo);
           ptrace(PTRACE_GETEVENTMSG, pid, 0, &long_var);
           ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_flags);

       Заметим, что о некоторых ошибках не сообщается. Например, установка информации о сигнале (siginfo)  может
       никак  не отразиться в некоторых ptrace-stop, при этом вызов может завершиться без ошибок (возвращается 0
       и значение errno не устанавливается); действие PTRACE_GETEVENTMSG может выполниться без ошибок и  вернуть
       произвольное значение, если текущий ptrace-stop не описан как возвращающий какое-то осмысленное сообщение
       о событии.

       Вызов

           ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_flags);

       затрагивает  одну трассируемую нить. Текущие флаги трассируемой нити заменяются. Флаги, наследуемые новой
       трассируемой нитью, создаются и «автоматически присоединяются» через активные  флаги  PTRACE_O_TRACEFORK,
       PTRACE_O_TRACEVFORK или PTRACE_O_TRACECLONE.

       Другая  группа  действий  заставляет трассируемую нить, находящуюся в ptrace-stop, выполняться. Они могут
       иметь вид:

           ptrace(cmd, pid, 0, sig);

       где значение cmd равно  PTRACE_CONT,  PTRACE_LISTEN,  PTRACE_DETACH,  PTRACE_SYSCALL,  PTRACE_SINGLESTEP,
       PTRACE_SYSEMU  или  PTRACE_SYSEMU_SINGLESTEP.  Если  трассируемая  нить  в signal-delivery-stop, то в sig
       указывается сигнал,  который  будет  внедрён  (если  не  равен  нулю).  В  противном  случае,  sig  может
       игнорироваться  (при  перезапуске  трассируемой  нити  из ptrace-stop в отличный от signal-delivery-stop,
       рекомендуется передавать в sig значение 0).

   Присоединение и отсоединение
       Нить можно присоединить к трассировщику с помощью вызова

           ptrace(PTRACE_ATTACH, pid, 0, 0);

       или

           ptrace(PTRACE_SEIZE, pid, 0, PTRACE_O_flags);

       PTRACE_ATTACH посылает в нить SIGSTOP. Если трассировщик хочет отменить действие SIGSTOP, ему  нужно  его
       подавить.  Заметим,  что  если  при  присоединении  в эту нить в тоже время посылаются другие сигналы, то
       трассировщик может увидеть, что трассируемая нить сначала вошла в signal-delivery-stop из этих  сигналов!
       Обычной практикой является повторное внедрение этих сигналов до тех пор, пока не будет обнаружен SIGSTOP,
       а  затем подавление внедрения SIGSTOP. Здесь есть ошибка в проектировании в том, что присоединение ptrace
       и одновременно доставляемый SIGSTOP могут состязаться и одновременный SIGSTOP может быть утерян.

       Так как при присоединении посылается SIGSTOP и трассировщик обычно подавляет его, то это может привести к
       блуждающему возврату EINTR из в данный момент выполняемого системного вызова  в  трассируемой  нити,  как
       описано в разделе «Внедрение и отмена сигнала».

       Начиная  с Linux 3.4, вместо PTRACE_ATTACH можно использовать PTRACE_SEIZE. PTRACE_SEIZE не останавливает
       присоединённый. Если вам нужно остановить его после присоединения (или в любое другое время) без отправки
       каких-либо, используйте действие PTRACE_INTERRUPT.

       The operation

           ptrace(PTRACE_TRACEME, 0, 0, 0);

       включает трассировку вызвавшей нити. Нить продолжает выполняться (не входит в  ptrace-stop).  Обычно,  за
       PTRACE_TRACEME следует

           raise(SIGSTOP);

       и это позволяет родителю (который теперь трассировщик) отследить signal-delivery-stop.

       Если   включены  флаги  PTRACE_O_TRACEFORK,  PTRACE_O_TRACEVFORK  или  PTRACE_O_TRACECLONE,  то  потомок,
       создаваемый, соответственно,  vfork(2)  или  clone(2)  с  флагом  CLONE_VFORK,  fork(2)  или  clone(2)  с
       установленным выходным сигналом равным SIGCHLD, и другими видами clone(2), автоматически присоединяется к
       тому же трассировщику, которой трассирует их родителя. Сигнал SIGSTOP доставляется потомку, заставляя его
       войти в signal-delivery-stop после завершения системного вызова, который его создал.

       Отсоединение от трассируемой нити выполняется с помощью:

           ptrace(PTRACE_DETACH, pid, 0, sig);

       PTRACE_DETACH  является  перезапускающей  операцией,  поэтому она требует, чтобы трассируемая нить была в
       ptrace-stop. Если трассируемая нить в signal-delivery-stop, то может быть  внедрён  сигнал.  В  противном
       случае параметр sig может быть проигнорирован.

       If the tracee is running when the tracer wants to detach it, the usual solution is to send SIGSTOP (using
       tgkill(2),   to   make   sure  it  goes  to  the  correct  thread),  wait  for  the  tracee  to  stop  in
       signal-delivery-stop for SIGSTOP and then detach it (suppressing SIGSTOP injection).   A  design  bug  is
       that  this  can  race  with concurrent SIGSTOPs.  Another complication is that the tracee may enter other
       ptrace-stops and needs to be restarted and  waited  for  again,  until  SIGSTOP  is  seen.   Yet  another
       complication  is  to  be  sure  that the tracee is not already ptrace-stopped, because no signal delivery
       happens while it is—not even SIGSTOP.

       Если  трассировщик  завершает  работу,  то  все   трассируемые   нити   автоматически   отсоединяются   и
       перезапускаются,  если  они  не  в  group-stop.  Выполнение  перезапуска  из group-stop в настоящее время
       содержит ошибки, но «плановым» поведением считается оставить трассируемую нить остановленной и  подождать
       SIGCONT. Если трассируемая нить перезапускается из signal-delivery-stop, то внедряется ожидающий сигнал.

   Выполнение execve(2) во время ptrace
       Когда одна нить многонитевого процесса вызывает execve(2), то ядро уничтожает все остальные нити процесса
       и  сбрасывает  ID  выполняющейся  нити  в значение ID группы нитей (ID процесса. Или, говоря иначе, когда
       многонитевой процесс выполняет execve(2), то по завершению вызова это  выглядит  как  если  бы  execve(2)
       произошёл  в  лидере группе нитей, независимо от того, какая нить вызвала execve(2)). Такой сброс ID нити
       запутывает трассировщиков:

       •  Все остальные нити останавливаются в останове PTRACE_EVENT_EXIT, если включён флаг PTRACE_O_TRACEEXIT.
          Затем все остальные нити, за исключением лидера группы нитей, сообщают о завершении, как если  бы  они
          кончили работу с помощью _exit(2) с кодом выхода 0.

       •  У  исполняемой трассируемой нити изменяется ID, так как она выполняет execve(2) (помните, что в ptrace
          «pid», возвращаемый из waitpid(2) или подаваемый в вызовы ptrace, это ID трассируемой нити).  То  есть
          ID трассируемой нити сбрасывается в значение ID своего процесса, который равен ID лидера группы нитей.

       •  Затем происходит остановка PTRACE_EVENT_EXEC, если включён флаг PTRACE_O_TRACEEXEC.

       •  Если  в  это  время  лидер  группы  нитей  сообщил о своей остановке PTRACE_EVENT_EXIT в это время, то
          трассировщику кажется, что завершившийся лидер группы «возник из ниоткуда»  (замечание:  лидер  группы
          нитей не сообщает о завершении через WIFEXITED(status) до тех пор, пока есть одна работающая нить. Это
          не  даёт  возможности  трассировщику  увидеть его завершение и повторное появление). Если лидер группы
          нитей всё ещё выполнялся, то для трассировщика может казаться, что  лидер  группы  нитей  вернулся  из
          другого  системного вызова в который входил, или даже «вернулся из системного вызова, хотя не был ни в
          каком  системном  вызове».  Если  лидер  группы  нитей  не  трассируется  (или   трассируется   другим
          трассировщиком),  то  во время execve(2) он выглядит так, как если бы стал трассируемым трассировщиком
          выполняющейся трассируемой нити.

       Все перечисленные выше эффекты происходят из-за смены ID трассируемой нити.

       В этой ситуации рекомендуется использовать флаг  PTRACE_O_TRACEEXEC.  Во-первых,  он  включает  остановку
       PTRACE_EVENT_EXEC,  которая  происходит перед возвратом из execve(2). В этой остановке трассировщик может
       использовать PTRACE_GETEVENTMSG для получения предыдущего ID трассируемой нити (эта возможность появилась
       в Linux 3.0). Во-вторых, флаг PTRACE_O_TRACEEXEC отключает устаревшую генерацию SIGTRAP при execve(2).

       Когда трассировщик получает уведомление об остановке PTRACE_EVENT_EXEC, гарантируется, что за исключением
       этой трассируемой нити и лидера группы нитей, больше живых нитей в этом процессе нет.

       On receiving the PTRACE_EVENT_EXEC stop notification, the tracer should clean up all  its  internal  data
       structures describing the threads of this process, and retain only one data structure—one which describes
       the single still running tracee, with

           thread ID == thread group ID == process ID.

       Пример: две нити вызывают execve(2) одновременно:

       *** мы получаем syscall-enter-stop в нити 1: **
       PID1 execve("/bin/foo", "foo" <unfinished ...>
       *** мы выдаём PTRACE_SYSCALL для нити 1 **
       *** мы получаем syscall-enter-stop в нити 2: **
       PID2 execve("/bin/bar", "bar" <unfinished ...>
       *** мы выдаём PTRACE_SYSCALL для нити 2 **
       *** мы получаем PTRACE_EVENT_EXEC for PID0, мы выдаём PTRACE_SYSCALL **
       *** мы получаем syscall-exit-stop для PID0: **
       PID0 <... execve resumed> )             = 0

       Если  флаг  PTRACE_O_TRACEEXEC  не  действует на выполняющуюся трассируемую нить и если трассируемая нить
       подключена с помощью PTRACE_ATTACH, а не PTRACE_SEIZE, то ядро доставляет ей дополнительный SIGTRAP после
       возврата из execve(2). Это обычный сигнал (похожий на тот, который генерируется с помощью kill -TRAP),  а
       не  какая-то специальная разновидность ptrace-stop. Выдача PTRACE_GETSIGINFO для этого сигнала возвращает
       si_code равный 0 (SI_USER). Этот сигнал может быть  блокирован  маской  сигналов  и  поэтому  может  быть
       доставлен (намного) позже.

       Обычно, трассировщик (например, strace(1)) не хотел бы показывать этот дополнительный пост-execve SIGTRAP
       сигнал  пользователю, и хотел бы подавить его доставку в трассируемую нить (если обработчик SIGTRAP равен
       SIG_DFL, то это уничтожающий сигнал). Однако, определить какой SIGTRAP подавлять, нелегко.  Рекомендуется
       установить флаг PTRACE_O_TRACEEXEC или PTRACE_SEIZE и затем подавить этот дополнительный SIGTRAP.

   Настоящий родитель
       Программный интерфейс ptrace использует стандартный обмен сигналами UNIX между родителем и потомком через
       waitpid(2).  Это  приводит  к  тому,  что  настоящий  родитель процесса перестаёт получать некоторые виды
       уведомлений waitpid(2), когда дочерний процесс трассируется другим процессом.

       Многие из этих дефектов были исправлены, но на момент версии  Linux  2.6.38  некоторые  из  них  всё  ещё
       существуют; смотрите ДЕФЕКТЫ далее.

       На момент версии Linux 2.6.38 работает правильно:

       •  при выходе/уничтожении по сигналу об этом сначала сообщается трассировщику, а затем,когда трассировщик
          подтвердит  результат  waitpid(2),  настоящему  родителю (настоящему родителю только когда завершается
          многонитевой процесс целиком). Если трассировщик и реальный родитель —  один  и  тот  же  процесс,  то
          сообщение приходит лишь однажды.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

       On   success,   the   PTRACE_PEEK*   operations   return   the   requested  data  (but  see  NOTES),  the
       PTRACE_SECCOMP_GET_FILTER  operation  returns  the  number  of  instructions  in  the  BPF  program,  the
       PTRACE_GET_SYSCALL_INFO  operation returns the number of bytes available to be written by the kernel, and
       other operations return zero.

       On error, all operations return -1, and errno is set to indicate the error.  Since the value returned  by
       a  successful  PTRACE_PEEK*  operation  may  be -1, the caller must clear errno before the call, and then
       check it afterward to determine whether or not an error occurred.

ОШИБКИ

       EBUSY  (только для i386) Произошла ошибка при размещении или освобождении отладочного регистра.

       EFAULT Была сделана попытка  чтения  или  записи  информации  в  область  памяти  трассируемой  нити  или
              трассировщика,  но,  скорее всего, эта память не отображена или недоступна. К сожалению, в Linux в
              разных ситуациях в результате этой ошибки возвращаются значения EIO  или  EFAULT,  что  не  всегда
              поддается объяснению.

       EINVAL Попытка установить недопустимое значение.

       EIO    op  is invalid, or an attempt was made to read from or write to an invalid area in the tracer's or
              the tracee's memory, or there was a word-alignment violation, or an invalid signal  was  specified
              during a restart operation.

       EPERM  The  specified  process  cannot  be  traced.   This  could  be because the tracer has insufficient
              privileges (the required  capability  is  CAP_SYS_PTRACE);  unprivileged  processes  cannot  trace
              processes that they cannot send signals to or those running set-user-ID/set-group-ID programs, for
              obvious reasons.  Alternatively, the process may already be being traced, or (before Linux 2.6.26)
              be init(1)  (PID 1).

       ESRCH  The  specified  process  does not exist, or is not currently being traced by the caller, or is not
              stopped (for operations that require a stopped tracee).

СТАНДАРТЫ

       Отсутствуют.

ИСТОРИЯ

       SVr4, 4.3BSD.

       Before Linux 2.6.26, init(1), the process with PID 1, may not be traced.

ПРИМЕЧАНИЯ

       Although arguments to ptrace()  are  interpreted  according  to  the  prototype  given,  glibc  currently
       declares  ptrace()   as a variadic function with only the op argument fixed.  It is recommended to always
       supply four arguments, even if  the  requested  operation  does  not  use  them,  setting  unused/ignored
       arguments to 0L or (void *) 0.

       Родитель трассируемой нити остаётся трассировщиком даже, если трассировщик вызывает execve(2).

       Структура  памяти и области USER зависят от ОС и архитектуры системы. Указываемое смещение и возвращаемые
       данные могут не полностью соответствовать определению struct user.

       Размер «слова» определяется вариантом ОС (например, для 32-битного варианта Linux слово будет 32-битным).

       Эта страница описывает работу системного вызова ptrace() в Linux. Его работа  значительно  отличается  от
       поведения  в  других  системах  UNIX. В любом случае, использование ptrace() очень сильно зависит от ОС и
       архитектуры.

   Проверка режима доступа ptrace
       Various parts of the kernel-user-space API (not just  ptrace()  operations),  require  so-called  "ptrace
       access  mode"  checks,  whose  outcome  determines whether an operation is permitted (or, in a few cases,
       causes a "read" operation to return sanitized data).  These checks  are  performed  in  cases  where  one
       process  can  inspect sensitive information about, or in some cases modify the state of, another process.
       The checks are based on factors such as the credentials and capabilities of the two processes, whether or
       not the "target" process is dumpable, and the results of checks performed by any enabled  Linux  Security
       Module (LSM)—for example, SELinux, Yama, or Smack—and by the commoncap LSM (which is always invoked).

       До  Linux  2.6.27  все  проверки  доступа  были  одного вида. Начиная с Linux 2.6.27 различают два уровня
       проверок доступа:

       PTRACE_MODE_READ
              For "read" operations or other operations that are less dangerous,  such  as:  get_robust_list(2);
              kcmp(2);  reading  /proc/pid/auxv,  /proc/pid/environ,  or  /proc/pid/stat;  or  readlink(2)  of a
              /proc/pid/ns/* file.

       PTRACE_MODE_ATTACH
              Для операций  «записи» или других более опасных операций: присоединение ptrace  (PTRACE_ATTACH)  к
              другому  процессу или вызов process_vm_writev(2) (PTRACE_MODE_ATTACH было эффективным значением по
              умолчанию до Linux 2.6.27).

       Начиная с Linux 4.5 приведённые выше проверки режима доступа объединяются  (ИЛИ)  с  одним  из  следующих
       модификаторов:

       PTRACE_MODE_FSCREDS
              Использовать  UID  и  GID файловой системы у вызывающего (смотрите credentials(7)) или эффективные
              мандаты для проверок LSM.

       PTRACE_MODE_REALCREDS
              Использовать реальные UID и GID у вызывающего или разрешающие мандаты для проверок LSM.  Это  было
              эффективным значением по умолчанию до Linux 4.5.

       Так  как объединение модификаторов мандатов с одной из вышеупомянутых режимов доступа часто используется,
       то в исходном коде ядра было определено несколько макросов:

       PTRACE_MODE_READ_FSCREDS
              Определён как PTRACE_MODE_READ | PTRACE_MODE_FSCREDS.

       PTRACE_MODE_READ_REALCREDS
              Определён как PTRACE_MODE_READ | PTRACE_MODE_REALCREDS.

       PTRACE_MODE_ATTACH_FSCREDS
              Определён как PTRACE_MODE_ATTACH | PTRACE_MODE_FSCREDS.

       PTRACE_MODE_ATTACH_REALCREDS
              Определён как PTRACE_MODE_ATTACH | PTRACE_MODE_REALCREDS.

       Один из следующих модификаторов может быть объединённых с режимом доступа:

       PTRACE_MODE_NOAUDIT (начиная с Linux 3.3)
              Не протоколировать (audit) проверку режима доступа. Данный модификатор  применяется  для  проверок
              режима доступа ptrace (например, проверки при чтении /proc/pid/stat), которые просто фильтруют или
              цензурируют  вывод, вместо возврата ошибки вызывающему. В этих случаях, доступ к файлу не нарушает
              правила безопасности и нет причины генерировать запись о нарушении. Данный  модификатор  отключает
              создание подобных протокольных записей для определённых проверок доступа.

       Заметим, что все константы PTRACE_MODE_*, описанные в данном разделе, доступны только для ядра и не видны
       из пользовательского пространства. Имена упомянутых констант служат обозначением различных видов проверок
       режима  доступа  ptrace,  которые  выполняются  для разных системных вызовов и получении доступа к разным
       псевдо-файлам (например, в каталоге /proc). Эти имена используются  в  других  справочных  страницах  как
       простые сокращения различных проверок ядра.

       Задействуемый  алгоритм  проверок  режима  доступа ptrace определяется по разрешению вызывающему процессу
       выполнять  соответствующее  действие  над  процессом  назначения  (в  случае  открытия  файлов  /proc/pid
       «вызывающий  процесс»  это  открывающий  файл,  а  процесс с соответствующим PID — «процесс назначения»).
       Возможные алгоритмы:

       (1)  Если вызывающая нить и нить назначения в одной группе нитей, то доступ всегда разрешён.

       (2)  Если режим доступа равен PTRACE_MODE_FSCREDS, то для проверки на следующем шаге используется  UID  и
            GID файловой системы у вызывающего (как упомянуто в credentials(7), UID и GID файловой системы почти
            всегда равны значениям соответствующих эффективных идентификаторов).

            В  противном  случае  режим  доступа  равен  PTRACE_MODE_REALCREDS,  и  на  следующем  шаге проверок
            используются реальные UID и GID вызывающего (большинство программных интерфейсов, которые  проверяют
            UID  и  GID  вызывающего,  используют  эффективные  идентификаторы. В проверке PTRACE_MODE_REALCREDS
            используются реальные ID только в силу исторических причин).

       (3)  Запрещается доступ, если срабатывает любое из этих правил:

            •  Реальные, эффективные и сохранённые пользовательские ID назначения совпадают  с  пользовательским
               ID  вызывающего,  и  Реальные,  эффективные  и  сохранённые  групповые  ID назначения совпадают с
               групповым ID вызывающего.

            •  Вызывающий имеет мандат CAP_SYS_PTRACE в пользовательском пространстве имён назначения.

       (4)  Доступ запрещается, если у процесса назначения значение атрибута  «возможности  дампа»  не  равно  1
            (SUID_DUMP_USER;  смотрите  обсуждение  PR_SET_DUMPABLE  в  prctl(2)), и вызывающий не имеет мандата
            CAP_SYS_PTRACE в пользовательском пространстве имён назначения.

       (5)  Для   проверки   того,   что   доступ   ptrace   разрешён,    вызывается    интерфейс    ядра    LSM
            security_ptrace_access_check().  Результат  зависит  от  LSM.  Реализация интерфейса в commoncap LSM
            выполняет следующие шаги:

            (5.1)  Если режим доступа включает PTRACE_MODE_FSCREDS, то используется эффективный  набор  мандатов
                   вызывающего   в   последующей   проверке;   в   противном   случае   (режим   доступа   равен
                   PTRACE_MODE_REALCREDS) используется допускающий набор мандатов.

            (5.2)  Запрещается доступ, если срабатывает любое из этих правил:

                   •  Вызывающий и процесс назначения находятся в одном пользовательском  пространстве  имён,  и
                      мандаты вызывающего составляют покрывающий набор допускающих мандатов процесса назначения.

                   •  Вызывающий  имеет  мандат  CAP_SYS_PTRACE  в  пользовательском  пространстве имён процесса
                      назначения.

                   Заметим, что commoncap LSM не различает PTRACE_MODE_READ и PTRACE_MODE_ATTACH.

       (6)  Если доступ не был запрещён в предыдущих шагах, то доступ разрешается.

   /proc/sys/kernel/yama/ptrace_scope
       В системах с установленным модулем Yama Linux Security  Module  (LSM)  (т.  е.,  ядро  было  настроено  с
       параметром  CONFIG_SECURITY_YAMA)  можно  использовать файл /proc/sys/kernel/yama/ptrace_scope (доступен,
       начиная с Linux 3.4) для того, чтобы огранить возможность трассировки процесса  с  помощью  ptrace()  (то
       есть  ограничить  использование  таких  инструментов  как strace(1) и gdb(1)). Целью ограничения является
       предотвращение возможности атаки, посредством которой  скомпроментированный  процесс  подключается  через
       ptrace  к  другим  ответственным  процессам  (например,  к  агенту  GPG  или  сеансу  SSH), принадлежащим
       пользователю, чтобы получить дополнительные полномочия (которые могут существовать  в  памяти)  и,  таким
       образом, расширить атакуемое пространство.

       Более точно, Yama LSM ограничивает два типа операций:

       •  Any  operation  that  performs  a  ptrace  access  mode PTRACE_MODE_ATTACH check—for example, ptrace()
          PTRACE_ATTACH.  (See the "Ptrace access mode checking" discussion above.)

       •  ptrace()  PTRACE_TRACEME.

       Процесс, имеющий мандат CAP_SYS_PTRACE, может записать в файл /proc/sys/kernel/yama/ptrace_scope одно  из
       следующих значений:

       0 («обычные права ptrace»)
              Без  дополнительных  ограничений  на  операции,  выполняющие  проверки  PTRACE_MODE_ATTACH  (кроме
              накладываемых commoncap и другими LSM).

              Использование PTRACE_TRACEME не изменяется.

       1 («ограниченный ptrace») [значение по умолчанию]
              Когда выполняется операция, требующая проверки PTRACE_MODE_ATTACH, вызывающий процесс должен иметь
              мандат CAP_SYS_PTRACE в пользовательском пространстве имён процесса назначения  или  должен  иметь
              предопределённые  отношения  с  процессом назначения. По умолчанию, предопределённые отношения это
              когда процесс назначения должен быть потомком вызывающего.

              Процесс назначения может выполнить операцию prctl(2) PR_SET_PTRACER для объявления дополнительного
              PID,  которому  разрешено  выполнять  операции  PTRACE_MODE_ATTACH   над   процессом   назначения.
              Подробности  смотрите  в  файле  исходного  кода  ядра Documentation/admin-guide/LSM/Yama.rst (или
              Documentation/security/Yama.txt до Linux 4.13).

              Использование PTRACE_TRACEME не изменяется.

       2 («только администраторское присоединение»)
              Только процессы с мандатом CAP_SYS_PTRACE в пользовательском пространстве имён процесса назначения
              могут выполнять операции PTRACE_MODE_ATTACH или трассировать потомков, выполнивших PTRACE_TRACEME.

       3 («присоединение заблокировано»)
              Никакие процессы  не  могут  выполнять  операции  PTRACE_MODE_ATTACH  или  трассировать  потомков,
              выполнивших PTRACE_TRACEME.

              После записи такого значения в файл, его нельзя изменить.

       Относительно  значений  1 и 2 заметим, что создание нового пользовательского пространства имён фактически
       удаляет защиту, предлагаемую Yama. Это происходит из-за того, что процесс в родительском пользовательском
       пространстве имён, у которого эффективный UID совпадает с  UID  создателя  дочернего  пространства  имён,
       имеет  все мандаты (включая CAP_SYS_PTRACE) при выполнении им операций внутри дочернего пользовательского
       пространства имён (вплоть до удаления потомков этого пространства имён). В результате, когда процесс  сам
       пытается  использовать  пользовательские  пространства  имён для песочницы, это непреднамеренно ослабляет
       защиту, предлагаемую Yama LSM.

   Отличия между библиотекой C и ядром
       At the system call level, the PTRACE_PEEKTEXT, PTRACE_PEEKDATA, and  PTRACE_PEEKUSER  operations  have  a
       different API: they store the result at the address specified by the data parameter, and the return value
       is  the  error  flag.   The  glibc wrapper function provides the API given in DESCRIPTION above, with the
       result being returned via the function return value.

ОШИБКИ

       On hosts with Linux 2.6 kernel headers, PTRACE_SETOPTIONS is declared with a different value than the one
       for Linux 2.4.  This leads to applications compiled with Linux 2.6 kernel headers  failing  when  run  on
       Linux 2.4.  This can be worked around by redefining PTRACE_SETOPTIONS to PTRACE_OLDSETOPTIONS, if that is
       defined.

       Уведомления  group-stop  посылаются  трассировщику,  но  не реальному родителю. Последнее подтверждение в
       версии 2.6.38.6.

       Если трассируется лидер группы нитей и завершается с помощью вызова _exit(2), то происходит  его  останов
       PTRACE_EVENT_EXIT (если это запрашивалось), но последующее уведомление WIFEXITED не будет доставлено пока
       все  остальные  нити  не  завершат  работу.  Как  объяснялось выше, если одна из остальных нитей вызывает
       execve(2), то о завершении лидера группы никогда не будет сообщено. Если исполняемая нить не трассируется
       этим трассировщиком, то трассировщик никогда не узнает,  что  происходил  execve(2).  Одним  из  обходных
       вариантов  решения  в этом случае является выполнение PTRACE_DETACH для лидера группы вместо перезапуска.
       Последнее подтверждение в версии 2.6.38.6.

       Сигнал SIGKILL всё ещё может вызвать остановку PTRACE_EVENT_EXIT перед настоящем завершением процесса  по
       сигналу.  Это  поведение  может измениться в будущем; SIGKILL всегда подразумевает немедленное завершение
       задач даже под ptrace. Последняя подтверждённая версия Linux — 3.13.

       Некоторые системные вызовы возвращаются с EINTR, если сигнал был послан трассируемой  нити,  но  доставка
       была  подавлена  трассировщиком  (это очень распространённая операция: она обычно выполняется отладчиками
       при каждом присоединении, чтобы  не  вызывать  ненужный  SIGSTOP).  Начиная  с  Linux  3.2.9,  подвержены
       следующие  системные  вызовы  (вероятно,  это  не  полный  список):  epoll_wait(2) и read(2) из файлового
       дескриптора inotify(7). Обычный симптом этой ошибки: когда вы присоединяетесь к  неактивному  процессу  с
       помощью команды

           strace -p <process-ID>

       то вместо обычного и ожидаемого вывода одной строки

           restart_syscall(<... resuming interrupted call ...>_

       или

           select(6, [5], NULL, [5], NULL_

       («_» означает позицию курсора), вы видите несколько строк. Пример:

               clock_gettime(CLOCK_MONOTONIC, {15370, 690928118}) = 0
               epoll_wait(4,_

       Здесь не видно, что процесс был заблокирован в epoll_wait(2) до того, как strace(1) присоединился к нему.
       Присоединение  заставляет epoll_wait(2) вернуться в пользовательское пространство с ошибкой EINTR. В этом
       частном случае, программа отвечает на EINTR проверкой текущего времени  и  затем  вызывает  epoll_wait(2)
       снова  (программы,  которые  не  ожидают таких «побочных» ошибок EINTR, при присоединении strace(1) могут
       повести себя непредсказуемо).

       В отличие от обычных правил, обёрточная функция glibc для ptrace() может присваивать errno значение нуля.

СМОТРИТЕ ТАКЖЕ

       gdb(1),  ltrace(1),  strace(1),  clone(2),   execve(2),   fork(2),   gettid(2),   prctl(2),   seccomp(2),
       sigaction(2), tgkill(2), vfork(2), waitpid(2), exec(3), capabilities(7), signal(7)

ПЕРЕВОД

       Русский     перевод     этой    страницы    руководства    разработал(и)    Alexey,    Azamat    Hackimov
       <azamat.hackimov@gmail.com>,      kogamatranslator49      <r.podarov@yandex.ru>,       Darima       Kogan
       <silverdk99@gmail.com>,  Max  Is  <ismax799@gmail.com>,  Yuri  Kozlov  <yuray@komyakino.ru>,  Иван Павлов
       <pavia00@gmail.com> и Kirill Rekhov <krekhov.dev@gmail.com>

       Этот перевод является свободной программной документацией; он распространяется на условиях  общедоступной
       лицензии  GNU  (GNU  General Public License - GPL, https://www.gnu.org/licenses/gpl-3.0.html версии 3 или
       более поздней) в отношении авторского права, но БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ.

       Если вы обнаружите какие-либо ошибки в переводе этой страницы руководства, пожалуйста, сообщите  об  этом
       разработчику(ам)   по   его(их)  адресу(ам)  электронной  почты  или  по  адресу  списка рассылки русских
       переводчиков.

Справочные страницы Linux 6.9.1                   2 мая 2024 г.                                        ptrace(2)