Bug 24657 - CPU-eating loop when stdin pipe is closed
Summary: CPU-eating loop when stdin pipe is closed
Status: CLOSED FIXED
Alias: None
Product: Sisyphus
Classification: Development
Component: netcat (show other bugs)
Version: unstable
Hardware: all Linux
: P3 normal
Assignee: placeholder@altlinux.org
QA Contact: qa-sisyphus
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-11-28 13:33 MSK by Sergey Vlasov
Modified: 2010-12-09 20:11 MSK (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sergey Vlasov 2010-11-28 13:33:55 MSK
netcat-4.0.20100420-alt1

В случае, если в качестве stdin передаётся pipe, и затем все дескрипторы для записи закрываются, netcat зацикливается, пока не будет закрыто сетевое соединение:

17160 poll([{fd=3, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=0, revents=POLLHUP}])
17160 poll([{fd=3, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=0, revents=POLLHUP}])
17160 poll([{fd=3, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 1 ([{fd=0, revents=POLLHUP}])
... (при отсутствии активности сетевого соединения продолжается бесконечно)
(после закрытия сокета с другой стороны)
17160 poll([{fd=3, events=POLLIN}, {fd=0, events=POLLIN}], 2, -1) = 2 ([{fd=3, revents=POLLIN}, {fd=0, revents=POLLHUP}])
17160 read(3, "", 2048)                 = 0
17160 shutdown(3, 0 /* receive */)      = 0
17160 close(3)                          = 0
17160 exit_group(0)                     = ?

Наблюдать это можно, например, при использовании ssh $host nc 127.0.0.1 $port; после этого нормальное закрытие входного потока ssh приводит к зацикливанию nc, причём данные в противоположном направлении в этом состоянии продолжают проходить.  Такой вызов nc через ssh используется в libvirt (virt-manager, virt-viewer) для соединения с VNC-сервером qemu при подключении qemu+ssh://, в результате на сервере остаются висеть процессы nc, потребляющие процессорное время. (Для основного соединения с сокетом libvirtd в нормальной ситуации эта проблема не наблюдается из-за наличия в протоколе явной команды закрытия соединения, в результате nc завершает работу при закрытии сокета со стороны libvirtd.)

В Linux для pipe или fifo в случае, если все дескрипторы для записи закрыты, и при этом в буфере нет данных, poll() возвращает для дескриптора чтения флаг POLLHUP без установки флага POLLIN; однако netcat не проверяет флаг POLLHUP - видимо, поведение ядра OpenBSD в такой ситуации отличается от Linux (похоже, там по EOF выставляется и POLLIN|POLLRDNORM).

В Fedora подобная проблема была починена ещё в 2005 году:

https://bugzilla.redhat.com/show_bug.cgi?id=156835

В январе 2010 года была попытка протолкнуть в апстрим патчи, среди которых был и чинящий обработку POLLHUP, но ответа не последовало:

http://kerneltrap.org/mailarchive/openbsd-tech/2010/1/12/6700583
http://jzeleny.fedorapeople.org/patches/nc/01-pollhup.patch
Comment 1 Andriy Stepanov (stanv) 2010-11-28 14:18:06 MSK
PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                              
27097 stanv     20   0  8556  724  596 R 99.7  0.0   0:06.36 nc                                    
27080 stanv     20   0  6324  456  356 R 92.1  0.0   0:05.92 nc
Comment 2 Anton Farygin 2010-12-02 12:27:29 MSK
Дима, очень нужно исправление этой ошибки.
Comment 3 Repository Robot 2010-12-09 20:11:45 MSK
netcat-4.0.20100725-alt1 -> sisyphus:

* Thu Dec 09 2010 Dmitry V. Levin <ldv@altlinux> 4.0.20100725-alt1
- Updated to 20100725 snapshot.
- Imported a POLLHUP detection patch by Jan Zeleny (closes: #24657).