Fix race condition when getting cmdline

Even though we check for the existence of the process before, it may
still terminate before we get to read its command line, so catch the
error that can occur here.

Change-Id: I3e89aca8bedfd2912effe2490718223f7d03133e
Closes-Bug: 1844500
This commit is contained in:
Jens Harbott 2019-09-18 08:46:58 +00:00 committed by Brian Haley
parent e16b789257
commit 3330bc01cb
2 changed files with 26 additions and 11 deletions

View File

@ -323,19 +323,24 @@ def process_is_running(pid):
def get_cmdline_from_pid(pid):
if not process_is_running(pid):
return []
with open('/proc/%s/cmdline' % pid, 'r') as f:
cmdline = f.readline().split('\0')[:-1]
# NOTE(jh): Even after the above check, the process may terminate
# before the open below happens
try:
with open('/proc/%s/cmdline' % pid, 'r') as f:
cmdline = f.readline().split('\0')[:-1]
except IOError:
return []
# NOTE(slaweq): sometimes it may happen that values in
# /proc/{pid}/cmdline are separated by space instead of NUL char,
# in such case we would have everything in one element of cmdline_args
# list and it would not match to expected cmd so we need to try to
# split it by spaces
if len(cmdline) == 1:
cmdline = cmdline[0].split(' ')
# NOTE(slaweq): sometimes it may happen that values in
# /proc/{pid}/cmdline are separated by space instead of NUL char,
# in such case we would have everything in one element of cmdline_args
# list and it would not match to expected cmd so we need to try to
# split it by spaces
if len(cmdline) == 1:
cmdline = cmdline[0].split(' ')
LOG.debug("Found cmdline %s for process with PID %s.", cmdline, pid)
return cmdline
LOG.debug("Found cmdline %s for process with PID %s.", cmdline, pid)
return cmdline
def cmd_matches_expected(cmd, expected_cmd):

View File

@ -336,6 +336,16 @@ class TestGetCmdlineFromPid(base.BaseTestCase):
mock_open.assert_not_called()
self.assertEqual([], cmdline)
def test_cmdline_process_disappearing(self):
self.process_is_running_mock.return_value = True
mock_open = self.useFixture(
lib_fixtures.OpenFixture('/proc/%s/cmdline' % self.pid, 'process')
).mock_open
mock_open.side_effect = IOError()
cmdline = utils.get_cmdline_from_pid(self.pid)
mock_open.assert_called_once_with('/proc/%s/cmdline' % self.pid, 'r')
self.assertEqual([], cmdline)
class TestFindChildPids(base.BaseTestCase):