Skip to content

Commit ea174a9

Browse files
namjaejeonsmfrench
authored andcommitted
ksmbd: destroy expired sessions
client can indefinitely send smb2 session setup requests with the SessionId set to 0, thus indefinitely spawning new sessions, and causing indefinite memory usage. This patch limit to the number of sessions using expired timeout and session state. Cc: stable@vger.kernel.org Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-20478 Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
1 parent f5c779b commit ea174a9

4 files changed

Lines changed: 41 additions & 31 deletions

File tree

fs/ksmbd/mgmt/user_session.c

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -165,70 +165,73 @@ static struct ksmbd_session *__session_lookup(unsigned long long id)
165165
struct ksmbd_session *sess;
166166

167167
hash_for_each_possible(sessions_table, sess, hlist, id) {
168-
if (id == sess->id)
168+
if (id == sess->id) {
169+
sess->last_active = jiffies;
169170
return sess;
171+
}
170172
}
171173
return NULL;
172174
}
173175

176+
static void ksmbd_expire_session(struct ksmbd_conn *conn)
177+
{
178+
unsigned long id;
179+
struct ksmbd_session *sess;
180+
181+
xa_for_each(&conn->sessions, id, sess) {
182+
if (sess->state != SMB2_SESSION_VALID ||
183+
time_after(jiffies,
184+
sess->last_active + SMB2_SESSION_TIMEOUT)) {
185+
xa_erase(&conn->sessions, sess->id);
186+
ksmbd_session_destroy(sess);
187+
continue;
188+
}
189+
}
190+
}
191+
174192
int ksmbd_session_register(struct ksmbd_conn *conn,
175193
struct ksmbd_session *sess)
176194
{
177195
sess->dialect = conn->dialect;
178196
memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE);
197+
ksmbd_expire_session(conn);
179198
return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
180199
}
181200

182-
static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
201+
static void ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
183202
{
184203
struct channel *chann;
185204

186205
chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
187206
if (!chann)
188-
return -ENOENT;
207+
return;
189208

190209
kfree(chann);
191-
192-
return 0;
193210
}
194211

195212
void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
196213
{
197214
struct ksmbd_session *sess;
215+
unsigned long id;
198216

199-
if (conn->binding) {
200-
int bkt;
201-
202-
down_write(&sessions_table_lock);
203-
hash_for_each(sessions_table, bkt, sess, hlist) {
204-
if (!ksmbd_chann_del(conn, sess)) {
205-
up_write(&sessions_table_lock);
206-
goto sess_destroy;
207-
}
217+
xa_for_each(&conn->sessions, id, sess) {
218+
ksmbd_chann_del(conn, sess);
219+
if (xa_empty(&sess->ksmbd_chann_list)) {
220+
xa_erase(&conn->sessions, sess->id);
221+
ksmbd_session_destroy(sess);
208222
}
209-
up_write(&sessions_table_lock);
210-
} else {
211-
unsigned long id;
212-
213-
xa_for_each(&conn->sessions, id, sess) {
214-
if (!ksmbd_chann_del(conn, sess))
215-
goto sess_destroy;
216-
}
217-
}
218-
219-
return;
220-
221-
sess_destroy:
222-
if (xa_empty(&sess->ksmbd_chann_list)) {
223-
xa_erase(&conn->sessions, sess->id);
224-
ksmbd_session_destroy(sess);
225223
}
226224
}
227225

228226
struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
229227
unsigned long long id)
230228
{
231-
return xa_load(&conn->sessions, id);
229+
struct ksmbd_session *sess;
230+
231+
sess = xa_load(&conn->sessions, id);
232+
if (sess)
233+
sess->last_active = jiffies;
234+
return sess;
232235
}
233236

234237
struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
@@ -237,6 +240,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
237240

238241
down_read(&sessions_table_lock);
239242
sess = __session_lookup(id);
243+
if (sess)
244+
sess->last_active = jiffies;
240245
up_read(&sessions_table_lock);
241246

242247
return sess;
@@ -315,6 +320,7 @@ static struct ksmbd_session *__session_create(int protocol)
315320
if (ksmbd_init_file_table(&sess->file_table))
316321
goto error;
317322

323+
sess->last_active = jiffies;
318324
sess->state = SMB2_SESSION_IN_PROGRESS;
319325
set_session_flag(sess, protocol);
320326
xa_init(&sess->tree_conns);

fs/ksmbd/mgmt/user_session.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ struct ksmbd_session {
5959
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
6060

6161
struct ksmbd_file_table file_table;
62+
unsigned long last_active;
6263
};
6364

6465
static inline int test_session_flag(struct ksmbd_session *sess, int bit)

fs/ksmbd/smb2pdu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1838,6 +1838,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
18381838
if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
18391839
try_delay = true;
18401840

1841+
sess->last_active = jiffies;
18411842
sess->state = SMB2_SESSION_EXPIRED;
18421843
if (try_delay)
18431844
ssleep(5);

fs/ksmbd/smb2pdu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ struct preauth_integrity_info {
6161
#define SMB2_SESSION_IN_PROGRESS BIT(0)
6262
#define SMB2_SESSION_VALID BIT(1)
6363

64+
#define SMB2_SESSION_TIMEOUT (10 * HZ)
65+
6466
struct create_durable_req_v2 {
6567
struct create_context ccontext;
6668
__u8 Name[8];

0 commit comments

Comments
 (0)