cros deploy: change working directory to alternative root for restorecon

Change working directory to alternative root specified in --root before
restorecon. Since tar tf results prefixes `.' so file lists fed to
restorecon will be handled based on current working directory.

This prevents failing on restorecon with
SELinux: Could not get canonical path for ./path
restorecon: No such file or directory

But after changing to an alternative root is very likely to make this
restorecon call to be a no-op since the new paths are not defined in
file_contexts. So it would be pretty much equivalent to not to restorecon
for an alternative root. I think it would be fine on our SELinux
perspective since it is dev-only, and isn't the supposed behavior of an
image which a user is using.

BUG=chromium:987298
TEST=cros deploy betty cherrypi --root=/usr/local
TEST=cros deploy betty audit; ssh betty ls -Z /sbin/auditd => u:r:cros_auditd_exec:s0

Change-Id: Iddfd1da2c7b14d78c48619ce540f3ab455c21202
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/1720171
Tested-by: Qijiang Fan <fqj@google.com>
Commit-Queue: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Kenny Root <kroot@google.com>
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
diff --git a/cli/deploy.py b/cli/deploy.py
index db70053..23002ca 100644
--- a/cli/deploy.py
+++ b/cli/deploy.py
@@ -818,7 +818,7 @@
   return device.CatFile('/sys/fs/selinux/enforce', max_size=None).strip() == '1'
 
 
-def _RestoreSELinuxContext(device, pkgpath):
+def _RestoreSELinuxContext(device, pkgpath, root):
   """Restore SELinux context for files in a given pacakge.
 
   This reads the tarball from pkgpath, and calls restorecon on device to
@@ -828,6 +828,7 @@
   Args:
     device: a ChromiumOSDevice object
     pkgpath: path to tarball
+    root: Package installation root path.
   """
   enforced = _IsSELinuxEnforced(device)
   if enforced:
@@ -837,8 +838,9 @@
   pkgpath_device = os.path.join(pkgroot, pkg_dirname, os.path.basename(pkgpath))
   # Testing shows restorecon splits on newlines instead of spaces.
   device.RunCommand(
-      ['cd', '/', '&&',
-       'tar', 'tf', pkgpath_device, '|', 'restorecon', '-i', '-f', '-'],
+      ['cd', root, '&&',
+       'tar', 'tf', pkgpath_device, '|',
+       'restorecon', '-i', '-f', '-'],
       remote_sudo=True)
   if enforced:
     device.RunCommand(['setenforce', '1'])
@@ -940,7 +942,7 @@
   for pkg_path in _GetPackagesPaths(pkgs, strip, sysroot):
     _Emerge(device, pkg_path, root, extra_args=emerge_args)
     if _HasSELinux(device):
-      _RestoreSELinuxContext(device, pkg_path)
+      _RestoreSELinuxContext(device, pkg_path, root)
 
 
 def _UnmergePackages(pkgs, device, root):