@@ -59,7 +59,7 @@ struct uprobe {
5959 struct rw_semaphore register_rwsem ;
6060 struct rw_semaphore consumer_rwsem ;
6161 struct list_head pending_list ;
62- struct uprobe_consumer * consumers ;
62+ struct list_head consumers ;
6363 struct inode * inode ; /* Also hold a ref to inode */
6464 struct rcu_head rcu ;
6565 loff_t offset ;
@@ -783,6 +783,7 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset,
783783 uprobe -> inode = inode ;
784784 uprobe -> offset = offset ;
785785 uprobe -> ref_ctr_offset = ref_ctr_offset ;
786+ INIT_LIST_HEAD (& uprobe -> consumers );
786787 init_rwsem (& uprobe -> register_rwsem );
787788 init_rwsem (& uprobe -> consumer_rwsem );
788789 RB_CLEAR_NODE (& uprobe -> rb_node );
@@ -808,32 +809,19 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset,
808809static void consumer_add (struct uprobe * uprobe , struct uprobe_consumer * uc )
809810{
810811 down_write (& uprobe -> consumer_rwsem );
811- uc -> next = uprobe -> consumers ;
812- uprobe -> consumers = uc ;
812+ list_add_rcu (& uc -> cons_node , & uprobe -> consumers );
813813 up_write (& uprobe -> consumer_rwsem );
814814}
815815
816816/*
817817 * For uprobe @uprobe, delete the consumer @uc.
818- * Return true if the @uc is deleted successfully
819- * or return false.
818+ * Should never be called with consumer that's not part of @uprobe->consumers.
820819 */
821- static bool consumer_del (struct uprobe * uprobe , struct uprobe_consumer * uc )
820+ static void consumer_del (struct uprobe * uprobe , struct uprobe_consumer * uc )
822821{
823- struct uprobe_consumer * * con ;
824- bool ret = false;
825-
826822 down_write (& uprobe -> consumer_rwsem );
827- for (con = & uprobe -> consumers ; * con ; con = & (* con )-> next ) {
828- if (* con == uc ) {
829- * con = uc -> next ;
830- ret = true;
831- break ;
832- }
833- }
823+ list_del_rcu (& uc -> cons_node );
834824 up_write (& uprobe -> consumer_rwsem );
835-
836- return ret ;
837825}
838826
839827static int __copy_insn (struct address_space * mapping , struct file * filp ,
@@ -929,7 +917,8 @@ static bool filter_chain(struct uprobe *uprobe, struct mm_struct *mm)
929917 bool ret = false;
930918
931919 down_read (& uprobe -> consumer_rwsem );
932- for (uc = uprobe -> consumers ; uc ; uc = uc -> next ) {
920+ list_for_each_entry_srcu (uc , & uprobe -> consumers , cons_node ,
921+ srcu_read_lock_held (& uprobes_srcu )) {
933922 ret = consumer_filter (uc , mm );
934923 if (ret )
935924 break ;
@@ -1125,18 +1114,29 @@ void uprobe_unregister(struct uprobe *uprobe, struct uprobe_consumer *uc)
11251114 int err ;
11261115
11271116 down_write (& uprobe -> register_rwsem );
1128- if (WARN_ON (!consumer_del (uprobe , uc ))) {
1129- err = - ENOENT ;
1130- } else {
1131- err = register_for_each_vma (uprobe , NULL );
1132- /* TODO : cant unregister? schedule a worker thread */
1133- if (unlikely (err ))
1134- uprobe_warn (current , "unregister, leaking uprobe" );
1135- }
1117+ consumer_del (uprobe , uc );
1118+ err = register_for_each_vma (uprobe , NULL );
11361119 up_write (& uprobe -> register_rwsem );
11371120
1138- if (!err )
1139- put_uprobe (uprobe );
1121+ /* TODO : cant unregister? schedule a worker thread */
1122+ if (unlikely (err )) {
1123+ uprobe_warn (current , "unregister, leaking uprobe" );
1124+ goto out_sync ;
1125+ }
1126+
1127+ put_uprobe (uprobe );
1128+
1129+ out_sync :
1130+ /*
1131+ * Now that handler_chain() and handle_uretprobe_chain() iterate over
1132+ * uprobe->consumers list under RCU protection without holding
1133+ * uprobe->register_rwsem, we need to wait for RCU grace period to
1134+ * make sure that we can't call into just unregistered
1135+ * uprobe_consumer's callbacks anymore. If we don't do that, fast and
1136+ * unlucky enough caller can free consumer's memory and cause
1137+ * handler_chain() or handle_uretprobe_chain() to do an use-after-free.
1138+ */
1139+ synchronize_srcu (& uprobes_srcu );
11401140}
11411141EXPORT_SYMBOL_GPL (uprobe_unregister );
11421142
@@ -1214,13 +1214,20 @@ EXPORT_SYMBOL_GPL(uprobe_register);
12141214int uprobe_apply (struct uprobe * uprobe , struct uprobe_consumer * uc , bool add )
12151215{
12161216 struct uprobe_consumer * con ;
1217- int ret = - ENOENT ;
1217+ int ret = - ENOENT , srcu_idx ;
12181218
12191219 down_write (& uprobe -> register_rwsem );
1220- for (con = uprobe -> consumers ; con && con != uc ; con = con -> next )
1221- ;
1222- if (con )
1223- ret = register_for_each_vma (uprobe , add ? uc : NULL );
1220+
1221+ srcu_idx = srcu_read_lock (& uprobes_srcu );
1222+ list_for_each_entry_srcu (con , & uprobe -> consumers , cons_node ,
1223+ srcu_read_lock_held (& uprobes_srcu )) {
1224+ if (con == uc ) {
1225+ ret = register_for_each_vma (uprobe , add ? uc : NULL );
1226+ break ;
1227+ }
1228+ }
1229+ srcu_read_unlock (& uprobes_srcu , srcu_idx );
1230+
12241231 up_write (& uprobe -> register_rwsem );
12251232
12261233 return ret ;
@@ -2085,10 +2092,12 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
20852092 struct uprobe_consumer * uc ;
20862093 int remove = UPROBE_HANDLER_REMOVE ;
20872094 bool need_prep = false; /* prepare return uprobe, when needed */
2095+ bool has_consumers = false;
20882096
2089- down_read (& uprobe -> register_rwsem );
20902097 current -> utask -> auprobe = & uprobe -> arch ;
2091- for (uc = uprobe -> consumers ; uc ; uc = uc -> next ) {
2098+
2099+ list_for_each_entry_srcu (uc , & uprobe -> consumers , cons_node ,
2100+ srcu_read_lock_held (& uprobes_srcu )) {
20922101 int rc = 0 ;
20932102
20942103 if (uc -> handler ) {
@@ -2101,31 +2110,40 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
21012110 need_prep = true;
21022111
21032112 remove &= rc ;
2113+ has_consumers = true;
21042114 }
21052115 current -> utask -> auprobe = NULL ;
21062116
21072117 if (need_prep && !remove )
21082118 prepare_uretprobe (uprobe , regs ); /* put bp at return */
21092119
2110- if (remove && uprobe -> consumers ) {
2111- WARN_ON (!uprobe_is_active (uprobe ));
2112- unapply_uprobe (uprobe , current -> mm );
2120+ if (remove && has_consumers ) {
2121+ down_read (& uprobe -> register_rwsem );
2122+
2123+ /* re-check that removal is still required, this time under lock */
2124+ if (!filter_chain (uprobe , current -> mm )) {
2125+ WARN_ON (!uprobe_is_active (uprobe ));
2126+ unapply_uprobe (uprobe , current -> mm );
2127+ }
2128+
2129+ up_read (& uprobe -> register_rwsem );
21132130 }
2114- up_read (& uprobe -> register_rwsem );
21152131}
21162132
21172133static void
21182134handle_uretprobe_chain (struct return_instance * ri , struct pt_regs * regs )
21192135{
21202136 struct uprobe * uprobe = ri -> uprobe ;
21212137 struct uprobe_consumer * uc ;
2138+ int srcu_idx ;
21222139
2123- down_read (& uprobe -> register_rwsem );
2124- for (uc = uprobe -> consumers ; uc ; uc = uc -> next ) {
2140+ srcu_idx = srcu_read_lock (& uprobes_srcu );
2141+ list_for_each_entry_srcu (uc , & uprobe -> consumers , cons_node ,
2142+ srcu_read_lock_held (& uprobes_srcu )) {
21252143 if (uc -> ret_handler )
21262144 uc -> ret_handler (uc , ri -> func , regs );
21272145 }
2128- up_read ( & uprobe -> register_rwsem );
2146+ srcu_read_unlock ( & uprobes_srcu , srcu_idx );
21292147}
21302148
21312149static struct return_instance * find_next_ret_chain (struct return_instance * ri )
0 commit comments