Skip Menu |
 

Subject: profile_flush_to_file() can corrupt shared tree state
Download (untitled) / with headers
text/plain 2.1KiB
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.
From: ghudson@mit.edu
Subject: git commit

Fix profile_flush_to_file() state corruption

In write_data_to_file(), do not clear the profile data object's flags.
If the call to this function resulted from profile_flush_to_file(), we
do not want to clear the DIRTY flag, and we especially do not want to
clear the SHARED flag for a data object which is part of
g_shared_trees. Instead, clear the DIRTY flag in
profile_flush_file_data().

Add a test case to prof_test1 to exercise the bug in unfixed code.
Also modify test1 to abandon the altered profile after flushing it to
a file, to preserve the external behavior of the script before this
fix.

https://github.com/krb5/krb5/commit/32a05995ff9df0d5ef8aff0d020900a37747670d
Author: Greg Hudson <ghudson@mit.edu>
Commit: 32a05995ff9df0d5ef8aff0d020900a37747670d
Branch: master
src/util/profile/prof_file.c | 2 +-
src/util/profile/prof_test1 | 22 +++++++++++++++++++++-
2 files changed, 22 insertions(+), 2 deletions(-)
From: tlyu@mit.edu
Subject: git commit

Fix profile_flush_to_file() state corruption

In write_data_to_file(), do not clear the profile data object's flags.
If the call to this function resulted from profile_flush_to_file(), we
do not want to clear the DIRTY flag, and we especially do not want to
clear the SHARED flag for a data object which is part of
g_shared_trees. Instead, clear the DIRTY flag in
profile_flush_file_data().

Add a test case to prof_test1 to exercise the bug in unfixed code.
Also modify test1 to abandon the altered profile after flushing it to
a file, to preserve the external behavior of the script before this
fix.

(cherry picked from commit 32a05995ff9df0d5ef8aff0d020900a37747670d)

https://github.com/krb5/krb5/commit/ab1aeed87db2d9e5777f99c850aa9b0c6500a6cc
Author: Greg Hudson <ghudson@mit.edu>
Committer: Tom Yu <tlyu@mit.edu>
Commit: ab1aeed87db2d9e5777f99c850aa9b0c6500a6cc
Branch: krb5-1.14
src/util/profile/prof_file.c | 2 +-
src/util/profile/prof_test1 | 22 +++++++++++++++++++++-
2 files changed, 22 insertions(+), 2 deletions(-)
From: tlyu@mit.edu
Subject: git commit

Fix profile_flush_to_file() state corruption

In write_data_to_file(), do not clear the profile data object's flags.
If the call to this function resulted from profile_flush_to_file(), we
do not want to clear the DIRTY flag, and we especially do not want to
clear the SHARED flag for a data object which is part of
g_shared_trees. Instead, clear the DIRTY flag in
profile_flush_file_data().

Add a test case to prof_test1 to exercise the bug in unfixed code.
Also modify test1 to abandon the altered profile after flushing it to
a file, to preserve the external behavior of the script before this
fix.

(cherry picked from commit 32a05995ff9df0d5ef8aff0d020900a37747670d)

https://github.com/krb5/krb5/commit/8920cdf552b761de517b59c774d857bd5a467f8f
Author: Greg Hudson <ghudson@mit.edu>
Committer: Tom Yu <tlyu@mit.edu>
Commit: 8920cdf552b761de517b59c774d857bd5a467f8f
Branch: krb5-1.13
src/util/profile/prof_file.c | 2 +-
src/util/profile/prof_test1 | 22 +++++++++++++++++++++-
2 files changed, 22 insertions(+), 2 deletions(-)