deploy_chrome: Only set the security context when SELinux is supported.

Also run restorecon even if we're deploying the browser somewhere other
than /opt/google/chrome, but still mounting it there.

BUG=chromium:968155
TEST=deploy_chrome w/ --mount and ran security.SELinuxFilesARC
Change-Id: I8af5a45e7ac5434cddb69843b77c48b6bc8dbcb4
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1753104
Commit-Queue: Ben Pastene <bpastene@chromium.org>
Tested-by: Ben Pastene <bpastene@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
diff --git a/cli/deploy.py b/cli/deploy.py
index 0d6cac4..f79f2a3 100644
--- a/cli/deploy.py
+++ b/cli/deploy.py
@@ -815,28 +815,6 @@
     logging.notice('%s has been installed.', pkg_name)
 
 
-def _HasSELinux(device):
-  """Check whether the device has SELinux-enabled.
-
-  Args:
-    device: A ChromiumOSDevice object.
-  """
-  try:
-    device.CatFile('/sys/fs/selinux/enforce', max_size=None)
-    return True
-  except remote_access.CatFileError:
-    return False
-
-
-def _IsSELinuxEnforced(device):
-  """Check whether the device has SELinux-enforced.
-
-  Args:
-    device: A ChromiumOSDevice object
-  """
-  return device.CatFile('/sys/fs/selinux/enforce', max_size=None).strip() == '1'
-
-
 def _RestoreSELinuxContext(device, pkgpath, root):
   """Restore SELinux context for files in a given pacakge.
 
@@ -849,7 +827,7 @@
     pkgpath: path to tarball
     root: Package installation root path.
   """
-  enforced = _IsSELinuxEnforced(device)
+  enforced = device.IsSELinuxEnforced()
   if enforced:
     device.RunCommand(['setenforce', '0'])
   pkgroot = os.path.join(device.work_dir, 'packages')
@@ -961,7 +939,7 @@
   dlc_deployed = False
   for pkg_path in _GetPackagesPaths(pkgs, strip, sysroot):
     _Emerge(device, pkg_path, root, extra_args=emerge_args)
-    if _HasSELinux(device):
+    if device.IsSELinuxAvailable():
       _RestoreSELinuxContext(device, pkg_path, root)
     if _DeployDLCImage(device, pkg_path):
       dlc_deployed = True
@@ -1170,7 +1148,7 @@
       else:
         func()
 
-      if _HasSELinux(device):
+      if device.IsSELinuxAvailable():
         if sum(x.count('selinux-policy') for x in pkgs):
           logging.warning(
               'Deploying SELinux policy will not take effect until reboot. '
diff --git a/cli/deploy_unittest.py b/cli/deploy_unittest.py
index 93379fa..b4c9515 100644
--- a/cli/deploy_unittest.py
+++ b/cli/deploy_unittest.py
@@ -38,10 +38,17 @@
     self.lsb_release = None
     self.cmds = []
     self.work_dir = '/testdir/'
+    self.selinux_available = False
 
   def MountRootfsReadWrite(self):
     return True
 
+  def IsSELinuxAvailable(self):
+    return self.selinux_available
+
+  def IsSELinuxEnforced(self):
+    return True
+
   def RunCommand(self, cmd, **_kwargs):
     self.cmds.append(cmd)
 
@@ -306,10 +313,6 @@
         deploy, '_GetPackagesByCPV', side_effect=self.FakeGetPackagesByCPV)
     self.emerge = self.PatchObject(deploy, '_Emerge', return_value=None)
     self.unmerge = self.PatchObject(deploy, '_Unmerge', return_value=None)
-    self.has_selinux = self.PatchObject(
-        deploy, '_HasSELinux', return_value=False)
-    self.is_selinux_enforced = self.PatchObject(
-        deploy, '_IsSELinuxEnforced', return_value=True)
     self.PatchObject(deploy, '_GetDLCInfo', return_value=(None, None))
 
   def testDeployEmerge(self):
@@ -364,7 +367,7 @@
                'restorecon', '-i', '-f', '-'],
               ['setenforce', '1']]
 
