Skip to content

Commit

Permalink
Improve trace_inputs.py for Ubuntu 14.04 and fix regressions.
Browse files Browse the repository at this point in the history
It's mostly working around the sandbox and other things plus an earlier commit
49abac8 that had broken it.

This change is just enough to get going, nothing more.

[email protected]
BUG=

Review-Url: https://codereview.chromium.org/2208833002
  • Loading branch information
maruel authored and Commit bot committed Aug 3, 2016
1 parent e448e8e commit f1a95e3
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 8 deletions.
5 changes: 3 additions & 2 deletions client/tests/trace_inputs_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def test_CsvReader(self):
class StraceInputs(unittest.TestCase):
# Represents the root process pid (an arbitrary number).
_ROOT_PID = 27
_CHILD_PID = 14
_CHILD_PID = 24
_GRAND_CHILD_PID = 70

@staticmethod
Expand Down Expand Up @@ -464,6 +464,7 @@ def test_futex_missing_in_partial_action(self):
def test_futex_missing_in_partial_action_with_no_process(self):
# That's how futex() calls roll even more (again).
lines = [
(self._ROOT_PID, 'syscall_317(0, 0, 0, 0, 0, 0) = 0'),
(self._ROOT_PID, 'futex(0x7134840, FUTEX_WAIT_PRIVATE, 2, '
'NULL <ptrace(SYSCALL):No such process>'),
]
Expand All @@ -477,7 +478,7 @@ def test_futex_missing_in_partial_action_with_no_process(self):
'pid': self._ROOT_PID,
},
}
self.assertContext(lines, ROOT_DIR, expected, True)
self.assertContext(lines, ROOT_DIR, expected, False)

