Bug 32532 - udm not SIGPIPE safe
udm not SIGPIPE safe
Status: NEW
Product: UCS
Classification: Unclassified
Component: UDM - CLI
UCS 5.0
Other Linux
: P5 normal (vote)
: ---
Assigned To: UMC maintainers
:
: 48807 (view as bug list)
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2013-09-09 14:05 CEST by Philipp Hahn
Modified: 2024-01-10 17:03 CET (History)
4 users (show)

See Also:
What kind of report is it?: Bug Report
What type of bug is this?: 2: Improvement: Would be a product improvement
Who will be affected by this bug?: 2: Will only affect a few installed domains
How will those affected feel about the bug?: 2: A Pain – users won’t like this once they notice it
User Pain: 0.046
Enterprise Customer affected?:
School Customer affected?:
ISV affected?:
Waiting Support:
Flags outvoted (downgraded) after PO Review:
Ticket number:
Bug group (optional): Cleanup, Error handling, Usability
Max CVSS v3 score:
best: Patch_Available-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Philipp Hahn univentionstaff 2013-09-09 14:05:13 CEST
Something in UDM (or Python) is not prepared for the STDOUT pipe being closed early:

# udm groups/group list | grep -Eq '^  (hosts|memberOf|users|groups):'
close failed in file object destructor:
Error in sys.excepthook:

Original exception was:

# strace -o /tmp/udm -f udm groups/group list | (dd bs=1 count=1 >/dev/null 2>&1)
close failed in file object destructor:
Error in sys.excepthook:

Original exception was:

# python -c 'print "*" * (1<<20)' | (dd bs=1 count=1 >/dev/null 2>&1)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
IOError: [Errno 32] Broken pipe

# cat /tmp/udm
...
30487 write(1, "=groups,dc=phahn,dc=dev\nARG: Non"..., 2964) = -1 EPIPE (Broken pipe)
30487 --- SIGPIPE (Broken pipe) @ 0 (0) ---
30487 rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7fc98fb9eff0}, {0x4daed0, [], SA_RESTORER, 0x7fc98fb9eff0}, 8) = 0
30487 write(2, "close failed in file object dest"..., 40) = 40
30487 write(2, "Error in sys.excepthook:\n", 25) = 25
30487 write(2, "\nOriginal exception was:\n", 25) = 25
30487 exit_group(0)                     = ?
Comment 1 Florian Best univentionstaff 2016-07-26 16:15:00 CEST
# udm groups/group list | grep -Eq '^  (hosts|memberOf|users|groups):'
Traceback (most recent call last):
  File "/usr/sbin/udm", line 195, in <module>
    main()
  File "/usr/sbin/udm", line 190, in main
    result = process_output(output, cmdfile)
  File "/usr/sbin/udm", line 146, in process_output
    print line
IOError: [Errno 32] Broken pipe

How should this be fixed? try-except around every print and exit(0) then?
Comment 2 Florian Best univentionstaff 2019-02-27 15:18:36 CET
*** Bug 48807 has been marked as a duplicate of this bug. ***
Comment 3 Florian Best univentionstaff 2019-02-27 16:16:34 CET
Patch in fbest/32532-udm-sigpipe-safe:

diff --git a/management/univention-directory-manager-modules/univention-cli-client b/management/univention-directory-manager-modules/univention-cli-client
index 9125ef7867..823c806ded 100755
--- a/management/univention-directory-manager-modules/univention-cli-client
+++ b/management/univention-directory-manager-modules/univention-cli-client
@@ -34,0 +35 @@ import socket
+import signal
@@ -185,0 +187 @@ def main():
+»   signal.signal(signal.SIGPIPE, signal.SIG_DFL)
Comment 4 Philipp Hahn univentionstaff 2019-02-27 17:35:34 CET
(In reply to Florian Best from comment #3)
> +»   signal.signal(signal.SIGPIPE, signal.SIG_DFL)

Please beware of the dire consequences which might happen if you go that way as you change a fundamental assumption in all Python libraries:
<https://docs.python.org/3/library/signal.html#note-on-sigpipe>

For more issues with SIGPIPE in LDAP see <https://hutten.knut.univention.de/blog/unix-102-1-sigpipe/>.

(In reply to Florian Best from comment #1)
> How should this be fixed? try-except around every print and exit(0) then?

NO: exit(0) != exit by SIGPIPE - the difference is IMPORTANT! Read <man:wait(2)> and <https://www.cons.org/cracauer/sigint.html>

import os
import signal
import errno
try:
  main()
except IOError as ex:
  if ex.errno != errno.EPIPE:
    raise
  if False:
    # This is only needed if you prefer exit(1)
    devnull = os.open(os.devnull, os.O_WRONLY)
    os.dup2(devnull, sys.stdout.fileno())
    os.dup2(devnull, sys.stderr.fileno())
    exit(1)
  else:
    # This will just kill python with SIGPIPE and STDOUT/STDERR will not be flushed
    signal.signal(signal.SIGPIPE, signal.SIG_DFL)
    os.kill(os.getpid(), signal.SIGPIPE)

For testing:
 udm groups/group list | (dd bs=1 count=1 >/dev/null 2>&1)
 echo ${PIPESTATUS[@]} # 141 0

<man:bash(1)>: The return value of a simple command is ... 128+n if the command is terminated by signal n.
<man:signal(7): SIGPIPE := 13
Comment 5 Florian Best univentionstaff 2019-02-27 17:44:24 CET
Okay, I see.
Comment 6 Florian Best univentionstaff 2019-03-19 09:45:43 CET
Also in our jenkins tests:

Adding ZONE record "root@AutoTest091.local. 1 28800 10800 604800 108001 master091.AutoTest091.local." to zone 10.210...
Traceback (most recent call last):
  File "/usr/sbin/univention-directory-manager", line 201, in <module>
    main()
  File "/usr/sbin/univention-directory-manager", line 196, in main
    result = process_output(output, cmdfile)
  File "/usr/sbin/univention-directory-manager", line 152, in process_output
    print line
IOError: [Errno 32] Broken pipe
Comment 7 Florian Best univentionstaff 2020-07-08 20:10:25 CEST
The Traceback in UCS 5.0:

Traceback (most recent call last):
  File "/usr/sbin/univention-directory-manager", line 205, in <module>
    main()
  File "/usr/sbin/univention-directory-manager", line 200, in main
    result = process_output(output, cmdfile)
  File "/usr/sbin/univention-directory-manager", line 153, in process_output
    print(line)
BrokenPipeError: [Errno 32] Broken pipe