Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Segmentation fault. Probably security related.



[Including more context than usual because this thread is moving from the zsh-security list]

On Thu, Oct 10, 2024 at 1:31 AM Daniel Shahaf <d.s@xxxxxxxxxxxxxxxxxx> wrote:
Alex Dev wrote on Wed, 09 Oct 2024 21:50 +00:00:
> Hi, it looks like I found integer overflow in the latest ZSH.
> The problem is related to the builtin "kill" command.
>
> I've tested it on 3 different machines(64bit), successfully.
> 1) mac(intel) with the latest macOS Sequoia 15.0.1, zsh 5.9
> (x86_64-apple-darwin24.0).
> 2) thinkpad(intel), linux 6.10..6, zsh 5.8.1
> 3) old laptop(intel), linux, zsh 5.8.1
>
> The command completely killed macos desktop environment, the same with the
> xfce on linux.
>
> How to reproduce:
> Normal behaviour - "kill 9223372036854775806"
>                                 result message "kill: kill
> 9223372036854775806 failed: no such process"
> Segfault - "kill 9223372036854775807"
>                  result - segfault

9223372036854775807 == 2**63 - 1 == INT64_MAX.

bin_kill() converts the string value "9223372036854775807" to an integer using atoi(3), which returns an int.

Presumably, INT_MAX < INT64_MAX, so atoi(3) returns (int)-1.

Thereafter kill(2) would be called with the pid_t argument having the value -1, which is a valid value for that argument:

    https://pubs.opengroup.org/onlinepubs/9799919799/functions/kill.html
    """If pid is -1, sig shall be sent to all processes (excluding an unspecified set of system processes) for which the process has permission to send that signal."""

So, no, it's not a segfault --- no process gets sent SIGSEGV.

This analysis appears to be correct but is difficult to demonstrate because "all processes for which the process has permission" typically includes the ssh daemon or terminal handler to which the current user logged in.  However, by arranging to su to the "nobody" user -- which has no permission to kill anything, even its own parent shell -- I was able to get this:

# su -s /bin/sh nobody
$ Src/zsh -f
toltec-ubuntu% kill 9223372036854775807
toltec-ubuntu% print $?
0
toltec-ubuntu%

No segmentation fault.

However, it's probably fair to call this a bug and argue it should either kill process 9223372036854775807 if it exists, or error out with "no such process" (if 9223372036854775807 is representable in pid_t and doesn't denote an existing process), or error out with "not a valid job or process ID value: '%s'" (otherwise).

This comes down to whether pid_t is larger than int.  If we, for example, switch from using atoi() to zstrtol(), and then pass a long integer to kill(), are we doing more harm than good?  Is this worth (for another example) a configure test to determine the size of a pid_t ?
 
Note that `kill 9223372036854775806` probably ends up calling kill(-2, SIGTERM).

 9223372036854775808 ?

Can this discussion continue on -workers@?  It doesn't seem it would be exploitable.

Thanks for the report,

Daniel
(I replied because it's on -security@, but I'm afraid I won't have much time for follow up discussions, sorry)

> Please let me know if it's a real bug, Thanks!
>
> Alexander Lemeza



Messages sorted by: Reverse Date, Date, Thread, Author