summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/cifs/ksmbd.rst3
-rw-r--r--MAINTAINERS1
-rw-r--r--fs/ksmbd/Kconfig1
-rw-r--r--fs/ksmbd/smb2pdu.c50
-rw-r--r--fs/ksmbd/smb2pdu.h6
-rw-r--r--fs/ksmbd/smb_common.c53
-rw-r--r--fs/ksmbd/smb_common.h3
-rw-r--r--fs/ksmbd/smbacl.c82
-rw-r--r--fs/ksmbd/transport_rdma.c5
-rw-r--r--fs/ksmbd/vfs.c9
10 files changed, 128 insertions, 85 deletions
diff --git a/Documentation/filesystems/cifs/ksmbd.rst b/Documentation/filesystems/cifs/ksmbd.rst
index 1e111efecd45..a1326157d53f 100644
--- a/Documentation/filesystems/cifs/ksmbd.rst
+++ b/Documentation/filesystems/cifs/ksmbd.rst
@@ -84,7 +84,8 @@ SMB3 encryption(CCM, GCM) Supported. (CCM and GCM128 supported, GCM256 in
progress)
SMB direct(RDMA) Partially Supported. SMB3 Multi-channel is
required to connect to Windows client.
-SMB3 Multi-channel In Progress.
+SMB3 Multi-channel Partially Supported. Planned to implement
+ replay/retry mechanisms for future.
SMB3.1.1 POSIX extension Supported.
ACLs Partially Supported. only DACLs available, SACLs
(auditing) is planned for the future. For
diff --git a/MAINTAINERS b/MAINTAINERS
index 6691ac75fce5..85af3ce6a28e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9945,6 +9945,7 @@ M: Steve French <sfrench@samba.org>
M: Hyunchul Lee <hyc.lee@gmail.com>
L: linux-cifs@vger.kernel.org
S: Maintained
+T: git git://git.samba.org/ksmbd.git
F: fs/ksmbd/
KERNEL UNIT TESTING FRAMEWORK (KUnit)
diff --git a/fs/ksmbd/Kconfig b/fs/ksmbd/Kconfig
index e9a5ac01b6e0..b83cbd756ae5 100644
--- a/fs/ksmbd/Kconfig
+++ b/fs/ksmbd/Kconfig
@@ -19,7 +19,6 @@ config SMB_SERVER
select CRYPTO_GCM
select ASN1
select OID_REGISTRY
- select FS_POSIX_ACL
default n
help
Choose Y here if you want to allow SMB3 compliant clients
diff --git a/fs/ksmbd/smb2pdu.c b/fs/ksmbd/smb2pdu.c
index 636570ecfa31..0131997c2177 100644
--- a/fs/ksmbd/smb2pdu.c
+++ b/fs/ksmbd/smb2pdu.c
@@ -58,18 +58,18 @@ static void __wbuf(struct ksmbd_work *work, void **req, void **rsp)
*
* Return: 1 if valid session id, otherwise 0
*/
-static inline int check_session_id(struct ksmbd_conn *conn, u64 id)
+static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
{
struct ksmbd_session *sess;
if (id == 0 || id == -1)
- return 0;
+ return false;
sess = ksmbd_session_lookup_all(conn, id);
if (sess)
- return 1;
+ return true;
pr_err("Invalid user session id: %llu\n", id);
- return 0;
+ return false;
}
struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn)
@@ -85,10 +85,11 @@ struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn
}
/**
- * smb2_get_ksmbd_tcon() - get tree connection information for a tree id
+ * smb2_get_ksmbd_tcon() - get tree connection information using a tree id.
* @work: smb work
*
- * Return: matching tree connection on success, otherwise error
+ * Return: 0 if there is a tree connection matched or these are
+ * skipable commands, otherwise error
*/
int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
{
@@ -105,14 +106,14 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
if (xa_empty(&work->sess->tree_conns)) {
ksmbd_debug(SMB, "NO tree connected\n");
- return -1;
+ return -ENOENT;
}
tree_id = le32_to_cpu(req_hdr->Id.SyncId.TreeId);
work->tcon = ksmbd_tree_conn_lookup(work->sess, tree_id);
if (!work->tcon) {
pr_err("Invalid tid %d\n", tree_id);
- return -1;
+ return -EINVAL;
}
return 1;
@@ -145,45 +146,45 @@ void smb2_set_err_rsp(struct ksmbd_work *work)
* is_smb2_neg_cmd() - is it smb2 negotiation command
* @work: smb work containing smb header
*
- * Return: 1 if smb2 negotiation command, otherwise 0
+ * Return: true if smb2 negotiation command, otherwise false
*/
-int is_smb2_neg_cmd(struct ksmbd_work *work)
+bool is_smb2_neg_cmd(struct ksmbd_work *work)
{
struct smb2_hdr *hdr = work->request_buf;
/* is it SMB2 header ? */
if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
- return 0;
+ return false;
/* make sure it is request not response message */
if (hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR)
- return 0;
+ return false;
if (hdr->Command != SMB2_NEGOTIATE)
- return 0;
+ return false;
- return 1;
+ return true;
}
/**
* is_smb2_rsp() - is it smb2 response
* @work: smb work containing smb response buffer
*
- * Return: 1 if smb2 response, otherwise 0
+ * Return: true if smb2 response, otherwise false
*/
-int is_smb2_rsp(struct ksmbd_work *work)
+bool is_smb2_rsp(struct ksmbd_work *work)
{
struct smb2_hdr *hdr = work->response_buf;
/* is it SMB2 header ? */
if (hdr->ProtocolId != SMB2_PROTO_NUMBER)
- return 0;
+ return false;
/* make sure it is response not request message */
if (!(hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR))
- return 0;
+ return false;
- return 1;
+ return true;
}
/**
@@ -2385,11 +2386,14 @@ static void ksmbd_acls_fattr(struct smb_fattr *fattr, struct inode *inode)
fattr->cf_uid = inode->i_uid;
fattr->cf_gid = inode->i_gid;
fattr->cf_mode = inode->i_mode;
+ fattr->cf_acls = NULL;
fattr->cf_dacls = NULL;
- fattr->cf_acls = get_acl(inode, ACL_TYPE_ACCESS);
- if (S_ISDIR(inode->i_mode))
- fattr->cf_dacls = get_acl(inode, ACL_TYPE_DEFAULT);
+ if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
+ fattr->cf_acls = get_acl(inode, ACL_TYPE_ACCESS);
+ if (S_ISDIR(inode->i_mode))
+ fattr->cf_dacls = get_acl(inode, ACL_TYPE_DEFAULT);
+ }
}
/**
@@ -8291,7 +8295,7 @@ int smb3_encrypt_resp(struct ksmbd_work *work)
return rc;
}
-int smb3_is_transform_hdr(void *buf)
+bool smb3_is_transform_hdr(void *buf)
{
struct smb2_transform_hdr *trhdr = buf;
diff --git a/fs/ksmbd/smb2pdu.h b/fs/ksmbd/smb2pdu.h
index 89019f67234c..bcec845b03f3 100644
--- a/fs/ksmbd/smb2pdu.h
+++ b/fs/ksmbd/smb2pdu.h
@@ -1638,8 +1638,8 @@ void init_smb2_max_read_size(unsigned int sz);
void init_smb2_max_write_size(unsigned int sz);
void init_smb2_max_trans_size(unsigned int sz);
-int is_smb2_neg_cmd(struct ksmbd_work *work);
-int is_smb2_rsp(struct ksmbd_work *work);
+bool is_smb2_neg_cmd(struct ksmbd_work *work);
+bool is_smb2_rsp(struct ksmbd_work *work);
u16 get_smb2_cmd_val(struct ksmbd_work *work);
void set_smb2_rsp_status(struct ksmbd_work *work, __le32 err);
@@ -1664,7 +1664,7 @@ void smb2_send_interim_resp(struct ksmbd_work *work, __le32 status);
struct channel *lookup_chann_list(struct ksmbd_session *sess,
struct ksmbd_conn *conn);
void smb3_preauth_hash_rsp(struct ksmbd_work *work);
-int smb3_is_transform_hdr(void *buf);
+bool smb3_is_transform_hdr(void *buf);
int smb3_decrypt_req(struct ksmbd_work *work);
int smb3_encrypt_resp(struct ksmbd_work *work);
bool smb3_11_final_sess_setup_resp(struct ksmbd_work *work);
diff --git a/fs/ksmbd/smb_common.c b/fs/ksmbd/smb_common.c
index 24c6bb476f6e..b108b918ec84 100644
--- a/fs/ksmbd/smb_common.c
+++ b/fs/ksmbd/smb_common.c
@@ -30,7 +30,7 @@ struct smb_protocol {
__u16 prot_id;
};
-static struct smb_protocol smb_protos[] = {
+static struct smb_protocol smb1_protos[] = {
{
SMB21_PROT,
"\2SMB 2.1",
@@ -43,6 +43,15 @@ static struct smb_protocol smb_protos[] = {
"SMB2_22",
SMB2X_PROT_ID
},
+};
+
+static struct smb_protocol smb2_protos[] = {
+ {
+ SMB21_PROT,
+ "\2SMB 2.1",
+ "SMB2_10",
+ SMB21_PROT_ID
+ },
{
SMB30_PROT,
"\2SMB 3.0",
@@ -90,14 +99,24 @@ inline int ksmbd_max_protocol(void)
int ksmbd_lookup_protocol_idx(char *str)
{
- int offt = ARRAY_SIZE(smb_protos) - 1;
+ int offt = ARRAY_SIZE(smb1_protos) - 1;
int len = strlen(str);
while (offt >= 0) {
- if (!strncmp(str, smb_protos[offt].prot, len)) {
+ if (!strncmp(str, smb1_protos[offt].prot, len)) {
+ ksmbd_debug(SMB, "selected %s dialect idx = %d\n",
+ smb1_protos[offt].prot, offt);
+ return smb1_protos[offt].index;
+ }
+ offt--;
+ }
+
+ offt = ARRAY_SIZE(smb2_protos) - 1;
+ while (offt >= 0) {
+ if (!strncmp(str, smb2_protos[offt].prot, len)) {
ksmbd_debug(SMB, "selected %s dialect idx = %d\n",
- smb_protos[offt].prot, offt);
- return smb_protos[offt].index;
+ smb2_protos[offt].prot, offt);
+ return smb2_protos[offt].index;
}
offt--;
}
@@ -169,7 +188,7 @@ static int ksmbd_lookup_dialect_by_name(char *cli_dialects, __le16 byte_count)
int i, seq_num, bcount, next;
char *dialect;
- for (i = ARRAY_SIZE(smb_protos) - 1; i >= 0; i--) {
+ for (i = ARRAY_SIZE(smb1_protos) - 1; i >= 0; i--) {
seq_num = 0;
next = 0;
dialect = cli_dialects;
@@ -178,14 +197,14 @@ static int ksmbd_lookup_dialect_by_name(char *cli_dialects, __le16 byte_count)
dialect = next_dialect(dialect, &next);
ksmbd_debug(SMB, "client requested dialect %s\n",
dialect);
- if (!strcmp(dialect, smb_protos[i].name)) {
- if (supported_protocol(smb_protos[i].index)) {
+ if (!strcmp(dialect, smb1_protos[i].name)) {
+ if (supported_protocol(smb1_protos[i].index)) {
ksmbd_debug(SMB,
"selected %s dialect\n",
- smb_protos[i].name);
- if (smb_protos[i].index == SMB1_PROT)
+ smb1_protos[i].name);
+ if (smb1_protos[i].index == SMB1_PROT)
return seq_num;
- return smb_protos[i].prot_id;
+ return smb1_protos[i].prot_id;
}
}
seq_num++;
@@ -201,19 +220,19 @@ int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count)
int i;
int count;
- for (i = ARRAY_SIZE(smb_protos) - 1; i >= 0; i--) {
+ for (i = ARRAY_SIZE(smb2_protos) - 1; i >= 0; i--) {
count = le16_to_cpu(dialects_count);
while (--count >= 0) {
ksmbd_debug(SMB, "client requested dialect 0x%x\n",
le16_to_cpu(cli_dialects[count]));
if (le16_to_cpu(cli_dialects[count]) !=
- smb_protos[i].prot_id)
+ smb2_protos[i].prot_id)
continue;
- if (supported_protocol(smb_protos[i].index)) {
+ if (supported_protocol(smb2_protos[i].index)) {
ksmbd_debug(SMB, "selected %s dialect\n",
- smb_protos[i].name);
- return smb_protos[i].prot_id;
+ smb2_protos[i].name);
+ return smb2_protos[i].prot_id;
}
}
}
@@ -221,7 +240,7 @@ int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count)
return BAD_PROT_ID;
}
-int ksmbd_negotiate_smb_dialect(void *buf)
+static int ksmbd_negotiate_smb_dialect(void *buf)
{
__le32 proto;
diff --git a/fs/ksmbd/smb_common.h b/fs/ksmbd/smb_common.h
index b8c350725905..eb667d85558e 100644
--- a/fs/ksmbd/smb_common.h
+++ b/fs/ksmbd/smb_common.h
@@ -473,7 +473,7 @@ struct smb_version_ops {
void (*set_sign_rsp)(struct ksmbd_work *work);
int (*generate_signingkey)(struct ksmbd_session *sess, struct ksmbd_conn *conn);
int (*generate_encryptionkey)(struct ksmbd_session *sess);
- int (*is_transform_hdr)(void *buf);
+ bool (*is_transform_hdr)(void *buf);
int (*decrypt_req)(struct ksmbd_work *work);
int (*encrypt_resp)(struct ksmbd_work *work);
};
@@ -498,7 +498,6 @@ bool ksmbd_smb_request(struct ksmbd_conn *conn);
int ksmbd_lookup_dialect_by_id(__le16 *cli_dialects, __le16 dialects_count);
-int ksmbd_negotiate_smb_dialect(void *buf);
int ksmbd_init_smb_server(struct ksmbd_work *work);
bool ksmbd_pdu_size_has_room(unsigned int pdu);
diff --git a/fs/ksmbd/smbacl.c b/fs/ksmbd/smbacl.c
index fa99d950a6f2..20455d810523 100644
--- a/fs/ksmbd/smbacl.c
+++ b/fs/ksmbd/smbacl.c
@@ -533,22 +533,29 @@ static void parse_dacl(struct user_namespace *user_ns,
if (acl_state.users->n || acl_state.groups->n) {
acl_state.mask.allow = 0x07;
- fattr->cf_acls = posix_acl_alloc(acl_state.users->n +
- acl_state.groups->n + 4, GFP_KERNEL);
- if (fattr->cf_acls) {
- cf_pace = fattr->cf_acls->a_entries;
- posix_state_to_acl(&acl_state, cf_pace);
+
+ if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
+ fattr->cf_acls =
+ posix_acl_alloc(acl_state.users->n +
+ acl_state.groups->n + 4, GFP_KERNEL);
+ if (fattr->cf_acls) {
+ cf_pace = fattr->cf_acls->a_entries;
+ posix_state_to_acl(&acl_state, cf_pace);
+ }
}
}
if (default_acl_state.users->n || default_acl_state.groups->n) {
default_acl_state.mask.allow = 0x07;
- fattr->cf_dacls =
- posix_acl_alloc(default_acl_state.users->n +
- default_acl_state.groups->n + 4, GFP_KERNEL);
- if (fattr->cf_dacls) {
- cf_pdace = fattr->cf_dacls->a_entries;
- posix_state_to_acl(&default_acl_state, cf_pdace);
+
+ if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
+ fattr->cf_dacls =
+ posix_acl_alloc(default_acl_state.users->n +
+ default_acl_state.groups->n + 4, GFP_KERNEL);
+ if (fattr->cf_dacls) {
+ cf_pdace = fattr->cf_dacls->a_entries;
+ posix_state_to_acl(&default_acl_state, cf_pdace);
+ }
}
}
free_acl_state(&acl_state);
@@ -724,7 +731,6 @@ static void set_mode_dacl(struct user_namespace *user_ns,
ace_size = fill_ace_for_sid(pace, sid, ACCESS_ALLOWED, 0,
fattr->cf_mode, 0700);
pace->sid.sub_auth[pace->sid.num_subauth++] = cpu_to_le32(uid);
- pace->access_req |= FILE_DELETE_LE | FILE_DELETE_CHILD_LE;
pace->size = cpu_to_le16(ace_size + 4);
size += le16_to_cpu(pace->size);
pace = (struct smb_ace *)((char *)pndace + size);
@@ -745,7 +751,6 @@ static void set_mode_dacl(struct user_namespace *user_ns,
/* creator owner */
size += fill_ace_for_sid(pace, &creator_owner, ACCESS_ALLOWED,
0x0b, fattr->cf_mode, 0700);
- pace->access_req |= FILE_DELETE_LE | FILE_DELETE_CHILD_LE;
pace = (struct smb_ace *)((char *)pndace + size);
/* creator group */
@@ -1221,31 +1226,36 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, struct path *path,
granted = GENERIC_ALL_FLAGS;
}
- posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
- if (posix_acls && !found) {
- unsigned int id = -1;
-
- pa_entry = posix_acls->a_entries;
- for (i = 0; i < posix_acls->a_count; i++, pa_entry++) {
- if (pa_entry->e_tag == ACL_USER)
- id = from_kuid(user_ns,
- pa_entry->e_uid);
- else if (pa_entry->e_tag == ACL_GROUP)
- id = from_kgid(user_ns,
- pa_entry->e_gid);
- else
- continue;
-
- if (id == uid) {
- mode_to_access_flags(pa_entry->e_perm, 0777, &access_bits);
- if (!access_bits)
- access_bits = SET_MINIMUM_RIGHTS;
- goto check_access_bits;
+ if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
+ posix_acls = get_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
+ if (posix_acls && !found) {
+ unsigned int id = -1;
+
+ pa_entry = posix_acls->a_entries;
+ for (i = 0; i < posix_acls->a_count; i++, pa_entry++) {
+ if (pa_entry->e_tag == ACL_USER)
+ id = from_kuid(user_ns,
+ pa_entry->e_uid);
+ else if (pa_entry->e_tag == ACL_GROUP)
+ id = from_kgid(user_ns,
+ pa_entry->e_gid);
+ else
+ continue;
+
+ if (id == uid) {
+ mode_to_access_flags(pa_entry->e_perm,
+ 0777,
+ &access_bits);
+ if (!access_bits)
+ access_bits =
+ SET_MINIMUM_RIGHTS;
+ goto check_access_bits;
+ }
}
}
+ if (posix_acls)
+ posix_acl_release(posix_acls);
}
- if (posix_acls)
- posix_acl_release(posix_acls);
if (!found) {
if (others_ace) {
@@ -1308,7 +1318,7 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
ksmbd_vfs_remove_acl_xattrs(user_ns, path->dentry);
/* Update posix acls */
- if (fattr.cf_dacls) {
+ if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) {
rc = set_posix_acl(user_ns, inode,
ACL_TYPE_ACCESS, fattr.cf_acls);
if (S_ISDIR(inode->i_mode) && fattr.cf_dacls)
diff --git a/fs/ksmbd/transport_rdma.c b/fs/ksmbd/transport_rdma.c
index f2ae6bae83f1..58f530056ac0 100644
--- a/fs/ksmbd/transport_rdma.c
+++ b/fs/ksmbd/transport_rdma.c
@@ -329,7 +329,8 @@ static void smb_direct_disconnect_rdma_work(struct work_struct *work)
static void
smb_direct_disconnect_rdma_connection(struct smb_direct_transport *t)
{
- queue_work(smb_direct_wq, &t->disconnect_work);
+ if (t->status == SMB_DIRECT_CS_CONNECTED)
+ queue_work(smb_direct_wq, &t->disconnect_work);
}
static void smb_direct_send_immediate_work(struct work_struct *work)
@@ -1415,7 +1416,7 @@ static void smb_direct_disconnect(struct ksmbd_transport *t)
ksmbd_debug(RDMA, "Disconnecting cm_id=%p\n", st->cm_id);
- smb_direct_disconnect_rdma_connection(st);
+ smb_direct_disconnect_rdma_work(&st->disconnect_work);
wait_event_interruptible(st->wait_status,
st->status == SMB_DIRECT_CS_DISCONNECTED);
free_transport(st);
diff --git a/fs/ksmbd/vfs.c b/fs/ksmbd/vfs.c
index 612c52d7a01b..aee28ee6b19c 100644
--- a/fs/ksmbd/vfs.c
+++ b/fs/ksmbd/vfs.c
@@ -1365,6 +1365,9 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct user_namespac
struct xattr_acl_entry *xa_entry;
int i;
+ if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
+ return NULL;
+
posix_acls = get_acl(inode, acl_type);
if (!posix_acls)
return NULL;
@@ -1811,6 +1814,9 @@ int ksmbd_vfs_set_init_posix_acl(struct user_namespace *user_ns,
struct posix_acl *acls;
int rc;
+ if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
+ return -EOPNOTSUPP;
+
ksmbd_debug(SMB, "Set posix acls\n");
rc = init_acl_state(&acl_state, 1);
if (rc)
@@ -1858,6 +1864,9 @@ int ksmbd_vfs_inherit_posix_acl(struct user_namespace *user_ns,
struct posix_acl_entry *pace;
int rc, i;
+ if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
+ return -EOPNOTSUPP;
+
acls = get_acl(parent_inode, ACL_TYPE_DEFAULT);
if (!acls)
return -ENOENT;