aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Christie <michaelc@cs.wisc.edu>2012-01-26 22:13:10 -0500
committerJames Bottomley <JBottomley@Parallels.com>2012-02-19 09:09:00 -0500
commit1304be5fe0efb42b7ec6a50dd8e1a9bce2adae17 (patch)
treebc3d95ab7c1cc5d779df4696aaa138b7cbd89825
parentdf1c7baba1b7b3053950f3845a6575aca47ba9ce (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.c13
-rw-r--r--drivers/scsi/iscsi_tcp.c13
-rw-r--r--drivers/scsi/libiscsi.c2
-rw-r--r--drivers/scsi/libiscsi_tcp.c18
-rw-r--r--include/scsi/libiscsi.h2
-rw-r--r--include/scsi/libiscsi_tcp.h2
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}
1171EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free); 1171EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free);
1172 1172
1173int 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}
1189EXPORT_SYMBOL_GPL(iscsi_tcp_set_max_r2t);
1190
1173void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, 1191void 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 */
129extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session); 129extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session);
130extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session); 130extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session);
131 131extern int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf);
132extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, 132extern 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 */