diff options
author | Mike Christie <michaelc@cs.wisc.edu> | 2012-01-26 22:13:10 -0500 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-02-19 09:09:00 -0500 |
commit | 1304be5fe0efb42b7ec6a50dd8e1a9bce2adae17 (patch) | |
tree | bc3d95ab7c1cc5d779df4696aaa138b7cbd89825 | |
parent | df1c7baba1b7b3053950f3845a6575aca47ba9ce (diff) |
[SCSI] libiscsi_tcp: fix max_r2t manipulation
Problem description from Xi Wang:
A large max_r2t could lead to integer overflow in subsequent call to
iscsi_tcp_r2tpool_alloc(), allocating a smaller buffer than expected
and leading to out-of-bounds write.
Signed-off-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/cxgbi/libcxgbi.c | 13 | ||||
-rw-r--r-- | drivers/scsi/iscsi_tcp.c | 13 | ||||
-rw-r--r-- | drivers/scsi/libiscsi.c | 2 | ||||
-rw-r--r-- | drivers/scsi/libiscsi_tcp.c | 18 | ||||
-rw-r--r-- | include/scsi/libiscsi.h | 2 | ||||
-rw-r--r-- | include/scsi/libiscsi_tcp.h | 2 |
6 files changed, 24 insertions, 26 deletions
diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index d3ff9cd40234..e6e6aa9289b8 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c | |||
@@ -2148,11 +2148,10 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, | |||
2148 | enum iscsi_param param, char *buf, int buflen) | 2148 | enum iscsi_param param, char *buf, int buflen) |
2149 | { | 2149 | { |
2150 | struct iscsi_conn *conn = cls_conn->dd_data; | 2150 | struct iscsi_conn *conn = cls_conn->dd_data; |
2151 | struct iscsi_session *session = conn->session; | ||
2152 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 2151 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
2153 | struct cxgbi_conn *cconn = tcp_conn->dd_data; | 2152 | struct cxgbi_conn *cconn = tcp_conn->dd_data; |
2154 | struct cxgbi_sock *csk = cconn->cep->csk; | 2153 | struct cxgbi_sock *csk = cconn->cep->csk; |
2155 | int value, err = 0; | 2154 | int err; |
2156 | 2155 | ||
2157 | log_debug(1 << CXGBI_DBG_ISCSI, | 2156 | log_debug(1 << CXGBI_DBG_ISCSI, |
2158 | "cls_conn 0x%p, param %d, buf(%d) %s.\n", | 2157 | "cls_conn 0x%p, param %d, buf(%d) %s.\n", |
@@ -2174,15 +2173,7 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, | |||
2174 | conn->datadgst_en, 0); | 2173 | conn->datadgst_en, 0); |
2175 | break; | 2174 | break; |
2176 | case ISCSI_PARAM_MAX_R2T: | 2175 | case ISCSI_PARAM_MAX_R2T: |
2177 | sscanf(buf, "%d", &value); | 2176 | return iscsi_tcp_set_max_r2t(conn, buf); |
2178 | if (value <= 0 || !is_power_of_2(value)) | ||
2179 | return -EINVAL; | ||
2180 | if (session->max_r2t == value) | ||
2181 | break; | ||
2182 | iscsi_tcp_r2tpool_free(session); | ||
2183 | err = iscsi_set_param(cls_conn, param, buf, buflen); | ||
2184 | if (!err && iscsi_tcp_r2tpool_alloc(session)) | ||
2185 | return -ENOMEM; | ||
2186 | case ISCSI_PARAM_MAX_RECV_DLENGTH: | 2177 | case ISCSI_PARAM_MAX_RECV_DLENGTH: |
2187 | err = iscsi_set_param(cls_conn, param, buf, buflen); | 2178 | err = iscsi_set_param(cls_conn, param, buf, buflen); |
2188 | if (!err) | 2179 | if (!err) |
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index db47158e0dde..453a740fa68e 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c | |||
@@ -684,10 +684,8 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn, | |||
684 | int buflen) | 684 | int buflen) |
685 | { | 685 | { |
686 | struct iscsi_conn *conn = cls_conn->dd_data; | 686 | struct iscsi_conn *conn = cls_conn->dd_data; |
687 | struct iscsi_session *session = conn->session; | ||
688 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; | 687 | struct iscsi_tcp_conn *tcp_conn = conn->dd_data; |
689 | struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; | 688 | struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; |
690 | int value; | ||
691 | 689 | ||
692 | switch(param) { | 690 | switch(param) { |
693 | case ISCSI_PARAM_HDRDGST_EN: | 691 | case ISCSI_PARAM_HDRDGST_EN: |
@@ -699,16 +697,7 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn, | |||
699 | sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage; | 697 | sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage; |
700 | break; | 698 | break; |
701 | case ISCSI_PARAM_MAX_R2T: | 699 | case ISCSI_PARAM_MAX_R2T: |
702 | sscanf(buf, "%d", &value); | 700 | return iscsi_tcp_set_max_r2t(conn, buf); |
703 | if (value <= 0 || !is_power_of_2(value)) | ||
704 | return -EINVAL; | ||
705 | if (session->max_r2t == value) | ||
706 | break; | ||
707 | iscsi_tcp_r2tpool_free(session); | ||
708 | iscsi_set_param(cls_conn, param, buf, buflen); | ||
709 | if (iscsi_tcp_r2tpool_alloc(session)) | ||
710 | return -ENOMEM; | ||
711 | break; | ||
712 | default: | 701 | default: |
713 | return iscsi_set_param(cls_conn, param, buf, buflen); | 702 | return iscsi_set_param(cls_conn, param, buf, buflen); |
714 | } | 703 | } |
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 00592e3bb375..8582d7c25732 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c | |||
@@ -3201,7 +3201,7 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn, | |||
3201 | sscanf(buf, "%d", &session->initial_r2t_en); | 3201 | sscanf(buf, "%d", &session->initial_r2t_en); |
3202 | break; | 3202 | break; |
3203 | case ISCSI_PARAM_MAX_R2T: | 3203 | case ISCSI_PARAM_MAX_R2T: |
3204 | sscanf(buf, "%d", &session->max_r2t); | 3204 | sscanf(buf, "%hu", &session->max_r2t); |
3205 | break; | 3205 | break; |
3206 | case ISCSI_PARAM_IMM_DATA_EN: | 3206 | case ISCSI_PARAM_IMM_DATA_EN: |
3207 | sscanf(buf, "%d", &session->imm_data_en); | 3207 | sscanf(buf, "%d", &session->imm_data_en); |
diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 5715a3d0a3d3..c4996b081999 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c | |||
@@ -1170,6 +1170,24 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session) | |||
1170 | } | 1170 | } |
1171 | EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free); | 1171 | EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free); |
1172 | 1172 | ||
1173 | int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf) | ||
1174 | { | ||
1175 | struct iscsi_session *session = conn->session; | ||
1176 | unsigned short r2ts = 0; | ||
1177 | |||
1178 | sscanf(buf, "%hu", &r2ts); | ||
1179 | if (session->max_r2t == r2ts) | ||
1180 | return 0; | ||
1181 | |||
1182 | if (!r2ts || !is_power_of_2(r2ts)) | ||
1183 | return -EINVAL; | ||
1184 | |||
1185 | session->max_r2t = r2ts; | ||
1186 | iscsi_tcp_r2tpool_free(session); | ||
1187 | return iscsi_tcp_r2tpool_alloc(session); | ||
1188 | } | ||
1189 | EXPORT_SYMBOL_GPL(iscsi_tcp_set_max_r2t); | ||
1190 | |||
1173 | void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, | 1191 | void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, |
1174 | struct iscsi_stats *stats) | 1192 | struct iscsi_stats *stats) |
1175 | { | 1193 | { |
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h index 2e42e9a0e0b6..6e33386a3898 100644 --- a/include/scsi/libiscsi.h +++ b/include/scsi/libiscsi.h | |||
@@ -268,7 +268,7 @@ struct iscsi_session { | |||
268 | int lu_reset_timeout; | 268 | int lu_reset_timeout; |
269 | int tgt_reset_timeout; | 269 | int tgt_reset_timeout; |
270 | int initial_r2t_en; | 270 | int initial_r2t_en; |
271 | unsigned max_r2t; | 271 | unsigned short max_r2t; |
272 | int imm_data_en; | 272 | int imm_data_en; |
273 | unsigned first_burst; | 273 | unsigned first_burst; |
274 | unsigned max_burst; | 274 | unsigned max_burst; |
diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h index ac0cc1d925ef..215469a9b801 100644 --- a/include/scsi/libiscsi_tcp.h +++ b/include/scsi/libiscsi_tcp.h | |||
@@ -128,7 +128,7 @@ extern void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn); | |||
128 | /* misc helpers */ | 128 | /* misc helpers */ |
129 | extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session); | 129 | extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session); |
130 | extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session); | 130 | extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session); |
131 | 131 | extern int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf); | |
132 | extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, | 132 | extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, |
133 | struct iscsi_stats *stats); | 133 | struct iscsi_stats *stats); |
134 | #endif /* LIBISCSI_TCP_H */ | 134 | #endif /* LIBISCSI_TCP_H */ |