Commit 7e74f756 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v6.15-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix integer overflow in server disconnect deadtime calculation

 - Three fixes for potential use after frees: one for oplocks, and one
   for leases and one for kerberos authentication

 - Fix to prevent attempted write to directory

 - Fix locking warning for durable scavenger thread

* tag 'v6.15-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: Prevent integer overflow in calculation of deadtime
  ksmbd: fix the warning from __kernel_write_iter
  ksmbd: fix use-after-free in smb_break_all_levII_oplock()
  ksmbd: fix use-after-free in __smb2_lease_break_noti()
  ksmbd: fix WARNING "do not call blocking ops when !TASK_RUNNING"
  ksmbd: Fix dangling pointer in krb_authenticate
parents f7c2ca25 a93ff742
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -39,9 +39,11 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
	xa_destroy(&conn->sessions);
	kvfree(conn->request_buf);
	kfree(conn->preauth_info);
	if (atomic_dec_and_test(&conn->refcnt))
	if (atomic_dec_and_test(&conn->refcnt)) {
		ksmbd_free_transport(conn->transport);
		kfree(conn);
	}
}

/**
 * ksmbd_conn_alloc() - initialize a new connection instance
+9 −20
Original line number Diff line number Diff line
@@ -129,14 +129,6 @@ static void free_opinfo(struct oplock_info *opinfo)
	kfree(opinfo);
}

static inline void opinfo_free_rcu(struct rcu_head *rcu_head)
{
	struct oplock_info *opinfo;

	opinfo = container_of(rcu_head, struct oplock_info, rcu_head);
	free_opinfo(opinfo);
}

struct oplock_info *opinfo_get(struct ksmbd_file *fp)
{
	struct oplock_info *opinfo;
@@ -157,8 +149,8 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
	if (list_empty(&ci->m_op_list))
		return NULL;

	rcu_read_lock();
	opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info,
	down_read(&ci->m_lock);
	opinfo = list_first_entry(&ci->m_op_list, struct oplock_info,
					op_entry);
	if (opinfo) {
		if (opinfo->conn == NULL ||
@@ -171,8 +163,7 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
			}
		}
	}

	rcu_read_unlock();
	up_read(&ci->m_lock);

	return opinfo;
}
@@ -185,7 +176,7 @@ void opinfo_put(struct oplock_info *opinfo)
	if (!atomic_dec_and_test(&opinfo->refcount))
		return;

	call_rcu(&opinfo->rcu_head, opinfo_free_rcu);
	free_opinfo(opinfo);
}

static void opinfo_add(struct oplock_info *opinfo)
@@ -193,7 +184,7 @@ static void opinfo_add(struct oplock_info *opinfo)
	struct ksmbd_inode *ci = opinfo->o_fp->f_ci;

	down_write(&ci->m_lock);
	list_add_rcu(&opinfo->op_entry, &ci->m_op_list);
	list_add(&opinfo->op_entry, &ci->m_op_list);
	up_write(&ci->m_lock);
}

@@ -207,7 +198,7 @@ static void opinfo_del(struct oplock_info *opinfo)
		write_unlock(&lease_list_lock);
	}
	down_write(&ci->m_lock);
	list_del_rcu(&opinfo->op_entry);
	list_del(&opinfo->op_entry);
	up_write(&ci->m_lock);
}

@@ -1347,8 +1338,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
	ci = fp->f_ci;
	op = opinfo_get(fp);

	rcu_read_lock();
	list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) {
	down_read(&ci->m_lock);
	list_for_each_entry(brk_op, &ci->m_op_list, op_entry) {
		if (brk_op->conn == NULL)
			continue;

@@ -1358,7 +1349,6 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
		if (ksmbd_conn_releasing(brk_op->conn))
			continue;

		rcu_read_unlock();
		if (brk_op->is_lease && (brk_op->o_lease->state &
		    (~(SMB2_LEASE_READ_CACHING_LE |
				SMB2_LEASE_HANDLE_CACHING_LE)))) {
@@ -1388,9 +1378,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
		oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE, NULL);
next:
		opinfo_put(brk_op);
		rcu_read_lock();
	}
	rcu_read_unlock();
	up_read(&ci->m_lock);

	if (op)
		opinfo_put(op);
+0 −1
Original line number Diff line number Diff line
@@ -71,7 +71,6 @@ struct oplock_info {
	struct list_head        lease_entry;
	wait_queue_head_t oplock_q; /* Other server threads */
	wait_queue_head_t oplock_brk; /* oplock breaking wait */
	struct rcu_head		rcu_head;
};

struct lease_break_info {
+3 −1
Original line number Diff line number Diff line
@@ -1602,8 +1602,10 @@ static int krb5_authenticate(struct ksmbd_work *work,
	if (prev_sess_id && prev_sess_id != sess->id)
		destroy_previous_session(conn, sess->user, prev_sess_id);

	if (sess->state == SMB2_SESSION_VALID)
	if (sess->state == SMB2_SESSION_VALID) {
		ksmbd_free_user(sess->user);
		sess->user = NULL;
	}

	retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
					 out_blob, &out_len);
+6 −1
Original line number Diff line number Diff line
@@ -310,7 +310,11 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
	server_conf.signing = req->signing;
	server_conf.tcp_port = req->tcp_port;
	server_conf.ipc_timeout = req->ipc_timeout * HZ;
	server_conf.deadtime = req->deadtime * SMB_ECHO_INTERVAL;
	if (check_mul_overflow(req->deadtime, SMB_ECHO_INTERVAL,
					&server_conf.deadtime)) {
		ret = -EINVAL;
		goto out;
	}
	server_conf.share_fake_fscaps = req->share_fake_fscaps;
	ksmbd_init_domain(req->sub_auth);

@@ -337,6 +341,7 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req)
	server_conf.bind_interfaces_only = req->bind_interfaces_only;
	ret |= ksmbd_tcp_set_interfaces(KSMBD_STARTUP_CONFIG_INTERFACES(req),
					req->ifc_list_sz);
out:
	if (ret) {
		pr_err("Server configuration error: %s %s %s\n",
		       req->netbios_name, req->server_string,
Loading