Commit b29fb882 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'v7.0-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

 - Fix potential use after free errors

 - Fix refcount leak in smb2 open error path

 - Prevent allowing logging signing or encryption keys

* tag 'v7.0-rc3-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
  ksmbd: Don't log keys in SMB3 signing and encryption key generation
  smb: server: fix use-after-free in smb2_open()
  ksmbd: fix use-after-free in smb_lazy_parent_lease_break_close()
  ksmbd: fix use-after-free by using call_rcu() for oplock_info
  ksmbd: fix use-after-free in proc_show_files due to early rcu_read_unlock
  smb/server: Fix another refcount leak in smb2_open()
parents b4f0dd31 44133611
Loading
Loading
Loading
Loading
+2 −20
Original line number Diff line number Diff line
@@ -589,12 +589,8 @@ static int generate_smb3signingkey(struct ksmbd_session *sess,
	if (!(conn->dialect >= SMB30_PROT_ID && signing->binding))
		memcpy(chann->smb3signingkey, key, SMB3_SIGN_KEY_SIZE);

	ksmbd_debug(AUTH, "dumping generated AES signing keys\n");
	ksmbd_debug(AUTH, "generated SMB3 signing key\n");
	ksmbd_debug(AUTH, "Session Id    %llu\n", sess->id);
	ksmbd_debug(AUTH, "Session Key   %*ph\n",
		    SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
	ksmbd_debug(AUTH, "Signing Key   %*ph\n",
		    SMB3_SIGN_KEY_SIZE, key);
	return 0;
}

@@ -652,23 +648,9 @@ static void generate_smb3encryptionkey(struct ksmbd_conn *conn,
		     ptwin->decryption.context,
		     sess->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);

	ksmbd_debug(AUTH, "dumping generated AES encryption keys\n");
	ksmbd_debug(AUTH, "generated SMB3 encryption/decryption keys\n");
	ksmbd_debug(AUTH, "Cipher type   %d\n", conn->cipher_type);
	ksmbd_debug(AUTH, "Session Id    %llu\n", sess->id);
	ksmbd_debug(AUTH, "Session Key   %*ph\n",
		    SMB2_NTLMV2_SESSKEY_SIZE, sess->sess_key);
	if (conn->cipher_type == SMB2_ENCRYPTION_AES256_CCM ||
	    conn->cipher_type == SMB2_ENCRYPTION_AES256_GCM) {
		ksmbd_debug(AUTH, "ServerIn Key  %*ph\n",
			    SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3encryptionkey);
		ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
			    SMB3_GCM256_CRYPTKEY_SIZE, sess->smb3decryptionkey);
	} else {
		ksmbd_debug(AUTH, "ServerIn Key  %*ph\n",
			    SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3encryptionkey);
		ksmbd_debug(AUTH, "ServerOut Key %*ph\n",
			    SMB3_GCM128_CRYPTKEY_SIZE, sess->smb3decryptionkey);
	}
}

void ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
+25 −10
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@ static void free_lease(struct oplock_info *opinfo)
	kfree(lease);
}

static void free_opinfo(struct oplock_info *opinfo)
static void __free_opinfo(struct oplock_info *opinfo)
{
	if (opinfo->is_lease)
		free_lease(opinfo);
@@ -129,6 +129,18 @@ static void free_opinfo(struct oplock_info *opinfo)
	kfree(opinfo);
}

static void free_opinfo_rcu(struct rcu_head *rcu)
{
	struct oplock_info *opinfo = container_of(rcu, struct oplock_info, rcu);

	__free_opinfo(opinfo);
}

static void free_opinfo(struct oplock_info *opinfo)
{
	call_rcu(&opinfo->rcu, free_opinfo_rcu);
}

struct oplock_info *opinfo_get(struct ksmbd_file *fp)
{
	struct oplock_info *opinfo;
@@ -176,9 +188,9 @@ void opinfo_put(struct oplock_info *opinfo)
	free_opinfo(opinfo);
}

