[apparmor] [utils] proposed redesign for mergeprof

Kshitij Gupta kgupta8592 at gmail.com
Thu Sep 4 21:02:04 UTC 2014


Hello,

Seems I sent out that patch a bit early, a secondary consolidated
patch which fixes (hopefully) the issue multiple profiles in a file is
attached.
(Brace a for loop is removed resulting in a huge diff due to the indent change).

Note: I've allowed the debug messages to be there for the sake of clarity.

Regards,
Kshitij Gupta

On Fri, Sep 5, 2014 at 12:19 AM, Kshitij Gupta <kgupta8592 at gmail.com> wrote:
> Hello,
>
> Version -1:
>
> Changes to facilitate 2-way merge (maybe also 3-way) of multiple
> profiles as discussed on IRC ( which someone had to summarize for ml
> ;-))
>
> The proposal:
> - moves reset method to reset_aa function
> - modifies message displayed to user
> - allows processing of multiple files in 2-way merge
> - disables 3-way merge till new syntax has been decided
>
> The changes reflect the approach of providing arbitrary number of
> files using wildcards or explicitly. This makes it necessary to define
> a way to distinguish the files for base and other case to be used in
> 3-way merge.
> @cboltz Any ideas are welcome!
>
> The changes map the profiles in the given files to their respective
> files in the local directory specified using -d. Then the merges take
> place profile-wise. There are some cases with this approach with
> multiple profiles in a file where unnecessary questions are asked not
> relevant to the other profile.
>
> === modified file 'utils/aa-mergeprof'
> --- utils/aa-mergeprof    2014-09-03 23:49:47 +0000
> +++ utils/aa-mergeprof    2014-09-04 18:33:34 +0000
> @@ -26,19 +26,19 @@
>  from apparmor.translations import init_translation
>  _ = init_translation()
>
> -parser = argparse.ArgumentParser(description=_('Perform a 2-way or
> 3-way merge on the given profiles'),
> +parser = argparse.ArgumentParser(description=_('Perform a 2-way or
> 3-way merge on the given profiles'),
>      epilog='WARNING: the arguments will change in a future version!')
> -parser.add_argument('mine', type=str, help=_('your profile'))
> -parser.add_argument('base', type=str, help=_('base profile'))
> -parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
> +parser.add_argument('files', nargs='+', type=str, help=_('base profile'))
> +#parser.add_argument('other', nargs='?', type=str, help=_('other profile'))
>  parser.add_argument('-d', '--dir', type=str, help=_('path to profiles'))
>  #parser.add_argument('-a', '--auto', action='store_true',
> help=_('Automatically merge profiles, exits incase of *x conflicts'))
>  args = parser.parse_args()
>
> +args.other = None
>  # 2-way merge or 3-way merge based on number of params
> -merge_mode = 2 if args.other == None else 3
> +merge_mode = 2 #if args.other == None else 3
>
> -profiles = [args.mine, args.base, args.other]
> +profiles = [args.files, [args.other]]
>
>  profiledir = args.dir
>  if profiledir:
> @@ -46,9 +46,78 @@
>      if not os.path.isdir(apparmor.aa.profile_dir):
>          raise apparmor.AppArmorException(_("%s is not a directory.")
> %profiledir)
>
> +def reset_aa():
> +    apparmor.aa.aa = apparmor.aa.hasher()
> +    apparmor.aa.filelist = apparmor.aa.hasher()
> +    apparmor.aa.include = dict()
> +    apparmor.aa.existing_profiles = apparmor.aa.hasher()
> +    apparmor.aa.original_aa = apparmor.aa.hasher()
> +
> +def find_profiles_from_files(files):
> +    profile_to_filename = dict()
> +    for file_name in files:
> +        apparmor.aa.read_profile(file_name, True)
> +        for profile_name in apparmor.aa.filelist[file_name]['profiles'].keys():
> +            profile_to_filename[profile_name] = file_name
> +        reset_aa()
> +
> +    return profile_to_filename
> +
> +def find_files_from_profiles(profiles):
> +    profile_to_filename = dict()
> +    apparmor.aa.read_profiles()
> +
> +    for profile_name in profiles:
> +        profile_to_filename[profile_name] =
> apparmor.aa.get_profile_filename(profile_name)
> +
> +    reset_aa()
> +
> +    return profile_to_filename
>
>  def main():
> -    mergeprofiles = Merge(profiles)
> +    profiles_to_merge = set()
> +
> +    base_files, other_files = profiles
> +
> +    base_profile_to_file = find_profiles_from_files(base_files)
> +
> +    profiles_to_merge =
> profiles_to_merge.union(set(base_profile_to_file.keys()))
> +
> +    other_profile_to_file = dict()
> +
> +    if merge_mode == 3:
> +        other_profile_to_file = find_profiles_from_files(other_files)
> +        profiles_to_merge.add(other_profile_to_file.keys())
> +
> +    user_profile_to_file = find_files_from_profiles(profiles_to_merge)
> +
> +    print(base_files,"\n",other_files)
> +    print(base_profile_to_file,"\n",other_profile_to_file,"\n",user_profile_to_file)
> +    print(profiles_to_merge)
> +
> +    for profile_name in profiles_to_merge:
> +        user_file = user_profile_to_file[profile_name]
> +        base_file = base_profile_to_file.get(profile_name, None)
> +        other_file =  None
> +
> +        if merge_mode == 3:
> +            other_file = other_profile_to_file.get(profile_name, None)
> +
> +        if base_file == None:
> +            if other_file == None:
> +                continue
> +
> +            act([user_file, other_file, None], 2, profile_name)
> +        else:
> +            if other_file == None:
> +                act([user_file, base_file, None], 2, profile_name)
> +            else:
> +                act([user_file, base_file, other_file], 3, profile_name)
> +
> +        reset_aa()
> +
> +def act(files, merge_mode, merging_profile):
> +    mergeprofiles = Merge(files)
>      #Get rid of common/superfluous stuff
>      mergeprofiles.clear_common()
>
> @@ -62,10 +131,10 @@
>          mergeprofiles.ask_the_questions('base')
>
>          q = apparmor.aa.hasher()
> -        q['title'] = 'Changed Local Profiles'
> +        q['title'] = _('Changes for Local Profile: %s')%(merging_profile)
>          q['headers'] = []
> -        q['explanation'] = _('The following local profiles were
> changed. Would you like to save them?')
> -        q['functions'] = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES', 'CMD_ABORT']
> +        q['explanation'] = _('Would you like to save them?')
> +        q['functions'] = ['CMD_SAVE_CHANGES', 'CMD_VIEW_CHANGES',
> 'CMD_ABORT', 'CMD_IGNORE_ENTRY']
>          q['default'] = 'CMD_VIEW_CHANGES'
>          q['options'] = []
>          q['selected'] = 0
> @@ -84,6 +153,8 @@
>                  #oldprofile =
> apparmor.serialize_profile(apparmor.original_aa[program], program, '')
>                  newprofile =
> apparmor.aa.serialize_profile(mergeprofiles.user.aa[program], program,
> '')
>
> apparmor.aa.display_changes_with_comments(mergeprofiles.user.filename,
> newprofile)
> +            elif ans == 'CMD_IGNORE_ENTRY':
> +                break
>
>
>  class Merge(object):
> @@ -94,25 +165,18 @@
>          apparmor.aa.read_profile(base, True)
>          self.base = cleanprofile.Prof(base)
>
> -        self.reset()
> +        reset_aa()
>
>          #Read and parse other profile and save profile data, include
> data from it and reset them
>          if merge_mode == 3:
>              apparmor.aa.read_profile(other, True)
>              self.other = cleanprofile.Prof(other)
> -            self.reset()
> +            reset_aa()
>
>          #Read and parse user profile
>          apparmor.aa.read_profile(user, True)
>          self.user = cleanprofile.Prof(user)
>
> -    def reset(self):
> -        apparmor.aa.aa = apparmor.aa.hasher()
> -        apparmor.aa.filelist = apparmor.aa.hasher()
> -        apparmor.aa.include = dict()
> -        apparmor.aa.existing_profiles = apparmor.aa.hasher()
> -        apparmor.aa.original_aa = apparmor.aa.hasher()
> -
>      def clear_common(self):
>          deleted = 0
>
>
>
> Regards,
> Kshitij Gupta
-------------- next part --------------
A non-text attachment was scrubbed...
Name: mergeprof2.patch
Type: text/x-patch
Size: 61581 bytes
Desc: not available
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20140905/00608d0c/attachment-0001.bin>


More information about the AppArmor mailing list