-    self.has_selinux.return_value = True
+    self.device.device.selinux_available = True
     packages = ['some/foo-1.2.3', _BINPKG, 'some/foobar-2.0']
     cpvs = ['some/foo-1.2.3', 'to/bar-1.2.5', 'some/foobar-2.0']
     self.package_scanner.return_value = PackageScannerFake(
diff --git a/lib/remote_access.py b/lib/remote_access.py
index 8731eda..c576f0d 100644
--- a/lib/remote_access.py
+++ b/lib/remote_access.py
@@ -756,6 +756,16 @@
                                       capture_output=True)
     return re.search(r'Speed: \d+000Mb/s', result.output)
 
+  def IsSELinuxAvailable(self):
+    """Check whether the device has SELinux compiled in."""
+    return self.IfFileExists('/sys/fs/selinux/enforce')
+
+  def IsSELinuxEnforced(self):
+    """Check whether the device has SELinux-enforced."""
+    if not self.IsSELinuxAvailable():
+      return False
+    return self.CatFile('/sys/fs/selinux/enforce', max_size=None).strip() == '1'
+
   def RegisterCleanupCmd(self, cmd, **kwargs):
     """Register a cleanup command to be run on the device in Cleanup().
 
@@ -886,6 +896,7 @@
 
   def IfFileExists(self, path, **kwargs):
     """Check if the given path exists on the device."""
+    kwargs.setdefault('error_code_ok', True)
     result = self.RunCommand(['test -f %s' % path], **kwargs)
     return result.returncode == 0
 
diff --git a/lib/remote_access_unittest.py b/lib/remote_access_unittest.py
index 74cb691..447c5d4 100644
--- a/lib/remote_access_unittest.py
+++ b/lib/remote_access_unittest.py
@@ -306,6 +306,30 @@
 
     self.assertEqual(self.rsh_mock.call_count, 2)
 
+  def testSELinux(self):
+    """Tests behavior of IsSELinuxAvailable() and IsSELinuxEnforced()."""
+    with remote_access.RemoteDeviceHandler('1.1.1.1') as device:
+      self.rsh_mock.AddCmdResult(
+          partial_mock.ListRegex('test -f'), returncode=0)
+      self.rsh_mock.AddCmdResult(
+          partial_mock.ListRegex('cat /sys/fs/selinux/enforce'),
+          returncode=0, output='1')
+      self.assertEqual(device.IsSELinuxAvailable(), True)
+      self.assertEqual(device.IsSELinuxEnforced(), True)
+
+      self.rsh_mock.AddCmdResult(
+          partial_mock.ListRegex('test -f'), returncode=0)
+      self.rsh_mock.AddCmdResult(
+          partial_mock.ListRegex('cat /sys/fs/selinux/enforce'),
+          returncode=0, output='0')
+      self.assertEqual(device.IsSELinuxAvailable(), True)
+      self.assertEqual(device.IsSELinuxEnforced(), False)
+
+      self.rsh_mock.AddCmdResult(
+          partial_mock.ListRegex('test -f'), returncode=1)
+      self.assertEqual(device.IsSELinuxAvailable(), False)
+      self.assertEqual(device.IsSELinuxEnforced(), False)
+
 
 class ScpTest(cros_test_lib.MockTempDirTestCase):
   """Tests for RemoteAccess.Scp"""
diff --git a/scripts/deploy_chrome.py b/scripts/deploy_chrome.py
index a3566a6..39aa830 100644
--- a/scripts/deploy_chrome.py
+++ b/scripts/deploy_chrome.py
@@ -276,8 +276,11 @@
                              compress=self._ShouldUseCompression(),
                              debug_level=logging.INFO,
                              verbose=self.options.verbose)
-    # Set the security context.
-    if self.options.target_dir == _CHROME_DIR:
+
+    # Set the security context on the default Chrome dir if that's where it's
+    # getting deployed, and only on SELinux supported devices.
+    if (self.device.IsSELinuxAvailable() and
+        _CHROME_DIR in (self.options.target_dir, self.options.mount_dir)):
       self.device.RunCommand(['restorecon', '-R', _CHROME_DIR])
 
     for p in self.copy_paths: