2023-04-14 19:58:50

by Alejandro Colomar

[permalink] [raw]
Subject: Re: Checking for support of ptrace(PTRACE_SEIZE,...) on older kernels

Hi Sergei,

On 4/13/23 21:30, Sergei Zhirikov wrote:
> Hello,
>
> I've been studying the ptrace(2) man page and experimenting with ptrace() recently and came across this unexpected aspect of its behavior that I think would be good to have documented.
>
> I would like to use PTRACE_SEIZE in my project because of the advantages it offers, but I would also like to support kernels older than 3.4 (where it was fully introduced). My thinking was that I would call ptrace(PTRACE_SEIZE, ...) and if it fails with the appropriate error code indicating that it's not supported I would fall back to PTRACE_ATTACH. That is where a little surprise was waiting for me. According to the man page, ptrace will fail with errno=EIO if called with an invalid request code. Logically, that was the error code I expected to get when PTRACE_SEIZE is not supported. In reality I got ESRCH instead. In my attempts to make sense of it I had to resort to reading the kernel source. Apparently, the logic in the kernel ( https://elixir.bootlin.com/linux/v3.0.101/source/kernel/ptrace.c#L944 ) seems to assume that any request other than PTRACE_ATTACH must come for an already existing tracee. So it proceeds to look for such a tracee (by calling ptrace_check_attach) before trying to interpret the request code. Obviously, in case of PTRACE_SEIZE, the target process/thread is not being traced yet, so ESRCH is returned. As far as I can tell by looking at the source code, that will happen for any request code (with a couple of exceptions), valid or otherwise. The relevant piece of logic seems to remain unchanged to this day, so this isn't just a problem with an ancient kernel that nobody cares about. I am not sure whether this behavior is intentional (I would guess it's not), but in any case it's probably good to have it documented in the man page.

I've added some CCs. Feel free to send a patch.

Cheers,
Alex

>
> Thanks and regards,
> Sergei.

--
<http://www.alejandro-colomar.es/>
GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5


Attachments:
OpenPGP_signature (849.00 B)
OpenPGP digital signature

2023-04-17 12:02:21

by Oleg Nesterov

[permalink] [raw]
Subject: Re: Checking for support of ptrace(PTRACE_SEIZE,...) on older kernels

Well, from https://man7.org/linux/man-pages/man2/ptrace.2.html

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

so if the kernel doesn't support PTRACE_SEIZE then ptrace(PTRACE_SEIZE)
should fail with -ESRCH as documented.

Perhaps this part

EIO request is invalid, or ...

can be improvef a bit to explain that this happens if the target is already
traced by us and stopped.

Oleg.

so in this case ptrace will fail with -ESRCH if called with an invalid request code

On 04/14, Alejandro Colomar wrote:
>
> Hi Sergei,
>
> On 4/13/23 21:30, Sergei Zhirikov wrote:
> > Hello,
> >
> > I've been studying the ptrace(2) man page and experimenting with ptrace() recently and came across this unexpected aspect of its behavior that I think would be good to have documented.
> >
> > I would like to use PTRACE_SEIZE in my project because of the advantages it offers, but I would also like to support kernels older than 3.4 (where it was fully introduced). My thinking was that I would call ptrace(PTRACE_SEIZE, ...) and if it fails with the appropriate error code indicating that it's not supported I would fall back to PTRACE_ATTACH. That is where a little surprise was waiting for me. According to the man page, ptrace will fail with errno=EIO if called with an invalid request code. Logically, that was the error code I expected to get when PTRACE_SEIZE is not supported. In reality I got ESRCH instead. In my attempts to make sense of it I had to resort to reading the kernel source. Apparently, the logic in the kernel (?https://elixir.bootlin.com/linux/v3.0.101/source/kernel/ptrace.c#L944?) seems to assume that any request other than PTRACE_ATTACH must come for an already existing tracee. So it proceeds to look for such a tracee (by calling ptrace_check_attach) before trying to interpret the request code. Obviously, in case of PTRACE_SEIZE, the target process/thread is not being traced yet, so ESRCH is returned. As far as I can tell by looking at the source code, that will happen for any request code (with a couple of exceptions), valid or otherwise. The relevant piece of logic seems to remain unchanged to this day, so this isn't just a problem with an ancient kernel that nobody cares about. I am not sure whether this behavior is intentional (I would guess it's not), but in any case it's probably good to have it documented in the man page.
>
> I've added some CCs. Feel free to send a patch.
>
> Cheers,
> Alex
>
> >
> > Thanks and regards,
> > Sergei.
>
> --
> <http://www.alejandro-colomar.es/>
> GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5




2023-04-17 18:54:29

by Alejandro Colomar

[permalink] [raw]
Subject: Re: Checking for support of ptrace(PTRACE_SEIZE,...) on older kernels

Hi Oleg,

On 4/17/23 13:50, Oleg Nesterov wrote:
> Well, from https://man7.org/linux/man-pages/man2/ptrace.2.html
>
> ESRCH The specified process does not exist, or is not currently
> being traced by the caller, or is not stopped (for
> requests that require a stopped tracee).
>
> so if the kernel doesn't support PTRACE_SEIZE then ptrace(PTRACE_SEIZE)
> should fail with -ESRCH as documented.
>
> Perhaps this part
>
> EIO request is invalid, or ...
>
> can be improvef a bit to explain that this happens if the target is already
> traced by us and stopped.

I'm not sure if it's necessary. When several errors happen at the same time,
there's usually no documentation about which takes precedence, with few
exceptions. Knowing it's intentional, I'm content.

Thanks,

Alex

--
<http://www.alejandro-colomar.es/>
GPG key fingerprint: A9348594CE31283A826FBDD8D57633D441E25BB5


Attachments:
OpenPGP_signature (849.00 B)
OpenPGP digital signature

2023-04-18 07:59:58

by Oleg Nesterov

[permalink] [raw]
Subject: Re: Checking for support of ptrace(PTRACE_SEIZE,...) on older kernels

Hi Alejandro,

On 04/17, Alejandro Colomar wrote:
>
> On 4/17/23 13:50, Oleg Nesterov wrote:
> > Well, from https://man7.org/linux/man-pages/man2/ptrace.2.html
> >
> > ESRCH The specified process does not exist, or is not currently
> > being traced by the caller, or is not stopped (for
> > requests that require a stopped tracee).
> >
> > so if the kernel doesn't support PTRACE_SEIZE then ptrace(PTRACE_SEIZE)
> > should fail with -ESRCH as documented.
> >
> > Perhaps this part
> >
> > EIO request is invalid, or ...
> >
> > can be improvef a bit to explain that this happens if the target is already
> > traced by us and stopped.
>
> I'm not sure if it's necessary. When several errors happen at the same time,
> there's usually no documentation about which takes precedence, with few
> exceptions.

Yes, agreed.

I just tried to understand where did this ESRCH/EIO confusion come from.

Oleg.