Package: autopkgtest
Version: 5.16
Severity: normal
User: de...@kali.org
Usertags: origin-kali

If the execution duration exceeds the specified timeout,
`execute_timeout` tries to kill the process it started. This will
systematically fail if the command was wrapped in `sudoify`, because
`execute_timeout` will of course not be able to terminate a process
owned by UID 0.

Here's an actual example, where an lxc test container took too long to
get its networking available (the corresponding call is in
autopkgtest-virt-lxc's `wait_booted` at line 131):

```
autopkgtest-virt-lxc [06:18:24]: ERROR: WARNING: Cannot kill timed out process 
['sudo', 'lxc-attach', '--name', 'ci-106-c7628f8c', '--', 'sh', '-ec', 'if [ -d 
/run/systemd/system ]; then systemctl start network-online.target; else while 
ps -ef | grep -q "/etc/init\\.d/rc"; do sleep 1; done; fi']: [Errno 1] 
Operation not permitted
```

I used the following pytest code to isolate and reproduce the error:

```python
import pytest
import re
import sys
sys.path.append('lib')

import VirtSubproc


@pytest.mark.parametrize("cmd", (["sleep", "10"], ["sudo", "sleep", "10"]))
def test_timeout_one_second(cmd, capfd):
    with pytest.raises(VirtSubproc.Timeout):
        VirtSubproc.execute_timeout(None, 1, cmd)

    out, err = capfd.readouterr()
    assert not re.search(r'WARNING.*Cannot.*timed out process', err)
```

I don't see an easy solution to this problem; I am able to work around
the issue by using the attached patch, combined with giving the `debci` user
(that runs our autopkgtests) additional sudo permissions for the
commands that timeout for us, but that's suboptimal.

-- System Information:
Debian Release: bullseye/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 
'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 5.10.0-4-amd64 (SMP w/36 CPU threads)
Kernel taint flags: TAINT_PROPRIETARY_MODULE, TAINT_OOT_MODULE, 
TAINT_UNSIGNED_MODULE
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8), LANGUAGE not set
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages autopkgtest depends on:
ii  apt-utils       2.1.20
ii  libdpkg-perl    1.20.7.1
ii  procps          2:3.3.17-2
ii  python3         3.9.1-1
ii  python3-debian  0.1.39

Versions of packages autopkgtest recommends:
ii  autodep8  0.24

Versions of packages autopkgtest suggests:
ii  lxc               1:4.0.6-1
pn  lxd               <none>
ii  ovmf              2020.11-2
ii  qemu-efi-aarch64  2020.11-2
ii  qemu-efi-arm      2020.11-2
ii  qemu-system       1:5.2+dfsg-3
ii  qemu-utils        1:5.2+dfsg-9
ii  schroot           1.6.10-11+b1
ii  vmdb2             0.22-1

-- no debconf information
commit fc83a3471e7f44d6330e8c88d6d9abe7bcd7ab26
Author: Sébastien Delafond <sdelaf...@gmail.com>
Date:   Fri Apr 16 12:57:38 2021 +0200

    virtsubproc: use sudo to kill timed-out processes started with sudo

diff --git a/lib/VirtSubproc.py b/lib/VirtSubproc.py
index bf948e6..67bc712 100644
--- a/lib/VirtSubproc.py
+++ b/lib/VirtSubproc.py
@@ -147,10 +147,22 @@ def execute_timeout(instr, timeout, *popenargs, 
**popenargsk):
             out = out.decode('UTF-8', 'replace')
         if err is not None:
             err = err.decode('UTF-8', 'replace')
-    except Timeout:
+    except Timeout as te:
         try:
             sp.kill()
             sp.wait()
+        except PermissionError as pe:
+            adtlog.info('INFO: Cannot kill timed out process %s due to 
insufficient permission: %s' %
+                         (popenargs[0], pe))
+            try:
+                cmd = ['sudo', '--non-interactive', 'kill', str(sp.pid)]
+                cp = subprocess.run(cmd, timeout=5, capture_output=True)
+                if cp.returncode != 0:
+                    raise OSError(cp.stderr.decode('UTF-8', 'replace'))
+                raise te
+            except OSError as es:
+                adtlog.error('WARNING: Cannot sudo-kill timed out process %s: 
%s' %
+                             (popenargs[0], es))
         except OSError as e:
             adtlog.error('WARNING: Cannot kill timed out process %s: %s' %
                          (popenargs[0], e))

Reply via email to