Commit 55f4a793 authored by segfault's avatar segfault
Browse files

Fix and improve tails-debugging-info.py

 - Fix wrong value set for owner
 - Fix whitespace in output
 - Fix doctests
 - Use /usr/bin/env in shebang
 - Make docstrings PEP 257 compliant
 - Add comment
parent 60d5490e
#! /usr/bin/python3
'''
Debug Tails.
#! /usr/bin/env python3
"""
Debug Tails.
Test with "python3 tails-debugging-info.py doctest" as root.
Test with "python3 tails-debugging-info.py doctest" as root.
goodcrypto.com converted from bash to python and added basic tests.
goodcrypto.com converted from bash to python and added basic tests.
*** WARNING about debug_file and debug_directory *********************
*** WARNING about debug_file and debug_directory *********************
Great attention must be given to the ownership situation of these
files and their parent directories in order to avoid a symlink-based
attack that could read the contents of any file and make it
accessible to the user running this script (typically the live
user). Therefore, when adding a new file, give as the first argument
'root' only if the complete path to it (including the file itself)
is owned by root and already exists before the system is connected to
the network (that is, before GDM's PostLogin script is run).
If not, the following rules must be followed strictly:
Great attention must be given to the ownership situation of these
files and their parent directories in order to avoid a symlink-based
attack that could read the contents of any file and make it
accessible to the user running this script (typically the live
user). Therefore, when adding a new file, give as the first argument
'root' only if the complete path to it (including the file itself)
is owned by root and already exists before the system is connected to
the network (that is, before GDM's PostLogin script is run).
If not, the following rules must be followed strictly:
* only one non-root user is involved in the ownership situation (the
file, its dir and the parent dirs). From now on let's assume it is
the case and call it $USER.
* only one non-root user is involved in the ownership situation (the
file, its dir and the parent dirs). From now on let's assume it is
the case and call it $USER.
* if any non-root group has write access, it must not have any
members.
* if any non-root group has write access, it must not have any
members.
If any of these rules does not apply, the file cannot be added here
safely and something is probably quite wrong and should be
investigated carefully.
>>> # run script
>>> this_command = sh.Command(sys.argv[0])
>>> this_command()
<BLANKLINE>
...
"""
If any of these rules does not apply, the file cannot be added here
safely and something is probably quite wrong and should be
investigated carefully.
'''
import os
import sys
from pwd import getpwuid
import sh
# AppArmor Ux rules don't sanitize PATH, which can lead to an
# exploited application (that's allowed to run this script unconfined)
# having this script run arbitrary code, violating that application's
# confinement. Let's prevent that by setting PATH to a list of
# directories where only root can write.
os.environ['PATH'] = '/usr/local/bin:/usr/bin:/bin'
def main():
"""
Print debug information.
"""Print debug information.
>>> main()
...
>>> main()
<BLANKLINE>
...
"""
debug_file('root', '/proc/cmdline')
......@@ -76,32 +89,40 @@ def main():
# The Journal
debug_command('/bin/journalctl', '--catalog', '--no-pager')
def debug_command(command, *args):
"""
Print the command and then run it.
"""Print the command and then run it.
>>> args = ['/usr/sbin/dmidecode', '-s', 'system-manufacturer']
>>> debug_command(args)
...
>>> debug_command('echo', 'foo')
<BLANKLINE>
===== output of command echo foo =====
foo
"""
print()
print('===== output of command {} {} ====='.format(command, ' '.join(args)))
print('===== output of command {} ====='.format(' '.join((command,) + args)))
run = sh.Command(command)
output = run(*args).stdout.decode().strip()
print(output)
def debug_file(user, filename):
"""
Print file content.
"""Print file content.
>>> debug_file('amnesia', '/etc/hosts')
...
>>> import tempfile, getpass
>>> with tempfile.NamedTemporaryFile('w') as f:
... _ = f.write("foo\\nbar")
... _ = f.seek(0)
... debug_file(getpass.getuser(), f.name)
<BLANKLINE>
===== content of ... =====
foo
bar
"""
if not os.path.isfile(filename):
return
owner = getpwuid(os.stat(filename).st_uid)
owner = getpwuid(os.stat(filename).st_uid).pw_name
if owner != user:
print()
print('WARNING: not opening file {}, '.format(filename), end='')
......@@ -111,21 +132,27 @@ def debug_file(user, filename):
print()
print('===== content of {} ====='.format(filename))
with open(filename) as f:
print(f.read())
print(f.read(), end='')
def debug_directory(user, dir_name):
"""
List directory and print content of all contained files (non-recursively).
"""List directory and print content of all contained files (non-recursively).
>>> debug_directory('amnesia', '/tmp')
...
>>> import tempfile, getpass
>>> with tempfile.TemporaryDirectory() as tmpdir:
... open(os.path.join(tmpdir, 'foo'), 'w').close()
... debug_directory(getpass.getuser(), tmpdir)
<BLANKLINE>
===== listing of ... =====
foo
"""
if not os.path.isdir(dir_name):
return
owner = getpwuid(os.stat(dir_name).st_uid)
print()
owner = getpwuid(os.stat(dir_name).st_uid).pw_name
if owner != user:
print()
print('WARNING: not opening directory {}, '.format(dir_name), end='')
print('because it is owned by {} instead of {}'.format(owner, user))
return
......@@ -140,21 +167,12 @@ def debug_directory(user, dir_name):
debug_file(user, f)
'''
>>> # run script
>>> this_command = sh.Command(sys.argv[0])
>>> this_command()
<BLANKLINE>
'''
if __name__ == '__main__':
if sys.argv and len(sys.argv) > 1:
if sys.argv[1] == 'doctest':
from doctest import testmod
testmod()
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
else:
main()
else:
main()
sys.exit(0)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment