Add selinux context manager for writing files
Glean can be responsible for creation of a few sensitive files, so make sure we restore the selinux context on any written files. I have tested this with selinux enabled and disabled; the restorecon should be a safe operation even if selinux is disabled and will ensure the right context if you ever re-enable selinux. Tested with centos-minimal builds and the kolla job that was previously hitting problems with the /etc/hostname file context. Change-Id: Ia2eba157e35b1e1b0bcdb830f98061692a198d42
This commit is contained in:
parent
64deca3c5b
commit
6bbb3073ae
25
glean/cmd.py
25
glean/cmd.py
|
@ -16,6 +16,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
import errno
|
||||
import json
|
||||
import logging
|
||||
|
@ -39,6 +40,24 @@ slaves_del = " pre-down ifenslave -d {0} {1}\n"
|
|||
# Type value for permanent mac addrs as defined by the linux kernel.
|
||||
PERMANENT_ADDR_TYPE = '0'
|
||||
|
||||
# Global flag for selinux restore.
|
||||
SELINUX_RESTORECON = '/usr/sbin/restorecon'
|
||||
HAVE_SELINUX = os.path.exists(SELINUX_RESTORECON)
|
||||
|
||||
|
||||
# Wrap open calls in this to make sure that any created or modified
|
||||
# files retain their selinux context.
|
||||
@contextlib.contextmanager
|
||||
def safe_open(*args, **kwargs):
|
||||
f = open(*args, **kwargs)
|
||||
try:
|
||||
yield f
|
||||
finally:
|
||||
path = os.path.abspath(f.name)
|
||||
if HAVE_SELINUX:
|
||||
logging.debug("Restoring selinux context for %s" % path)
|
||||
subprocess.call([SELINUX_RESTORECON, path])
|
||||
|
||||
|
||||
def _exists_rh_interface(name):
|
||||
file_to_check = '/etc/sysconfig/network-scripts/ifcfg-{name}'.format(
|
||||
|
@ -628,7 +647,7 @@ def finish_files(files_to_write, args):
|
|||
while True:
|
||||
try:
|
||||
log.debug("Writing output file : %s" % k)
|
||||
with open(k, 'w') as outfile:
|
||||
with safe_open(k, 'w') as outfile:
|
||||
outfile.write(files_to_write[k])
|
||||
log.debug(" ... done")
|
||||
break
|
||||
|
@ -880,7 +899,7 @@ def set_hostname_from_config_drive(args):
|
|||
with open('/etc/conf.d/hostname', 'w') as fh:
|
||||
fh.write("hostname=\"{host}\"\n".format(host=hostname))
|
||||
else:
|
||||
with open('/etc/hostname', 'w') as fh:
|
||||
with safe_open('/etc/hostname', 'w') as fh:
|
||||
fh.write(hostname)
|
||||
fh.write('\n')
|
||||
|
||||
|
@ -917,7 +936,7 @@ def set_hostname_from_config_drive(args):
|
|||
|
||||
# Write out a hosts entry for hostname
|
||||
if match is None:
|
||||
with open('/etc/hosts', 'a+') as fh:
|
||||
with safe_open('/etc/hosts', 'a+') as fh:
|
||||
fh.write(u'%s %s\n' % (host_value, host))
|
||||
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ class TestGlean(base.BaseTestCase):
|
|||
mock_handle = mock.Mock()
|
||||
mock_handle.__enter__ = mock.Mock()
|
||||
mock_handle.__exit__ = mock.Mock()
|
||||
mock_handle.name = args[0]
|
||||
# This is a trick to handle open used as a context
|
||||
# manager (i.e. with open('foo') as f). It's the
|
||||
# returned object that gets called, so we point it
|
||||
|
@ -86,12 +87,10 @@ class TestGlean(base.BaseTestCase):
|
|||
# second call opens as usual. We check that there
|
||||
# was an os.unlink() performed
|
||||
if args[0].startswith('/etc/resolv.conf'):
|
||||
self._resolv_unlinked = True
|
||||
mock_handle.__enter__ = mock.Mock(
|
||||
side_effect=[IOError(errno.ELOOP,
|
||||
os.strerror(errno.ELOOP),
|
||||
args[0]),
|
||||
mock_handle])
|
||||
if not self._resolv_unlinked:
|
||||
self._resolv_unlinked = True
|
||||
raise IOError(errno.ELOOP,
|
||||
os.strerror(errno.ELOOP), args[0])
|
||||
self.file_handle_mocks[args[0]] = mock_handle
|
||||
return mock_handle
|
||||
elif args[0].startswith('/sys/class/net'):
|
||||
|
|
Loading…
Reference in New Issue