[krbdev.mit.edu #8431] profile_flush_to_file() can corrupt shared tree state

Greg Hudson via RT rt-comment at krbdev.mit.edu
Thu Jun 23 11:52:23 EDT 2016


 A profile data object can have two flags: DIRTY and SHARED.  DIRTY means 
there are unflushed changes in memory relative to the contents on disk, due to 
a mutating API call like profile_update_relation().  SHARED means the data 
object is part of g_shared_trees.  These flags are exclusive; mutation 
operations on a SHARED object will create a new data object with the DIRTY 
flag.

The normal flush profile_flush() operation (which is also implicit in 
profile_release()) checks the DIRTY flag and does nothing if it is not set.  
There is no bug to report here.

profile_flush_to_file() writes the contents of the profile to a specified 
file, which is presumably different from the one the profile was loaded from.    
This calls profile_flush_file_data_to_file() which calls write_data_to_file().   
The DIRTY flag is not checked, because there is no presumption that the target 
file ever contained the contents of the data object.

At the end of write_data_to_file(), data->flags is set to 0.  I assume the 
intent is to clear the DIRTY flag for a profile_flush() call, but the flag 
change is at the wrong layer.  For profile_flush_to_file(), this is harmful in 
two cases:

* For a DIRTY data object, the data object is set to non-DIRTY even though the 
profile's backing file was probably not updated.

* For a SHARED data object, the data object remains part of g_shared_trees but 
does not have the SHARED flag set.  This becomes very bad later on.  When the 
data object is dereferenced and deleted, profile_free_file_data() will free 
the data object but will not remove it from g_shared_trees, leaving a dangling 
reference.

To reproduce the second problem:

1. Open a profile.
2. Without making any changes, call profile_flush_to_file().
3. Release the profile (leaves a dangling reference in g_shared_trees).
4. Open a profile (dereferences the dangling g_shared_trees reference and 
fails an assertion).

Note that test1() in prof_test1 invokes profile_flush_to_file and then 
profile_release.  Fixing both sides bug will change the behavior of 
profile_release (the updated relations will be written to test2.ini), so we 
might need to change it to profile_abandon.



More information about the krb5-bugs mailing list