rust_binder: don't delete FreezeListener if there are pending duplicates

When userspace issues commands to a freeze listener, it identifies it
using a cookie. Normally this cookie uniquely identifies a freeze
listener, but when userspace clears a listener with the intent of
deleting it, it's allowed to "regret" clearing it and create a new
freeze listener for the same node using the same cookie. (IMO this was
an API mistake, but userspace relies on it.)

Currently if the active freeze listener gets fully deleted while there
are still pending duplicates, then the code incorrectly deletes the
pending duplicates too. To fix this, do not delete the entry if there
are still pending duplicates.

Since the current data structure requires a main freeze listener, we
convert one pending duplicate into the primary listener in this
scenario.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Acked-by: Carlos Llamas <cmllamas@google.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by Alice Ryhl and committed by Greg Kroah-Hartman 99559e5b bfe144da

+10 -1
+10 -1
drivers/android/binder/freeze.rs
··· 106 return Ok(true); 107 } 108 if freeze.is_clearing { 109 - _removed_listener = freeze_entry.remove_node(); 110 drop(node_refs); 111 writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?; 112 writer.write_payload(&self.cookie.0)?;
··· 106 return Ok(true); 107 } 108 if freeze.is_clearing { 109 + kernel::warn_on!(freeze.num_cleared_duplicates != 0); 110 + if freeze.num_pending_duplicates > 0 { 111 + // The primary freeze listener was deleted, so convert a pending duplicate back 112 + // into the primary one. 113 + freeze.num_pending_duplicates -= 1; 114 + freeze.is_pending = true; 115 + freeze.is_clearing = true; 116 + } else { 117 + _removed_listener = freeze_entry.remove_node(); 118 + } 119 drop(node_refs); 120 writer.write_code(BR_CLEAR_FREEZE_NOTIFICATION_DONE)?; 121 writer.write_payload(&self.cookie.0)?;