Skip to content

Commit 8fbbe5d

Browse files
committed
ksmbd: fix use-after-free by using call_rcu() for oplock_info
ksmbd currently frees oplock_info immediately using kfree(), even though it is accessed under RCU read-side critical sections in places like opinfo_get() and proc_show_files(). Since there is no RCU grace period delay between nullifying the pointer and freeing the memory, a reader can still access oplock_info structure after it has been freed. This can leads to a use-after-free especially in opinfo_get() where atomic_inc_not_zero() is called on already freed memory. Fix this by switching to deferred freeing using call_rcu(). Cc: stable@vger.kernel.org Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
1 parent dac6acd commit 8fbbe5d

File tree

2 files changed

+14
-6
lines changed

2 files changed

+14
-6
lines changed

oplock.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ static void free_opinfo(struct oplock_info *opinfo)
135135
kfree(opinfo);
136136
}
137137

138+
static void free_opinfo_rcu(struct rcu_head *rcu)
139+
{
140+
struct oplock_info *opinfo = container_of(rcu, struct oplock_info, rcu);
141+
142+
if (!atomic_dec_and_test(&opinfo->refcount))
143+
return;
144+
145+
free_opinfo(opinfo);
146+
}
147+
138148
struct oplock_info *opinfo_get(struct ksmbd_file *fp)
139149
{
140150
struct oplock_info *opinfo;
@@ -176,10 +186,7 @@ void opinfo_put(struct oplock_info *opinfo)
176186
if (!opinfo)
177187
return;
178188

179-
if (!atomic_dec_and_test(&opinfo->refcount))
180-
return;
181-
182-
free_opinfo(opinfo);
189+
call_rcu(&opinfo->rcu, free_opinfo_rcu);
183190
}
184191

185192
static void opinfo_add(struct oplock_info *opinfo)

oplock.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@ struct oplock_info {
8080
struct lease *o_lease;
8181
struct list_head op_entry;
8282
struct list_head lease_entry;
83-
wait_queue_head_t oplock_q; /* Other server threads */
84-
wait_queue_head_t oplock_brk; /* oplock breaking wait */
83+
wait_queue_head_t oplock_q; /* Other server threads */
84+
wait_queue_head_t oplock_brk; /* oplock breaking wait */
85+
struct rcu_head rcu;
8586
};
8687

8788
struct lease_break_info {

0 commit comments

Comments
 (0)