From c69e41c6fb65c963b7ed743a843b79d1689e1140 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 25 Sep 2024 23:34:39 +0900 Subject: [PATCH] ksmbd: add support for supplementary groups Signed-off-by: Namjae Jeon --- ksmbd_netlink.h | 4 ++++ mgmt/user_config.c | 12 ++++++++++++ mgmt/user_config.h | 2 ++ smb_common.c | 21 ++++++++++++++++++--- transport_ipc.c | 15 ++++++++++++--- 5 files changed, 48 insertions(+), 6 deletions(-) diff --git a/ksmbd_netlink.h b/ksmbd_netlink.h index d9de08d4b..6da2eede4 100644 --- a/ksmbd_netlink.h +++ b/ksmbd_netlink.h @@ -131,6 +131,8 @@ struct ksmbd_login_request { __u32 reserved[16]; /* Reserved room */ }; +#define KSMBD_MAX_NGROUPS 128 + /* * IPC user login response. */ @@ -143,6 +145,8 @@ struct ksmbd_login_response { __u16 hash_sz; /* hash size */ __s8 hash[KSMBD_REQ_MAX_HASH_SZ]; /* password hash */ __u32 reserved[16]; /* Reserved room */ + __u32 ngroups; /* supplementary group count */ + __u32 sgid[KSMBD_MAX_NGROUPS]; /* supplementary group id */ }; /* diff --git a/mgmt/user_config.c b/mgmt/user_config.c index 279d00fef..3f0bb946a 100644 --- a/mgmt/user_config.c +++ b/mgmt/user_config.c @@ -31,6 +31,12 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp) { struct ksmbd_user *user = NULL; + if (resp->ngroups > KSMBD_MAX_NGROUPS) { + pr_err("ngroups(%u) from login response exceed NGROUPS_MAX\n", + resp->ngroups); + return NULL; + } + user = kmalloc(sizeof(struct ksmbd_user), GFP_KERNEL); if (!user) return NULL; @@ -50,6 +56,12 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp) kfree(user); user = NULL; } + + user->sgid = kmemdup(resp->sgid, resp->ngroups * sizeof(__u32), + GFP_KERNEL); + if (user->sgid) + user->ngroups = resp->ngroups; + return user; } diff --git a/mgmt/user_config.h b/mgmt/user_config.h index e068a19fd..be7ce50e0 100644 --- a/mgmt/user_config.h +++ b/mgmt/user_config.h @@ -18,6 +18,8 @@ struct ksmbd_user { size_t passkey_sz; char *passkey; + unsigned int ngroups; + unsigned int *sgid; }; static inline bool user_guest(struct ksmbd_user *user) diff --git a/smb_common.c b/smb_common.c index 613c2f8da..3f6beedbf 100644 --- a/smb_common.c +++ b/smb_common.c @@ -781,13 +781,15 @@ int __ksmbd_override_fsids(struct ksmbd_work *work, struct ksmbd_share_config *share) { struct ksmbd_session *sess = work->sess; + struct ksmbd_user *user = sess->user; struct cred *cred; struct group_info *gi; unsigned int uid; unsigned int gid; + int i; - uid = user_uid(sess->user); - gid = user_gid(sess->user); + uid = user_uid(user); + gid = user_gid(user); if (share->force_uid != KSMBD_SHARE_INVALID_UID) uid = share->force_uid; if (share->force_gid != KSMBD_SHARE_INVALID_GID) @@ -800,11 +802,24 @@ int __ksmbd_override_fsids(struct ksmbd_work *work, cred->fsuid = make_kuid(&init_user_ns, uid); cred->fsgid = make_kgid(&init_user_ns, gid); - gi = groups_alloc(0); + gi = groups_alloc(user->ngroups); if (!gi) { abort_creds(cred); return -ENOMEM; } + + for (i = 0; i < user->ngroups; i++) { + if (gid_eq(GLOBAL_ROOT_GID, + make_kgid(&init_user_ns, user->sgid[i]))) + gi->gid[i] = cred->fsgid; + else + gi->gid[i] = make_kgid(&init_user_ns, + user->sgid[i]); + } + + if (user->ngroups) + groups_sort(gi); + set_groups(cred, gi); put_group_info(gi); diff --git a/transport_ipc.c b/transport_ipc.c index 85662f33c..f5612cca3 100644 --- a/transport_ipc.c +++ b/transport_ipc.c @@ -461,16 +461,24 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) { unsigned int msg_sz = entry->msg_sz; - if (entry->type == KSMBD_EVENT_RPC_REQUEST) { + switch (entry->type) { + case KSMBD_EVENT_RPC_REQUEST: + { struct ksmbd_rpc_command *resp = entry->response; msg_sz = sizeof(struct ksmbd_rpc_command) + resp->payload_sz; - } else if (entry->type == KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST) { + break; + } + case KSMBD_EVENT_SPNEGO_AUTHEN_REQUEST: + { struct ksmbd_spnego_authen_response *resp = entry->response; msg_sz = sizeof(struct ksmbd_spnego_authen_response) + resp->session_key_len + resp->spnego_blob_len; - } else if (entry->type == KSMBD_EVENT_SHARE_CONFIG_REQUEST) { + break; + } + case KSMBD_EVENT_SHARE_CONFIG_REQUEST: + { struct ksmbd_share_config_response *resp = entry->response; if (resp->payload_sz) { @@ -481,6 +489,7 @@ static int ipc_validate_msg(struct ipc_msg_table_entry *entry) resp->payload_sz; } } + } return entry->msg_sz != msg_sz ? -EINVAL : 0; }