static void opinfo_add(struct oplock_info *opinfo)
static void opinfo_add(struct oplock_info *opinfo, struct ksmbd_file *fp)
{
	struct ksmbd_inode *ci = opinfo->o_fp->f_ci;
	struct ksmbd_inode *ci = fp->f_ci;

	down_write(&ci->m_lock);
	list_add(&opinfo->op_entry, &ci->m_op_list);
@@ -1123,10 +1135,12 @@ void smb_lazy_parent_lease_break_close(struct ksmbd_file *fp)

	rcu_read_lock();
	opinfo = rcu_dereference(fp->f_opinfo);
	rcu_read_unlock();

	if (!opinfo || !opinfo->is_lease || opinfo->o_lease->version != 2)
	if (!opinfo || !opinfo->is_lease || opinfo->o_lease->version != 2) {
		rcu_read_unlock();
		return;
	}
	rcu_read_unlock();

	p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent);
	if (!p_ci)
@@ -1277,20 +1291,21 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
	set_oplock_level(opinfo, req_op_level, lctx);

out:
	rcu_assign_pointer(fp->f_opinfo, opinfo);
	opinfo->o_fp = fp;

	opinfo_count_inc(fp);
	opinfo_add(opinfo);
	opinfo_add(opinfo, fp);

	if (opinfo->is_lease) {
		err = add_lease_global_list(opinfo);
		if (err)
			goto err_out;
	}

	rcu_assign_pointer(fp->f_opinfo, opinfo);
	opinfo->o_fp = fp;

	return 0;
err_out:
	free_opinfo(opinfo);
	__free_opinfo(opinfo);
	return err;
}

+3 −2
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ 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;
};

struct lease_break_info {
+4 −4
Original line number Diff line number Diff line
@@ -3012,13 +3012,14 @@ int smb2_open(struct ksmbd_work *work)
				goto err_out2;
			}

			fp = dh_info.fp;

			if (ksmbd_override_fsids(work)) {
				rc = -ENOMEM;
				ksmbd_put_durable_fd(dh_info.fp);
				goto err_out2;
			}

			fp = dh_info.fp;
			file_info = FILE_OPENED;

			rc = ksmbd_vfs_getattr(&fp->filp->f_path, &stat);
@@ -3616,10 +3617,8 @@ int smb2_open(struct ksmbd_work *work)

reconnected_fp:
	rsp->StructureSize = cpu_to_le16(89);
	rcu_read_lock();
	opinfo = rcu_dereference(fp->f_opinfo);
	opinfo = opinfo_get(fp);
	rsp->OplockLevel = opinfo != NULL ? opinfo->level : 0;
	rcu_read_unlock();
	rsp->Flags = 0;
	rsp->CreateAction = cpu_to_le32(file_info);
	rsp->CreationTime = cpu_to_le64(fp->create_time);
@@ -3660,6 +3659,7 @@ int smb2_open(struct ksmbd_work *work)
		next_ptr = &lease_ccontext->Next;
		next_off = conn->vals->create_lease_size;
	}
	opinfo_put(opinfo);

	if (maximal_access_ctxt) {
		struct create_context *mxac_ccontext;
+5 −5
Original line number Diff line number Diff line
@@ -87,11 +87,7 @@ static int proc_show_files(struct seq_file *m, void *v)

		rcu_read_lock();
		opinfo = rcu_dereference(fp->f_opinfo);
		rcu_read_unlock();

		if (!opinfo) {
			seq_printf(m, " %-15s", " ");
		} else {
		if (opinfo) {
			const struct ksmbd_const_name *const_names;
			int count;
			unsigned int level;
@@ -105,8 +101,12 @@ static int proc_show_files(struct seq_file *m, void *v)
				count = ARRAY_SIZE(ksmbd_oplock_const_names);
				level = opinfo->level;
			}
			rcu_read_unlock();
			ksmbd_proc_show_const_name(m, " %-15s",
						   const_names, count, level);
		} else {
			rcu_read_unlock();
			seq_printf(m, " %-15s", " ");
		}

		seq_printf(m, " %#010x %#010x %s\n",