aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <roland@purestorage.com>2014-05-29 16:32:30 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2014-06-03 22:17:31 -0400
commit79d59d08082dd0a0a18f8ceb78c99f9f321d72aa (patch)
tree94515b2560bdc01a57939ae00b7ca0c9abc965e4
parent6cc44a6fb46e1ecc1c28125aa8fa34d317aa9ea7 (diff)
iscsi-target: Fix wrong buffer / buffer overrun in iscsi_change_param_value()
In non-leading connection login, iscsi_login_non_zero_tsih_s1() calls iscsi_change_param_value() with the buffer it uses to hold the login PDU, not a temporary buffer. This leads to the login header getting corrupted and login failing for non-leading connections in MC/S. Fix this by adding a wrapper iscsi_change_param_sprintf() that handles the temporary buffer itself to avoid confusion. Also handle sending a reject in case of failure in the wrapper, which lets the calling code get quite a bit smaller and easier to read. Finally, bump the size of the temporary buffer from 32 to 64 bytes to be safe, since "MaxRecvDataSegmentLength=" by itself is 25 bytes; with a trailing NUL, a value >= 1M will lead to a buffer overrun. (This isn't the default but we don't need to run right at the ragged edge here) Reported-by: Santosh Kulkarni <santosh.kulkarni@calsoftinc.com> Signed-off-by: Roland Dreier <roland@purestorage.com> Cc: stable@vger.kernel.org # 3.10+ Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c70
1 files changed, 31 insertions, 39 deletions
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index ca31fa1b8a4b..d9b1d88e1ad3 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -249,6 +249,28 @@ static void iscsi_login_set_conn_values(
249 mutex_unlock(&auth_id_lock); 249 mutex_unlock(&auth_id_lock);
250} 250}
251 251
252static __printf(2, 3) int iscsi_change_param_sprintf(
253 struct iscsi_conn *conn,
254 const char *fmt, ...)
255{
256 va_list args;
257 unsigned char buf[64];
258
259 memset(buf, 0, sizeof buf);
260
261 va_start(args, fmt);
262 vsnprintf(buf, sizeof buf, fmt, args);
263 va_end(args);
264
265 if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
266 iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
267 ISCSI_LOGIN_STATUS_NO_RESOURCES);
268 return -1;
269 }
270
271 return 0;
272}
273
252/* 274/*
253 * This is the leading connection of a new session, 275 * This is the leading connection of a new session,
254 * or session reinstatement. 276 * or session reinstatement.
@@ -339,7 +361,6 @@ static int iscsi_login_zero_tsih_s2(
339{ 361{
340 struct iscsi_node_attrib *na; 362 struct iscsi_node_attrib *na;
341 struct iscsi_session *sess = conn->sess; 363 struct iscsi_session *sess = conn->sess;
342 unsigned char buf[32];
343 bool iser = false; 364 bool iser = false;
344 365
345 sess->tpg = conn->tpg; 366 sess->tpg = conn->tpg;
@@ -380,26 +401,16 @@ static int iscsi_login_zero_tsih_s2(
380 * 401 *
381 * In our case, we have already located the struct iscsi_tiqn at this point. 402 * In our case, we have already located the struct iscsi_tiqn at this point.
382 */ 403 */
383 memset(buf, 0, 32); 404 if (iscsi_change_param_sprintf(conn, "TargetPortalGroupTag=%hu", sess->tpg->tpgt))
384 sprintf(buf, "TargetPortalGroupTag=%hu", sess->tpg->tpgt);
385 if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
386 iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
387 ISCSI_LOGIN_STATUS_NO_RESOURCES);
388 return -1; 405 return -1;
389 }
390 406
391 /* 407 /*
392 * Workaround for Initiators that have broken connection recovery logic. 408 * Workaround for Initiators that have broken connection recovery logic.
393 * 409 *
394 * "We would really like to get rid of this." Linux-iSCSI.org team 410 * "We would really like to get rid of this." Linux-iSCSI.org team
395 */ 411 */
396 memset(buf, 0, 32); 412 if (iscsi_change_param_sprintf(conn, "ErrorRecoveryLevel=%d", na->default_erl))
397 sprintf(buf, "ErrorRecoveryLevel=%d", na->default_erl);
398 if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
399 iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
400 ISCSI_LOGIN_STATUS_NO_RESOURCES);
401 return -1; 413 return -1;
402 }
403 414
404 if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0) 415 if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0)
405 return -1; 416 return -1;
@@ -411,12 +422,9 @@ static int iscsi_login_zero_tsih_s2(
411 unsigned long mrdsl, off; 422 unsigned long mrdsl, off;
412 int rc; 423 int rc;
413 424
414 sprintf(buf, "RDMAExtensions=Yes"); 425 if (iscsi_change_param_sprintf(conn, "RDMAExtensions=Yes"))
415 if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
416 iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
417 ISCSI_LOGIN_STATUS_NO_RESOURCES);
418 return -1; 426 return -1;
419 } 427
420 /* 428 /*
421 * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for 429 * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for
422 * Immediate Data + Unsolicitied Data-OUT if necessary.. 430 * Immediate Data + Unsolicitied Data-OUT if necessary..
@@ -446,12 +454,8 @@ static int iscsi_login_zero_tsih_s2(
446 pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down" 454 pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down"
447 " to PAGE_SIZE\n", mrdsl); 455 " to PAGE_SIZE\n", mrdsl);
448 456
449 sprintf(buf, "MaxRecvDataSegmentLength=%lu\n", mrdsl); 457 if (iscsi_change_param_sprintf(conn, "MaxRecvDataSegmentLength=%lu\n", mrdsl))
450 if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
451 iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
452 ISCSI_LOGIN_STATUS_NO_RESOURCES);
453 return -1; 458 return -1;
454 }
455 /* 459 /*
456 * ISER currently requires that ImmediateData + Unsolicited 460 * ISER currently requires that ImmediateData + Unsolicited
457 * Data be disabled when protection / signature MRs are enabled. 461 * Data be disabled when protection / signature MRs are enabled.
@@ -461,19 +465,12 @@ check_prot:
461 (TARGET_PROT_DOUT_STRIP | TARGET_PROT_DOUT_PASS | 465 (TARGET_PROT_DOUT_STRIP | TARGET_PROT_DOUT_PASS |
462 TARGET_PROT_DOUT_INSERT)) { 466 TARGET_PROT_DOUT_INSERT)) {
463 467
464 sprintf(buf, "ImmediateData=No"); 468 if (iscsi_change_param_sprintf(conn, "ImmediateData=No"))
465 if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
466 iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
467 ISCSI_LOGIN_STATUS_NO_RESOURCES);
468 return -1; 469 return -1;
469 }
470 470
471 sprintf(buf, "InitialR2T=Yes"); 471 if (iscsi_change_param_sprintf(conn, "InitialR2T=Yes"))
472 if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
473 iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
474 ISCSI_LOGIN_STATUS_NO_RESOURCES);
475 return -1; 472 return -1;
476 } 473
477 pr_debug("Forcing ImmediateData=No + InitialR2T=Yes for" 474 pr_debug("Forcing ImmediateData=No + InitialR2T=Yes for"
478 " T10-PI enabled ISER session\n"); 475 " T10-PI enabled ISER session\n");
479 } 476 }
@@ -618,13 +615,8 @@ static int iscsi_login_non_zero_tsih_s2(
618 * 615 *
619 * In our case, we have already located the struct iscsi_tiqn at this point. 616 * In our case, we have already located the struct iscsi_tiqn at this point.
620 */ 617 */
621 memset(buf, 0, 32); 618 if (iscsi_change_param_sprintf(conn, "TargetPortalGroupTag=%hu", sess->tpg->tpgt))
622 sprintf(buf, "TargetPortalGroupTag=%hu", sess->tpg->tpgt);
623 if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) {
624 iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
625 ISCSI_LOGIN_STATUS_NO_RESOURCES);
626 return -1; 619 return -1;
627 }
628 620
629 return iscsi_login_disable_FIM_keys(conn->param_list, conn); 621 return iscsi_login_disable_FIM_keys(conn->param_list, conn);
630} 622}