def test_getcwd(self):
lines = [
Expand Down
69 changes: 63 additions & 6 deletions client/trace_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def full_path(self):
def real_path(self):
"""Returns the path with symlinks resolved."""
if not self._real_path:
self._real_path = fs.path.realpath(self.full_path)
self._real_path = os.path.realpath(self.full_path)
return self._real_path

@property
Expand Down Expand Up @@ -556,7 +556,7 @@ def strip_root(self, root):
accessed through any symlink which points to the same directory.
"""
# Resolve any symlink
root = fs.realpath(root)
root = os.path.realpath(root)
root = (
file_path.get_native_path_case(root).rstrip(os.path.sep) + os.path.sep)
logging.debug('strip_root(%s)' % root)
Expand Down Expand Up @@ -847,6 +847,9 @@ class Process(ApiBase.Context.Process):
RE_PROCESS_EXITED = re.compile(r'^\+\+\+ exited with (\d+) \+\+\+')
# A call was canceled. Ignore any prefix.
RE_UNAVAILABLE = re.compile(r'^.*\)\s*= \? <unavailable>$')
# The process has exited due to the ptrace sandbox. RE_PROCESS_EXITED will
# follow on next line.
RE_PTRACE = re.compile(r'^.*<ptrace\(SYSCALL\):No such process>$')
# Happens when strace fails to even get the function name.
UNNAMED_FUNCTION = '????'

Expand Down Expand Up @@ -991,6 +994,13 @@ def on_line(self, line):
# make sure any self._pending_calls[anything] is properly flushed.
return

match = self.RE_PTRACE.match(line)
if match:
# Not sure what this means. Anyhow, the process died.
# TODO(maruel): Add note that only RE_PROCESS_EXITED is valid
# afterward.
return

match = self.RE_RESUMED.match(line)
if match:
if match.group(1) not in self._pending_calls:
Expand Down Expand Up @@ -1060,6 +1070,12 @@ def handle_close(self, _args, _result):
def handle_chmod(self, args, _result):
self._handle_file(args[0], Results.File.WRITE)

@parse_args(r'^\"(.+?)\"$', False)
def handle_chroot(self, _args, _result):
# This is used by Chromium's sandbox. See
# https://chromium.googlesource.com/chromium/src/+/master/sandbox/linux/suid/sandbox.c
pass

@parse_args(r'^\"(.+?)\", (\d+)$', False)
def handle_creat(self, args, _result):
self._handle_file(args[0], Results.File.WRITE)
Expand Down Expand Up @@ -1095,6 +1111,11 @@ def handle_fallocate(self, _args, result):
def handle_fork(self, args, result):
self._handle_unknown('fork', args, result)

@parse_args(r'^(\d+), \"(.*?)\", ({.+}), (\d+)$', True)
def handle_fstatat64(self, _args, _result):
# TODO(maruel): Handle.
pass

def handle_futex(self, _args, _result):
pass

Expand Down Expand Up @@ -1128,6 +1149,11 @@ def handle_mkdir(self, _args, _result):
# We track content, not directories.
pass

@parse_args(r'^(\d+|AT_FDCWD), \".*?\", ({.+}), (\d+)$', True)
def handle_newfstatat(self, _args, _result):
# TODO(maruel): Handle
pass

@parse_args(r'^(\".*?\"|0x[a-f0-9]+), ([A-Z\_\|]+)(|, \d+)$', False)
def handle_open(self, args, _result):
if 'O_DIRECTORY' in args[1]:
Expand Down Expand Up @@ -1184,11 +1210,24 @@ def handle_stat(self, args, _result):
if not args[0].startswith('0x'):
self._handle_file(args[0][1:-1], Results.File.TOUCHED)

@parse_args(r'^(\".+?\"|0x[a-f0-9]+), \{.+?\}$', True)
def handle_stat64(self, args, _result):
if not args[0].startswith('0x'):
self._handle_file(args[0][1:-1], Results.File.TOUCHED)

@parse_args(r'^\"(.+?)\", \"(.+?)\"$', True)
def handle_symlink(self, args, _result):
self._handle_file(args[0], Results.File.TOUCHED)
self._handle_file(args[1], Results.File.WRITE)

@parse_args(
r'^([0-9xa-f]+), ([0-9xa-f]+), ([0-9xa-f]+), ([0-9xa-f]+), '
r'([0-9xa-f]+), ([0-9xa-f]+)$',
False)
def handle_syscall_317(self, _args, _result):
# move_pages()
pass

@parse_args(r'^\"(.+?)\", \d+', True)
def handle_truncate(self, args, _result):
self._handle_file(args[0], Results.File.WRITE)
Expand Down Expand Up @@ -1224,13 +1263,18 @@ def _handling_forking(self, name, result):
return
# Update the other process right away.
childpid = int(result)
if childpid < 20:
# Ignore, it's probably the Chromium sandbox.
return
child = self._root().get_or_set_proc(childpid)
if child.parentid is not None or childpid in self.children:
raise TracingFailure(
'Found internal inconsitency in process lifetime detection '
'during a %s() call' % name,
'during a %s()=%s call:\n%s' % (
name,
result,
sorted(self._root()._process_lookup)),
None, None, None)

# Copy the cwd object.
child.initial_cwd = self.get_cwd()
child.parentid = self.pid
Expand Down Expand Up @@ -1289,6 +1333,15 @@ def to_results(self):
self.root_process = root[0]
# Save it for later.
self.root_pid = self.root_process.pid
else:
raise TracingFailure(
'Found internal inconsitency in process lifetime detection '
'while finding the root process',
None,
None,
None,
self.root_pid,
sorted(self._process_lookup))
else:
# The sudo case. The traced process was started manually so its pid is
# known.
Expand Down Expand Up @@ -1371,7 +1424,10 @@ def trace(self, cmd, cwd, tracename, output):
stderr = subprocess.STDOUT

# Ensure all file related APIs are hooked.
traces = ','.join(Strace.Context.traces() + ['file'])
traces = ','.join(
[i for i in Strace.Context.traces()
if not i.startswith('syscall_')] +
['file'])
flags = [
# Each child process has its own trace file. It is necessary because
# strace may generate corrupted log file if multiple processes are
Expand All @@ -1390,6 +1446,7 @@ def trace(self, cmd, cwd, tracename, output):
'-e', 'trace=%s' % traces,
'-o', self._logname + '.' + tracename,
]
logging.info('%s', flags)

if self.use_sudo:
pipe_r, pipe_w = os.pipe()
Expand Down Expand Up @@ -3173,7 +3230,7 @@ def extract_directories(root_dir, files, blacklist):
# It is important for root_dir to not be a symlinked path, make sure to call
# os.path.realpath() as needed.
assert not root_dir or (
fs.realpath(file_path.get_native_path_case(root_dir)) == root_dir)
os.path.realpath(file_path.get_native_path_case(root_dir)) == root_dir)
assert not any(isinstance(f, Results.Directory) for f in files)
# Remove non existent files.
files = [f for f in files if f.existent]
Expand Down

0 comments on commit f1a95e3

Please sign in to comment.