From 03fbe320e1e19692d184d3f45c5e69f3150b2c5f Mon Sep 17 00:00:00 2001 From: Trishank Karthik Kuppusamy Date: Fri, 19 Feb 2016 17:27:17 -0500 Subject: [PATCH 1/2] Skip visited roles in preorder DFS. --- tuf/client/updater.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tuf/client/updater.py b/tuf/client/updater.py index 878aca0e..aada3843 100755 --- a/tuf/client/updater.py +++ b/tuf/client/updater.py @@ -2400,12 +2400,13 @@ def _preorder_depth_first_walk(self, target_filepath): target = None current_metadata = self.metadata['current'] role_names = ['targets'] + visited_role_names = set() # Ensure the client has the most up-to-date version of 'targets.json'. # Raise 'tuf.NoWorkingMirrorError' if the changed metadata cannot be # successfully downloaded and 'tuf.RepositoryError' if the referenced - # metadata is missing. Target methods such as this one are called after the - # top-level metadata have been refreshed (i.e., updater.refresh()). + # metadata is missing. Target methods such as this one are called after + # the top-level metadata have been refreshed (i.e., updater.refresh()). self._update_metadata_if_changed('targets') # Preorder depth-first traversal of the tree of target delegations. @@ -2413,13 +2414,17 @@ def _preorder_depth_first_walk(self, target_filepath): # Pop the role name from the top of the stack. role_name = role_names.pop(-1) + # Skip any visited current role. + if role_name in visited_role_names: + logger.debug('Skipping visited current role '+repr(role_name)) + continue - # The metadata for 'role_name' must be downloaded/updated before - # its targets, delegations, and child roles can be inspected. + # The metadata for 'role_name' must be downloaded/updated before its + # targets, delegations, and child roles can be inspected. # self.metadata['current'][role_name] is currently missing. - # _refresh_targets_metadata() does not refresh 'targets.json', it - # expects _update_metadata_if_changed() to have already refreshed it, - # which this function has checked above. + # _refresh_targets_metadata() does not refresh 'targets.json', it expects + # _update_metadata_if_changed() to have already refreshed it, which this + # function has checked above. self._refresh_targets_metadata(role_name, include_delegations=False) role_metadata = current_metadata[role_name] @@ -2428,6 +2433,8 @@ def _preorder_depth_first_walk(self, target_filepath): child_roles = delegations.get('roles', []) target = self._get_target_from_targets_role(role_name, targets, target_filepath) + # After preorder check, add current role to set of visited roles. + visited_role_names.add(role_name) if target is None: @@ -2450,7 +2457,8 @@ def _preorder_depth_first_walk(self, target_filepath): child_roles_to_visit.append(child_role_name) # Push 'child_roles_to_visit' in reverse order of appearance onto - # 'role_names'. Roles are popped from the end of the 'role_names' list. + # 'role_names'. Roles are popped from the end of the 'role_names' + # list. child_roles_to_visit.reverse() role_names.extend(child_roles_to_visit) From da0a9aa196346e66c1c4a276e0bfe016aa236055 Mon Sep 17 00:00:00 2001 From: Trishank Karthik Kuppusamy Date: Fri, 19 Feb 2016 17:44:21 -0500 Subject: [PATCH 2/2] By default, limit visited number of delegations in preorder DFS. --- tuf/client/updater.py | 10 +++++++++- tuf/conf.py | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tuf/client/updater.py b/tuf/client/updater.py index aada3843..7db9ebe7 100755 --- a/tuf/client/updater.py +++ b/tuf/client/updater.py @@ -2401,6 +2401,7 @@ def _preorder_depth_first_walk(self, target_filepath): current_metadata = self.metadata['current'] role_names = ['targets'] visited_role_names = set() + number_of_delegations = tuf.conf.MAX_NUMBER_OF_DELEGATIONS # Ensure the client has the most up-to-date version of 'targets.json'. # Raise 'tuf.NoWorkingMirrorError' if the changed metadata cannot be @@ -2410,7 +2411,7 @@ def _preorder_depth_first_walk(self, target_filepath): self._update_metadata_if_changed('targets') # Preorder depth-first traversal of the tree of target delegations. - while len(role_names) > 0 and target is None: + while target is None and number_of_delegations > 0 and len(role_names) > 0: # Pop the role name from the top of the stack. role_name = role_names.pop(-1) @@ -2435,6 +2436,8 @@ def _preorder_depth_first_walk(self, target_filepath): target_filepath) # After preorder check, add current role to set of visited roles. visited_role_names.add(role_name) + # And also decrement number of visited roles. + number_of_delegations -= 1 if target is None: @@ -2465,6 +2468,11 @@ def _preorder_depth_first_walk(self, target_filepath): else: logger.debug('Found target in current role '+repr(role_name)) + if target is None and number_of_delegations == 0 and len(role_names) > 0: + logger.debug(repr(len(role_names))+' roles left to visit, '+ + 'but allowed to visit at most '+ + repr(tuf.conf.MAX_NUMBER_OF_DELEGATIONS)+' delegations.') + return target diff --git a/tuf/conf.py b/tuf/conf.py index a3d63731..2683a71b 100755 --- a/tuf/conf.py +++ b/tuf/conf.py @@ -131,3 +131,7 @@ # the ['http', 'https'] URI schemes are supported, but may be modified by # integrators to schemes that they wish to support for their integration. SUPPORTED_URI_SCHEMES = ['http', 'https'] + +# By default, limit number of delegatees we visit for any target. +MAX_NUMBER_OF_DELEGATIONS = 2**5 +