From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Daniel P. Berrange" Subject: [PATCH] Scrub VNC passwords from XenD log files Date: Tue, 5 Dec 2006 19:31:25 +0000 Message-ID: <20061205193125.GF21067@redhat.com> Reply-To: "Daniel P. Berrange" Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="FsscpQKzF/jJk6ya" Return-path: Content-Disposition: inline List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: xen-devel@lists.xensource.com List-Id: xen-devel@lists.xenproject.org --FsscpQKzF/jJk6ya Content-Type: text/plain; charset=us-ascii Content-Disposition: inline The XendDomainInfo and XendConfig classes both log the guest VM config data to the /var/log/xen/xend.log in many places. Unfortunately the VNC passwords are stored in plain text in the guest VM config files. So we end up with plain text passwords in the xend.log file Now we can make /var/log/xen mode 0700 to protect them from local users, but it is very common when debugging issues to request that a user attach the contents of /var/log/xen/xend.log to the bug report ticket, or emails sent to mailing lists. This will obviously compromise any VNC passwords to essentially the while world & his dog. What's more, Google will make it incredibly easy to search for these too. There are a few potential approaches to this 1. Remove all logging from xend.log 2. Change default log level to only record WARN and higher, so DEBUG stuff is not recorded normally 3. Scrub the passwords out of the data being logged 4. Do nothing I really don't like options 1 or 2, because the stuff XenD is logging is actually incredibly helpful when debugging end user problems. 4 is not really a viable option either. So we're left with 3. Thus I am attaching a prototype patch which scrubs VNC passwords out of the data being logged by XenD. Regards, Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=| --FsscpQKzF/jJk6ya Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="xen-3.0.4-scrub-passwords.patch" diff -r 7df4d8cfba3b tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Tue Dec 05 12:42:29 2006 +0000 +++ b/tools/python/xen/xend/XendConfig.py Tue Dec 05 14:33:34 2006 -0500 @@ -41,6 +41,35 @@ def reverse_dict(adict): def bool0(v): return v != '0' and bool(v) + +# Recursively copy a data struct, scrubbing out VNC passwords. +# Will scrub any dict entry with a key of 'vncpasswd' or any +# 2-element list whose first member is 'vncpasswd'. It will +# also scrub a string matching '(vncpasswd XYZ)'. Everything +# else is no-op passthrough +def scrub_password(data): + log.debug("Scrub " + str(type(data))) + if type(data) == dict or type(data) == XendConfig: + scrubbed = {} + for key in data.keys(): + if key == "vncpasswd": + scrubbed[key] = "XXXXXXXX" + else: + scrubbed[key] = scrub_password(data[key]) + return scrubbed + elif type(data) == list: + if len(data) == 2 and type(data[0]) == str and data[0] == 'vncpasswd': + return ['vncpasswd', 'XXXXXXXX'] + else: + scrubbed = [] + for entry in data: + scrubbed.append(scrub_password(entry)) + return scrubbed + elif type(data) == str: + return re.sub(r'\(vncpasswd\s+[^\)]+\)','(vncpasswd XXXXXX)', data) + else: + return data + # Mapping from XendConfig configuration keys to the old # legacy configuration keys that map directly. @@ -269,7 +298,7 @@ class XendConfig(dict): # output from xc.domain_getinfo self._dominfo_to_xapi(dominfo) - log.debug('XendConfig.init: %s' % self) + log.debug('XendConfig.init: %s' % scrub_password(self)) # validators go here self.validate() diff -r 7df4d8cfba3b tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Tue Dec 05 12:42:29 2006 +0000 +++ b/tools/python/xen/xend/XendDomainInfo.py Tue Dec 05 14:33:25 2006 -0500 @@ -40,6 +40,7 @@ from xen.xend import balloon, sxp, uuid, from xen.xend import balloon, sxp, uuid, image, arch from xen.xend import XendRoot, XendNode, XendConfig +from xen.xend.XendConfig import scrub_password from xen.xend.XendBootloader import bootloader from xen.xend.XendError import XendError, VmError from xen.xend.XendDevices import XendDevices @@ -148,7 +149,7 @@ def create(config): @raise VmError: Invalid configuration or failure to start. """ - log.debug("XendDomainInfo.create(%s)", config) + log.debug("XendDomainInfo.create(%s)", scrub_password(config)) vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config)) try: vm.start() @@ -175,7 +176,7 @@ def recreate(info, priv): @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.recreate(%s)", info) + log.debug("XendDomainInfo.recreate(%s)", scrub_password(info)) assert not info['dying'] @@ -257,7 +258,7 @@ def restore(config): @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.restore(%s)", config) + log.debug("XendDomainInfo.restore(%s)", scrub_password(config)) vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config), resume = True) try: @@ -280,7 +281,7 @@ def createDormant(domconfig): @raise XendError: Errors with configuration. """ - log.debug("XendDomainInfo.createDormant(%s)", domconfig) + log.debug("XendDomainInfo.createDormant(%s)", scrub_password(domconfig)) # domid does not make sense for non-running domains. domconfig.pop('domid', None) @@ -520,11 +521,11 @@ class XendDomainInfo: @param dev_config: device configuration @type dev_config: SXP object (parsed config) """ - log.debug("XendDomainInfo.device_create: %s" % dev_config) + log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config)) dev_type = sxp.name(dev_config) dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config) dev_config_dict = self.info['devices'][dev_uuid][1] - log.debug("XendDomainInfo.device_create: %s" % dev_config_dict) + log.debug("XendDomainInfo.device_create: %s" % scrub_password(dev_config_dict)) devid = self._createDevice(dev_type, dev_config_dict) self._waitForDevice(dev_type, devid) return self.getDeviceController(dev_type).sxpr(devid) @@ -746,7 +747,7 @@ class XendDomainInfo: to_store.update(self._vcpuDomDetails()) - log.debug("Storing domain details: %s", to_store) + log.debug("Storing domain details: %s", scrub_password(to_store)) self._writeDom(to_store) @@ -1661,7 +1662,7 @@ class XendDomainInfo: if not self._readVm('xend/restart_count'): to_store['xend/restart_count'] = str(0) - log.debug("Storing VM details: %s", to_store) + log.debug("Storing VM details: %s", scrub_password(to_store)) self._writeVm(to_store) self._setVmPermissions() --FsscpQKzF/jJk6ya Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel --FsscpQKzF/jJk6ya--