diff options
author | Laura Abbott <labbott@redhat.com> | 2018-09-04 14:47:40 -0400 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2018-09-11 20:47:08 -0400 |
commit | 679fcae46c8b2352bba3485d521da070cfbe68e6 (patch) | |
tree | 7dd0d16bc5f68c5d459e39089d2dc81a678f2047 | |
parent | c77a2fa3ff8f73d1a485e67e6f81c64823739d59 (diff) |
scsi: iscsi: target: Don't use stack buffer for scatterlist
Fedora got a bug report of a crash with iSCSI:
kernel BUG at include/linux/scatterlist.h:143!
...
RIP: 0010:iscsit_do_crypto_hash_buf+0x154/0x180 [iscsi_target_mod]
...
Call Trace:
? iscsi_target_tx_thread+0x200/0x200 [iscsi_target_mod]
iscsit_get_rx_pdu+0x4cd/0xa90 [iscsi_target_mod]
? native_sched_clock+0x3e/0xa0
? iscsi_target_tx_thread+0x200/0x200 [iscsi_target_mod]
iscsi_target_rx_thread+0x81/0xf0 [iscsi_target_mod]
kthread+0x120/0x140
? kthread_create_worker_on_cpu+0x70/0x70
ret_from_fork+0x3a/0x50
This is a BUG_ON for using a stack buffer with a scatterlist. There
are two cases that trigger this bug. Switch to using a dynamically
allocated buffer for one case and do not assign a NULL buffer in
another case.
Signed-off-by: Laura Abbott <labbott@redhat.com>
Reviewed-by: Mike Christie <mchristi@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 9cdfccbdd06f..cc756a123fd8 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -1416,7 +1416,8 @@ static void iscsit_do_crypto_hash_buf(struct ahash_request *hash, | |||
1416 | 1416 | ||
1417 | sg_init_table(sg, ARRAY_SIZE(sg)); | 1417 | sg_init_table(sg, ARRAY_SIZE(sg)); |
1418 | sg_set_buf(sg, buf, payload_length); | 1418 | sg_set_buf(sg, buf, payload_length); |
1419 | sg_set_buf(sg + 1, pad_bytes, padding); | 1419 | if (padding) |
1420 | sg_set_buf(sg + 1, pad_bytes, padding); | ||
1420 | 1421 | ||
1421 | ahash_request_set_crypt(hash, sg, data_crc, payload_length + padding); | 1422 | ahash_request_set_crypt(hash, sg, data_crc, payload_length + padding); |
1422 | 1423 | ||
@@ -3910,10 +3911,14 @@ static bool iscsi_target_check_conn_state(struct iscsi_conn *conn) | |||
3910 | static void iscsit_get_rx_pdu(struct iscsi_conn *conn) | 3911 | static void iscsit_get_rx_pdu(struct iscsi_conn *conn) |
3911 | { | 3912 | { |
3912 | int ret; | 3913 | int ret; |
3913 | u8 buffer[ISCSI_HDR_LEN], opcode; | 3914 | u8 *buffer, opcode; |
3914 | u32 checksum = 0, digest = 0; | 3915 | u32 checksum = 0, digest = 0; |
3915 | struct kvec iov; | 3916 | struct kvec iov; |
3916 | 3917 | ||
3918 | buffer = kcalloc(ISCSI_HDR_LEN, sizeof(*buffer), GFP_KERNEL); | ||
3919 | if (!buffer) | ||
3920 | return; | ||
3921 | |||
3917 | while (!kthread_should_stop()) { | 3922 | while (!kthread_should_stop()) { |
3918 | /* | 3923 | /* |
3919 | * Ensure that both TX and RX per connection kthreads | 3924 | * Ensure that both TX and RX per connection kthreads |
@@ -3921,7 +3926,6 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) | |||
3921 | */ | 3926 | */ |
3922 | iscsit_thread_check_cpumask(conn, current, 0); | 3927 | iscsit_thread_check_cpumask(conn, current, 0); |
3923 | 3928 | ||
3924 | memset(buffer, 0, ISCSI_HDR_LEN); | ||
3925 | memset(&iov, 0, sizeof(struct kvec)); | 3929 | memset(&iov, 0, sizeof(struct kvec)); |
3926 | 3930 | ||
3927 | iov.iov_base = buffer; | 3931 | iov.iov_base = buffer; |
@@ -3930,7 +3934,7 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) | |||
3930 | ret = rx_data(conn, &iov, 1, ISCSI_HDR_LEN); | 3934 | ret = rx_data(conn, &iov, 1, ISCSI_HDR_LEN); |
3931 | if (ret != ISCSI_HDR_LEN) { | 3935 | if (ret != ISCSI_HDR_LEN) { |
3932 | iscsit_rx_thread_wait_for_tcp(conn); | 3936 | iscsit_rx_thread_wait_for_tcp(conn); |
3933 | return; | 3937 | break; |
3934 | } | 3938 | } |
3935 | 3939 | ||
3936 | if (conn->conn_ops->HeaderDigest) { | 3940 | if (conn->conn_ops->HeaderDigest) { |
@@ -3940,7 +3944,7 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) | |||
3940 | ret = rx_data(conn, &iov, 1, ISCSI_CRC_LEN); | 3944 | ret = rx_data(conn, &iov, 1, ISCSI_CRC_LEN); |
3941 | if (ret != ISCSI_CRC_LEN) { | 3945 | if (ret != ISCSI_CRC_LEN) { |
3942 | iscsit_rx_thread_wait_for_tcp(conn); | 3946 | iscsit_rx_thread_wait_for_tcp(conn); |
3943 | return; | 3947 | break; |
3944 | } | 3948 | } |
3945 | 3949 | ||
3946 | iscsit_do_crypto_hash_buf(conn->conn_rx_hash, buffer, | 3950 | iscsit_do_crypto_hash_buf(conn->conn_rx_hash, buffer, |
@@ -3964,7 +3968,7 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) | |||
3964 | } | 3968 | } |
3965 | 3969 | ||
3966 | if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) | 3970 | if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) |
3967 | return; | 3971 | break; |
3968 | 3972 | ||
3969 | opcode = buffer[0] & ISCSI_OPCODE_MASK; | 3973 | opcode = buffer[0] & ISCSI_OPCODE_MASK; |
3970 | 3974 | ||
@@ -3975,13 +3979,15 @@ static void iscsit_get_rx_pdu(struct iscsi_conn *conn) | |||
3975 | " while in Discovery Session, rejecting.\n", opcode); | 3979 | " while in Discovery Session, rejecting.\n", opcode); |
3976 | iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, | 3980 | iscsit_add_reject(conn, ISCSI_REASON_PROTOCOL_ERROR, |
3977 | buffer); | 3981 | buffer); |
3978 | return; | 3982 | break; |
3979 | } | 3983 | } |
3980 | 3984 | ||
3981 | ret = iscsi_target_rx_opcode(conn, buffer); | 3985 | ret = iscsi_target_rx_opcode(conn, buffer); |
3982 | if (ret < 0) | 3986 | if (ret < 0) |
3983 | return; | 3987 | break; |
3984 | } | 3988 | } |
3989 | |||
3990 | kfree(buffer); | ||
3985 | } | 3991 | } |
3986 | 3992 | ||
3987 | int iscsi_target_rx_thread(void *arg) | 3993 | int iscsi_target_rx_thread(void *arg) |