[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>
This commit is contained in:
parent
df1c7baba1
commit
1304be5fe0
|
@ -2148,11 +2148,10 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn,
|
||||||
enum iscsi_param param, char *buf, int buflen)
|
enum iscsi_param param, char *buf, int buflen)
|
||||||
{
|
{
|
||||||
struct iscsi_conn *conn = cls_conn->dd_data;
|
struct iscsi_conn *conn = cls_conn->dd_data;
|
||||||
struct iscsi_session *session = conn->session;
|
|
||||||
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
|
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
|
||||||
struct cxgbi_conn *cconn = tcp_conn->dd_data;
|
struct cxgbi_conn *cconn = tcp_conn->dd_data;
|
||||||
struct cxgbi_sock *csk = cconn->cep->csk;
|
struct cxgbi_sock *csk = cconn->cep->csk;
|
||||||
int value, err = 0;
|
int err;
|
||||||
|
|
||||||
log_debug(1 << CXGBI_DBG_ISCSI,
|
log_debug(1 << CXGBI_DBG_ISCSI,
|
||||||
"cls_conn 0x%p, param %d, buf(%d) %s.\n",
|
"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,
|
||||||
conn->datadgst_en, 0);
|
conn->datadgst_en, 0);
|
||||||
break;
|
break;
|
||||||
case ISCSI_PARAM_MAX_R2T:
|
case ISCSI_PARAM_MAX_R2T:
|
||||||
sscanf(buf, "%d", &value);
|
return iscsi_tcp_set_max_r2t(conn, buf);
|
||||||
if (value <= 0 || !is_power_of_2(value))
|
|
||||||
return -EINVAL;
|
|
||||||
if (session->max_r2t == value)
|
|
||||||
break;
|
|
||||||
iscsi_tcp_r2tpool_free(session);
|
|
||||||
err = iscsi_set_param(cls_conn, param, buf, buflen);
|
|
||||||
if (!err && iscsi_tcp_r2tpool_alloc(session))
|
|
||||||
return -ENOMEM;
|
|
||||||
case ISCSI_PARAM_MAX_RECV_DLENGTH:
|
case ISCSI_PARAM_MAX_RECV_DLENGTH:
|
||||||
err = iscsi_set_param(cls_conn, param, buf, buflen);
|
err = iscsi_set_param(cls_conn, param, buf, buflen);
|
||||||
if (!err)
|
if (!err)
|
||||||
|
|
|
@ -684,10 +684,8 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn,
|
||||||
int buflen)
|
int buflen)
|
||||||
{
|
{
|
||||||
struct iscsi_conn *conn = cls_conn->dd_data;
|
struct iscsi_conn *conn = cls_conn->dd_data;
|
||||||
struct iscsi_session *session = conn->session;
|
|
||||||
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
|
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
|
||||||
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
|
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
|
||||||
int value;
|
|
||||||
|
|
||||||
switch(param) {
|
switch(param) {
|
||||||
case ISCSI_PARAM_HDRDGST_EN:
|
case ISCSI_PARAM_HDRDGST_EN:
|
||||||
|
@ -699,16 +697,7 @@ static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn,
|
||||||
sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage;
|
sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage;
|
||||||
break;
|
break;
|
||||||
case ISCSI_PARAM_MAX_R2T:
|
case ISCSI_PARAM_MAX_R2T:
|
||||||
sscanf(buf, "%d", &value);
|
return iscsi_tcp_set_max_r2t(conn, buf);
|
||||||
if (value <= 0 || !is_power_of_2(value))
|
|
||||||
return -EINVAL;
|
|
||||||
if (session->max_r2t == value)
|
|
||||||
break;
|
|
||||||
iscsi_tcp_r2tpool_free(session);
|
|
||||||
iscsi_set_param(cls_conn, param, buf, buflen);
|
|
||||||
if (iscsi_tcp_r2tpool_alloc(session))
|
|
||||||
return -ENOMEM;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
return iscsi_set_param(cls_conn, param, buf, buflen);
|
return iscsi_set_param(cls_conn, param, buf, buflen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3201,7 +3201,7 @@ int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
|
||||||
sscanf(buf, "%d", &session->initial_r2t_en);
|
sscanf(buf, "%d", &session->initial_r2t_en);
|
||||||
break;
|
break;
|
||||||
case ISCSI_PARAM_MAX_R2T:
|
case ISCSI_PARAM_MAX_R2T:
|
||||||
sscanf(buf, "%d", &session->max_r2t);
|
sscanf(buf, "%hu", &session->max_r2t);
|
||||||
break;
|
break;
|
||||||
case ISCSI_PARAM_IMM_DATA_EN:
|
case ISCSI_PARAM_IMM_DATA_EN:
|
||||||
sscanf(buf, "%d", &session->imm_data_en);
|
sscanf(buf, "%d", &session->imm_data_en);
|
||||||
|
|
|
@ -1170,6 +1170,24 @@ void iscsi_tcp_r2tpool_free(struct iscsi_session *session)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free);
|
EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free);
|
||||||
|
|
||||||
|
int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf)
|
||||||
|
{
|
||||||
|
struct iscsi_session *session = conn->session;
|
||||||
|
unsigned short r2ts = 0;
|
||||||
|
|
||||||
|
sscanf(buf, "%hu", &r2ts);
|
||||||
|
if (session->max_r2t == r2ts)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!r2ts || !is_power_of_2(r2ts))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
session->max_r2t = r2ts;
|
||||||
|
iscsi_tcp_r2tpool_free(session);
|
||||||
|
return iscsi_tcp_r2tpool_alloc(session);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(iscsi_tcp_set_max_r2t);
|
||||||
|
|
||||||
void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
|
void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
|
||||||
struct iscsi_stats *stats)
|
struct iscsi_stats *stats)
|
||||||
{
|
{
|
||||||
|
|
|
@ -268,7 +268,7 @@ struct iscsi_session {
|
||||||
int lu_reset_timeout;
|
int lu_reset_timeout;
|
||||||
int tgt_reset_timeout;
|
int tgt_reset_timeout;
|
||||||
int initial_r2t_en;
|
int initial_r2t_en;
|
||||||
unsigned max_r2t;
|
unsigned short max_r2t;
|
||||||
int imm_data_en;
|
int imm_data_en;
|
||||||
unsigned first_burst;
|
unsigned first_burst;
|
||||||
unsigned max_burst;
|
unsigned max_burst;
|
||||||
|
|
|
@ -128,7 +128,7 @@ extern void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn);
|
||||||
/* misc helpers */
|
/* misc helpers */
|
||||||
extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session);
|
extern int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session);
|
||||||
extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session);
|
extern void iscsi_tcp_r2tpool_free(struct iscsi_session *session);
|
||||||
|
extern int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf);
|
||||||
extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
|
extern void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn,
|
||||||
struct iscsi_stats *stats);
|
struct iscsi_stats *stats);
|
||||||
#endif /* LIBISCSI_TCP_H */
|
#endif /* LIBISCSI_TCP_H */
|
||||||
|
|
Loading…
Reference in New Issue