Skip to content

Commit 5a7ee91

Browse files
namjaejeonSteve French
authored andcommitted
ksmbd: fix race condition with fp
fp can used in each command. If smb2_close command is coming at the same time, UAF issue can happen by race condition. Time + Thread A | Thread B1 B2 .... B5 smb2_open | smb2_close | __open_id | insert fp to file_table | | | atomic_dec_and_test(&fp->refcount) | if fp->refcount == 0, free fp by kfree. // UAF! | use fp | + This patch add f_state not to use freed fp is used and not to free fp in use. Reported-by: luosili <[email protected]> Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 53ff5cf commit 5a7ee91

File tree

3 files changed

+32
-4
lines changed

3 files changed

+32
-4
lines changed

fs/smb/server/smb2pdu.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3370,8 +3370,10 @@ int smb2_open(struct ksmbd_work *work)
33703370
}
33713371
ksmbd_revert_fsids(work);
33723372
err_out1:
3373-
if (!rc)
3373+
if (!rc) {
3374+
ksmbd_update_fstate(&work->sess->file_table, fp, FP_INITED);
33743375
rc = ksmbd_iov_pin_rsp(work, (void *)rsp, iov_len);
3376+
}
33753377
if (rc) {
33763378
if (rc == -EINVAL)
33773379
rsp->hdr.Status = STATUS_INVALID_PARAMETER;

fs/smb/server/vfs_cache.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ static void __ksmbd_close_fd(struct ksmbd_file_table *ft, struct ksmbd_file *fp)
333333

334334
static struct ksmbd_file *ksmbd_fp_get(struct ksmbd_file *fp)
335335
{
336+
if (fp->f_state != FP_INITED)
337+
return NULL;
338+
336339
if (!atomic_inc_not_zero(&fp->refcount))
337340
return NULL;
338341
return fp;
@@ -382,15 +385,20 @@ int ksmbd_close_fd(struct ksmbd_work *work, u64 id)
382385
return 0;
383386

384387
ft = &work->sess->file_table;
385-
read_lock(&ft->lock);
388+
write_lock(&ft->lock);
386389
fp = idr_find(ft->idr, id);
387390
if (fp) {
388391
set_close_state_blocked_works(fp);
389392

390-
if (!atomic_dec_and_test(&fp->refcount))
393+
if (fp->f_state != FP_INITED)
391394
fp = NULL;
395+
else {
396+
fp->f_state = FP_CLOSED;
397+
if (!atomic_dec_and_test(&fp->refcount))
398+
fp = NULL;
399+
}
392400
}
393-
read_unlock(&ft->lock);
401+
write_unlock(&ft->lock);
394402

395403
if (!fp)
396404
return -EINVAL;
@@ -570,6 +578,7 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
570578
fp->tcon = work->tcon;
571579
fp->volatile_id = KSMBD_NO_FID;
572580
fp->persistent_id = KSMBD_NO_FID;
581+
fp->f_state = FP_NEW;
573582
fp->f_ci = ksmbd_inode_get(fp);
574583

575584
if (!fp->f_ci) {
@@ -591,6 +600,14 @@ struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp)
591600
return ERR_PTR(ret);
592601
}
593602

603+
void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
604+
unsigned int state)
605+
{
606+
write_lock(&ft->lock);
607+
fp->f_state = state;
608+
write_unlock(&ft->lock);
609+
}
610+
594611
static int
595612
__close_file_table_ids(struct ksmbd_file_table *ft,
596613
struct ksmbd_tree_connect *tcon,

fs/smb/server/vfs_cache.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ struct ksmbd_inode {
6060
__le32 m_fattr;
6161
};
6262

63+
enum {
64+
FP_NEW = 0,
65+
FP_INITED,
66+
FP_CLOSED
67+
};
68+
6369
struct ksmbd_file {
6470
struct file *filp;
6571
u64 persistent_id;
@@ -98,6 +104,7 @@ struct ksmbd_file {
98104
/* if ls is happening on directory, below is valid*/
99105
struct ksmbd_readdir_data readdir_data;
100106
int dot_dotdot[2];
107+
unsigned int f_state;
101108
};
102109

103110
static inline void set_ctx_actor(struct dir_context *ctx,
@@ -142,6 +149,8 @@ int ksmbd_close_inode_fds(struct ksmbd_work *work, struct inode *inode);
142149
int ksmbd_init_global_file_table(void);
143150
void ksmbd_free_global_file_table(void);
144151
void ksmbd_set_fd_limit(unsigned long limit);
152+
void ksmbd_update_fstate(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
153+
unsigned int state);
145154

146155
/*
147156
* INODE hash

0 commit comments

Comments
 (0)