Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v6.3 629 lines 14 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org> 4 * Copyright (C) 2018 Samsung Electronics Co., Ltd. 5 */ 6 7#include "glob.h" 8#include "oplock.h" 9#include "misc.h" 10#include <linux/sched/signal.h> 11#include <linux/workqueue.h> 12#include <linux/sysfs.h> 13#include <linux/module.h> 14#include <linux/moduleparam.h> 15 16#include "server.h" 17#include "smb_common.h" 18#include "smbstatus.h" 19#include "connection.h" 20#include "transport_ipc.h" 21#include "mgmt/user_session.h" 22#include "crypto_ctx.h" 23#include "auth.h" 24 25int ksmbd_debug_types; 26 27struct ksmbd_server_config server_conf; 28 29enum SERVER_CTRL_TYPE { 30 SERVER_CTRL_TYPE_INIT, 31 SERVER_CTRL_TYPE_RESET, 32}; 33 34struct server_ctrl_struct { 35 int type; 36 struct work_struct ctrl_work; 37}; 38 39static DEFINE_MUTEX(ctrl_lock); 40 41static int ___server_conf_set(int idx, char *val) 42{ 43 if (idx >= ARRAY_SIZE(server_conf.conf)) 44 return -EINVAL; 45 46 if (!val || val[0] == 0x00) 47 return -EINVAL; 48 49 kfree(server_conf.conf[idx]); 50 server_conf.conf[idx] = kstrdup(val, GFP_KERNEL); 51 if (!server_conf.conf[idx]) 52 return -ENOMEM; 53 return 0; 54} 55 56int ksmbd_set_netbios_name(char *v) 57{ 58 return ___server_conf_set(SERVER_CONF_NETBIOS_NAME, v); 59} 60 61int ksmbd_set_server_string(char *v) 62{ 63 return ___server_conf_set(SERVER_CONF_SERVER_STRING, v); 64} 65 66int ksmbd_set_work_group(char *v) 67{ 68 return ___server_conf_set(SERVER_CONF_WORK_GROUP, v); 69} 70 71char *ksmbd_netbios_name(void) 72{ 73 return server_conf.conf[SERVER_CONF_NETBIOS_NAME]; 74} 75 76char *ksmbd_server_string(void) 77{ 78 return server_conf.conf[SERVER_CONF_SERVER_STRING]; 79} 80 81char *ksmbd_work_group(void) 82{ 83 return server_conf.conf[SERVER_CONF_WORK_GROUP]; 84} 85 86/** 87 * check_conn_state() - check state of server thread connection 88 * @work: smb work containing server thread information 89 * 90 * Return: 0 on valid connection, otherwise 1 to reconnect 91 */ 92static inline int check_conn_state(struct ksmbd_work *work) 93{ 94 struct smb_hdr *rsp_hdr; 95 96 if (ksmbd_conn_exiting(work) || ksmbd_conn_need_reconnect(work)) { 97 rsp_hdr = work->response_buf; 98 rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED; 99 return 1; 100 } 101 return 0; 102} 103 104#define SERVER_HANDLER_CONTINUE 0 105#define SERVER_HANDLER_ABORT 1 106 107static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn, 108 u16 *cmd) 109{ 110 struct smb_version_cmds *cmds; 111 u16 command; 112 int ret; 113 114 if (check_conn_state(work)) 115 return SERVER_HANDLER_CONTINUE; 116 117 if (ksmbd_verify_smb_message(work)) 118 return SERVER_HANDLER_ABORT; 119 120 command = conn->ops->get_cmd_val(work); 121 *cmd = command; 122 123andx_again: 124 if (command >= conn->max_cmds) { 125 conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER); 126 return SERVER_HANDLER_CONTINUE; 127 } 128 129 cmds = &conn->cmds[command]; 130 if (!cmds->proc) { 131 ksmbd_debug(SMB, "*** not implemented yet cmd = %x\n", command); 132 conn->ops->set_rsp_status(work, STATUS_NOT_IMPLEMENTED); 133 return SERVER_HANDLER_CONTINUE; 134 } 135 136 if (work->sess && conn->ops->is_sign_req(work, command)) { 137 ret = conn->ops->check_sign_req(work); 138 if (!ret) { 139 conn->ops->set_rsp_status(work, STATUS_ACCESS_DENIED); 140 return SERVER_HANDLER_CONTINUE; 141 } 142 } 143 144 ret = cmds->proc(work); 145 146 if (ret < 0) 147 ksmbd_debug(CONN, "Failed to process %u [%d]\n", command, ret); 148 /* AndX commands - chained request can return positive values */ 149 else if (ret > 0) { 150 command = ret; 151 *cmd = command; 152 goto andx_again; 153 } 154 155 if (work->send_no_response) 156 return SERVER_HANDLER_ABORT; 157 return SERVER_HANDLER_CONTINUE; 158} 159 160static void __handle_ksmbd_work(struct ksmbd_work *work, 161 struct ksmbd_conn *conn) 162{ 163 u16 command = 0; 164 int rc; 165 166 if (conn->ops->allocate_rsp_buf(work)) 167 return; 168 169 if (conn->ops->is_transform_hdr && 170 conn->ops->is_transform_hdr(work->request_buf)) { 171 rc = conn->ops->decrypt_req(work); 172 if (rc < 0) { 173 conn->ops->set_rsp_status(work, STATUS_DATA_ERROR); 174 goto send; 175 } 176 177 work->encrypted = true; 178 } 179 180 rc = conn->ops->init_rsp_hdr(work); 181 if (rc) { 182 /* either uid or tid is not correct */ 183 conn->ops->set_rsp_status(work, STATUS_INVALID_HANDLE); 184 goto send; 185 } 186 187 if (conn->ops->check_user_session) { 188 rc = conn->ops->check_user_session(work); 189 if (rc < 0) { 190 command = conn->ops->get_cmd_val(work); 191 conn->ops->set_rsp_status(work, 192 STATUS_USER_SESSION_DELETED); 193 goto send; 194 } else if (rc > 0) { 195 rc = conn->ops->get_ksmbd_tcon(work); 196 if (rc < 0) { 197 conn->ops->set_rsp_status(work, 198 STATUS_NETWORK_NAME_DELETED); 199 goto send; 200 } 201 } 202 } 203 204 do { 205 rc = __process_request(work, conn, &command); 206 if (rc == SERVER_HANDLER_ABORT) 207 break; 208 209 /* 210 * Call smb2_set_rsp_credits() function to set number of credits 211 * granted in hdr of smb2 response. 212 */ 213 if (conn->ops->set_rsp_credits) { 214 spin_lock(&conn->credits_lock); 215 rc = conn->ops->set_rsp_credits(work); 216 spin_unlock(&conn->credits_lock); 217 if (rc < 0) { 218 conn->ops->set_rsp_status(work, 219 STATUS_INVALID_PARAMETER); 220 goto send; 221 } 222 } 223 224 if (work->sess && 225 (work->sess->sign || smb3_11_final_sess_setup_resp(work) || 226 conn->ops->is_sign_req(work, command))) 227 conn->ops->set_sign_rsp(work); 228 } while (is_chained_smb2_message(work)); 229 230 if (work->send_no_response) 231 return; 232 233send: 234 smb3_preauth_hash_rsp(work); 235 if (work->sess && work->sess->enc && work->encrypted && 236 conn->ops->encrypt_resp) { 237 rc = conn->ops->encrypt_resp(work); 238 if (rc < 0) 239 conn->ops->set_rsp_status(work, STATUS_DATA_ERROR); 240 } 241 242 ksmbd_conn_write(work); 243} 244 245/** 246 * handle_ksmbd_work() - process pending smb work requests 247 * @wk: smb work containing request command buffer 248 * 249 * called by kworker threads to processing remaining smb work requests 250 */ 251static void handle_ksmbd_work(struct work_struct *wk) 252{ 253 struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work); 254 struct ksmbd_conn *conn = work->conn; 255 256 atomic64_inc(&conn->stats.request_served); 257 258 __handle_ksmbd_work(work, conn); 259 260 ksmbd_conn_try_dequeue_request(work); 261 ksmbd_free_work_struct(work); 262 /* 263 * Checking waitqueue to dropping pending requests on 264 * disconnection. waitqueue_active is safe because it 265 * uses atomic operation for condition. 266 */ 267 if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q)) 268 wake_up(&conn->r_count_q); 269} 270 271/** 272 * queue_ksmbd_work() - queue a smb request to worker thread queue 273 * for proccessing smb command and sending response 274 * @conn: connection instance 275 * 276 * read remaining data from socket create and submit work. 277 */ 278static int queue_ksmbd_work(struct ksmbd_conn *conn) 279{ 280 struct ksmbd_work *work; 281 282 work = ksmbd_alloc_work_struct(); 283 if (!work) { 284 pr_err("allocation for work failed\n"); 285 return -ENOMEM; 286 } 287 288 work->conn = conn; 289 work->request_buf = conn->request_buf; 290 conn->request_buf = NULL; 291 292 ksmbd_init_smb_server(work); 293 294 ksmbd_conn_enqueue_request(work); 295 atomic_inc(&conn->r_count); 296 /* update activity on connection */ 297 conn->last_active = jiffies; 298 INIT_WORK(&work->work, handle_ksmbd_work); 299 ksmbd_queue_work(work); 300 return 0; 301} 302 303static int ksmbd_server_process_request(struct ksmbd_conn *conn) 304{ 305 return queue_ksmbd_work(conn); 306} 307 308static int ksmbd_server_terminate_conn(struct ksmbd_conn *conn) 309{ 310 ksmbd_sessions_deregister(conn); 311 destroy_lease_table(conn); 312 return 0; 313} 314 315static void ksmbd_server_tcp_callbacks_init(void) 316{ 317 struct ksmbd_conn_ops ops; 318 319 ops.process_fn = ksmbd_server_process_request; 320 ops.terminate_fn = ksmbd_server_terminate_conn; 321 322 ksmbd_conn_init_server_callbacks(&ops); 323} 324 325static void server_conf_free(void) 326{ 327 int i; 328 329 for (i = 0; i < ARRAY_SIZE(server_conf.conf); i++) { 330 kfree(server_conf.conf[i]); 331 server_conf.conf[i] = NULL; 332 } 333} 334 335static int server_conf_init(void) 336{ 337 WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP); 338 server_conf.enforced_signing = 0; 339 server_conf.min_protocol = ksmbd_min_protocol(); 340 server_conf.max_protocol = ksmbd_max_protocol(); 341 server_conf.auth_mechs = KSMBD_AUTH_NTLMSSP; 342#ifdef CONFIG_SMB_SERVER_KERBEROS5 343 server_conf.auth_mechs |= KSMBD_AUTH_KRB5 | 344 KSMBD_AUTH_MSKRB5; 345#endif 346 return 0; 347} 348 349static void server_ctrl_handle_init(struct server_ctrl_struct *ctrl) 350{ 351 int ret; 352 353 ret = ksmbd_conn_transport_init(); 354 if (ret) { 355 server_queue_ctrl_reset_work(); 356 return; 357 } 358 359 WRITE_ONCE(server_conf.state, SERVER_STATE_RUNNING); 360} 361 362static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl) 363{ 364 ksmbd_ipc_soft_reset(); 365 ksmbd_conn_transport_destroy(); 366 server_conf_free(); 367 server_conf_init(); 368 WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP); 369} 370 371static void server_ctrl_handle_work(struct work_struct *work) 372{ 373 struct server_ctrl_struct *ctrl; 374 375 ctrl = container_of(work, struct server_ctrl_struct, ctrl_work); 376 377 mutex_lock(&ctrl_lock); 378 switch (ctrl->type) { 379 case SERVER_CTRL_TYPE_INIT: 380 server_ctrl_handle_init(ctrl); 381 break; 382 case SERVER_CTRL_TYPE_RESET: 383 server_ctrl_handle_reset(ctrl); 384 break; 385 default: 386 pr_err("Unknown server work type: %d\n", ctrl->type); 387 } 388 mutex_unlock(&ctrl_lock); 389 kfree(ctrl); 390 module_put(THIS_MODULE); 391} 392 393static int __queue_ctrl_work(int type) 394{ 395 struct server_ctrl_struct *ctrl; 396 397 ctrl = kmalloc(sizeof(struct server_ctrl_struct), GFP_KERNEL); 398 if (!ctrl) 399 return -ENOMEM; 400 401 __module_get(THIS_MODULE); 402 ctrl->type = type; 403 INIT_WORK(&ctrl->ctrl_work, server_ctrl_handle_work); 404 queue_work(system_long_wq, &ctrl->ctrl_work); 405 return 0; 406} 407 408int server_queue_ctrl_init_work(void) 409{ 410 return __queue_ctrl_work(SERVER_CTRL_TYPE_INIT); 411} 412 413int server_queue_ctrl_reset_work(void) 414{ 415 return __queue_ctrl_work(SERVER_CTRL_TYPE_RESET); 416} 417 418static ssize_t stats_show(struct class *class, struct class_attribute *attr, 419 char *buf) 420{ 421 /* 422 * Inc this each time you change stats output format, 423 * so user space will know what to do. 424 */ 425 static int stats_version = 2; 426 static const char * const state[] = { 427 "startup", 428 "running", 429 "reset", 430 "shutdown" 431 }; 432 return sysfs_emit(buf, "%d %s %d %lu\n", stats_version, 433 state[server_conf.state], server_conf.tcp_port, 434 server_conf.ipc_last_active / HZ); 435} 436 437static ssize_t kill_server_store(struct class *class, 438 struct class_attribute *attr, const char *buf, 439 size_t len) 440{ 441 if (!sysfs_streq(buf, "hard")) 442 return len; 443 444 pr_info("kill command received\n"); 445 mutex_lock(&ctrl_lock); 446 WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING); 447 __module_get(THIS_MODULE); 448 server_ctrl_handle_reset(NULL); 449 module_put(THIS_MODULE); 450 mutex_unlock(&ctrl_lock); 451 return len; 452} 453 454static const char * const debug_type_strings[] = {"smb", "auth", "vfs", 455 "oplock", "ipc", "conn", 456 "rdma"}; 457 458static ssize_t debug_show(struct class *class, struct class_attribute *attr, 459 char *buf) 460{ 461 ssize_t sz = 0; 462 int i, pos = 0; 463 464 for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) { 465 if ((ksmbd_debug_types >> i) & 1) { 466 pos = sysfs_emit_at(buf, sz, "[%s] ", debug_type_strings[i]); 467 } else { 468 pos = sysfs_emit_at(buf, sz, "%s ", debug_type_strings[i]); 469 } 470 sz += pos; 471 } 472 sz += sysfs_emit_at(buf, sz, "\n"); 473 return sz; 474} 475 476static ssize_t debug_store(struct class *class, struct class_attribute *attr, 477 const char *buf, size_t len) 478{ 479 int i; 480 481 for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) { 482 if (sysfs_streq(buf, "all")) { 483 if (ksmbd_debug_types == KSMBD_DEBUG_ALL) 484 ksmbd_debug_types = 0; 485 else 486 ksmbd_debug_types = KSMBD_DEBUG_ALL; 487 break; 488 } 489 490 if (sysfs_streq(buf, debug_type_strings[i])) { 491 if (ksmbd_debug_types & (1 << i)) 492 ksmbd_debug_types &= ~(1 << i); 493 else 494 ksmbd_debug_types |= (1 << i); 495 break; 496 } 497 } 498 499 return len; 500} 501 502static CLASS_ATTR_RO(stats); 503static CLASS_ATTR_WO(kill_server); 504static CLASS_ATTR_RW(debug); 505 506static struct attribute *ksmbd_control_class_attrs[] = { 507 &class_attr_stats.attr, 508 &class_attr_kill_server.attr, 509 &class_attr_debug.attr, 510 NULL, 511}; 512ATTRIBUTE_GROUPS(ksmbd_control_class); 513 514static struct class ksmbd_control_class = { 515 .name = "ksmbd-control", 516 .owner = THIS_MODULE, 517 .class_groups = ksmbd_control_class_groups, 518}; 519 520static int ksmbd_server_shutdown(void) 521{ 522 WRITE_ONCE(server_conf.state, SERVER_STATE_SHUTTING_DOWN); 523 524 class_unregister(&ksmbd_control_class); 525 ksmbd_workqueue_destroy(); 526 ksmbd_ipc_release(); 527 ksmbd_conn_transport_destroy(); 528 ksmbd_crypto_destroy(); 529 ksmbd_free_global_file_table(); 530 destroy_lease_table(NULL); 531 ksmbd_work_pool_destroy(); 532 ksmbd_exit_file_cache(); 533 server_conf_free(); 534 return 0; 535} 536 537static int __init ksmbd_server_init(void) 538{ 539 int ret; 540 541 ret = class_register(&ksmbd_control_class); 542 if (ret) { 543 pr_err("Unable to register ksmbd-control class\n"); 544 return ret; 545 } 546 547 ksmbd_server_tcp_callbacks_init(); 548 549 ret = server_conf_init(); 550 if (ret) 551 goto err_unregister; 552 553 ret = ksmbd_work_pool_init(); 554 if (ret) 555 goto err_unregister; 556 557 ret = ksmbd_init_file_cache(); 558 if (ret) 559 goto err_destroy_work_pools; 560 561 ret = ksmbd_ipc_init(); 562 if (ret) 563 goto err_exit_file_cache; 564 565 ret = ksmbd_init_global_file_table(); 566 if (ret) 567 goto err_ipc_release; 568 569 ret = ksmbd_inode_hash_init(); 570 if (ret) 571 goto err_destroy_file_table; 572 573 ret = ksmbd_crypto_create(); 574 if (ret) 575 goto err_release_inode_hash; 576 577 ret = ksmbd_workqueue_init(); 578 if (ret) 579 goto err_crypto_destroy; 580 581 pr_warn_once("The ksmbd server is experimental\n"); 582 583 return 0; 584 585err_crypto_destroy: 586 ksmbd_crypto_destroy(); 587err_release_inode_hash: 588 ksmbd_release_inode_hash(); 589err_destroy_file_table: 590 ksmbd_free_global_file_table(); 591err_ipc_release: 592 ksmbd_ipc_release(); 593err_exit_file_cache: 594 ksmbd_exit_file_cache(); 595err_destroy_work_pools: 596 ksmbd_work_pool_destroy(); 597err_unregister: 598 class_unregister(&ksmbd_control_class); 599 600 return ret; 601} 602 603/** 604 * ksmbd_server_exit() - shutdown forker thread and free memory at module exit 605 */ 606static void __exit ksmbd_server_exit(void) 607{ 608 ksmbd_server_shutdown(); 609 ksmbd_release_inode_hash(); 610} 611 612MODULE_AUTHOR("Namjae Jeon <linkinjeon@kernel.org>"); 613MODULE_VERSION(KSMBD_VERSION); 614MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER"); 615MODULE_LICENSE("GPL"); 616MODULE_SOFTDEP("pre: ecb"); 617MODULE_SOFTDEP("pre: hmac"); 618MODULE_SOFTDEP("pre: md5"); 619MODULE_SOFTDEP("pre: nls"); 620MODULE_SOFTDEP("pre: aes"); 621MODULE_SOFTDEP("pre: cmac"); 622MODULE_SOFTDEP("pre: sha256"); 623MODULE_SOFTDEP("pre: sha512"); 624MODULE_SOFTDEP("pre: aead2"); 625MODULE_SOFTDEP("pre: ccm"); 626MODULE_SOFTDEP("pre: gcm"); 627MODULE_SOFTDEP("pre: crc32"); 628module_init(ksmbd_server_init) 629module_exit(ksmbd_server_exit)