Skip to content

Commit

Permalink
sctp: Fix kernel panic while process protocol violation parameter
Browse files Browse the repository at this point in the history
Since call to function sctp_sf_abort_violation() need paramter 'arg' with
'struct sctp_chunk' type, it will read the chunk type and chunk length from
the chunk_hdr member of chunk. But call to sctp_sf_violation_paramlen()
always with 'struct sctp_paramhdr' type's parameter, it will be passed to
sctp_sf_abort_violation(). This may cause kernel panic.

   sctp_sf_violation_paramlen()
     |-- sctp_sf_abort_violation()
        |-- sctp_make_abort_violation()

This patch fixed this problem. This patch also fix two place which called
sctp_sf_violation_paramlen() with wrong paramter type.

Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Wei Yongjun authored and davem330 committed Sep 30, 2008
1 parent 8b122ef commit ba01667
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 24 deletions.
3 changes: 3 additions & 0 deletions include/net/sctp/sm.h
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ struct sctp_chunk *sctp_make_abort_violation(const struct sctp_association *,
const struct sctp_chunk *,
const __u8 *,
const size_t );
struct sctp_chunk *sctp_make_violation_paramlen(const struct sctp_association *,
const struct sctp_chunk *,
struct sctp_paramhdr *);
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *,
const struct sctp_transport *,
const void *payload,
Expand Down
37 changes: 24 additions & 13 deletions net/sctp/sm_make_chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1012,6 +1012,29 @@ struct sctp_chunk *sctp_make_abort_violation(
return retval;
}

struct sctp_chunk *sctp_make_violation_paramlen(
const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
struct sctp_paramhdr *param)
{
struct sctp_chunk *retval;
static const char error[] = "The following parameter had invalid length:";
size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t) +
sizeof(sctp_paramhdr_t);

retval = sctp_make_abort(asoc, chunk, payload_len);
if (!retval)
goto nodata;

sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION,
sizeof(error) + sizeof(sctp_paramhdr_t));
sctp_addto_chunk(retval, sizeof(error), error);
sctp_addto_param(retval, sizeof(sctp_paramhdr_t), param);

nodata:
return retval;
}

/* Make a HEARTBEAT chunk. */
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
const struct sctp_transport *transport,
Expand Down Expand Up @@ -1782,26 +1805,14 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
struct sctp_chunk **errp)
{
static const char error[] = "The following parameter had invalid length:";
size_t payload_len = WORD_ROUND(sizeof(error)) +
sizeof(sctp_paramhdr_t);


/* This is a fatal error. Any accumulated non-fatal errors are
* not reported.
*/
if (*errp)
sctp_chunk_free(*errp);

/* Create an error chunk and fill it in with our payload. */
*errp = sctp_make_op_error_space(asoc, chunk, payload_len);

if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION,
sizeof(error) + sizeof(sctp_paramhdr_t));
sctp_addto_chunk(*errp, sizeof(error), error);
sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param);
}
*errp = sctp_make_violation_paramlen(asoc, chunk, param);

return 0;
}
Expand Down
48 changes: 37 additions & 11 deletions net/sctp/sm_statefuns.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
void *arg, void *ext,
sctp_cmd_seq_t *commands);

static sctp_disposition_t sctp_sf_violation_ctsn(
Expand Down Expand Up @@ -3425,16 +3425,16 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
addr_param = (union sctp_addr_param *)hdr->params;
length = ntohs(addr_param->p.length);
if (length < sizeof(sctp_paramhdr_t))
return sctp_sf_violation_paramlen(ep, asoc, type,
return sctp_sf_violation_paramlen(ep, asoc, type, arg,
(void *)addr_param, commands);

/* Verify the ASCONF chunk before processing it. */
if (!sctp_verify_asconf(asoc,
(sctp_paramhdr_t *)((void *)addr_param + length),
(void *)chunk->chunk_end,
&err_param))
return sctp_sf_violation_paramlen(ep, asoc, type,
(void *)&err_param, commands);
return sctp_sf_violation_paramlen(ep, asoc, type, arg,
(void *)err_param, commands);

/* ADDIP 5.2 E1) Compare the value of the serial number to the value
* the endpoint stored in a new association variable
Expand Down Expand Up @@ -3542,8 +3542,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
(sctp_paramhdr_t *)addip_hdr->params,
(void *)asconf_ack->chunk_end,
&err_param))
return sctp_sf_violation_paramlen(ep, asoc, type,
(void *)&err_param, commands);
return sctp_sf_violation_paramlen(ep, asoc, type, arg,
(void *)err_param, commands);

if (last_asconf) {
addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr;
Expand Down Expand Up @@ -4240,12 +4240,38 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands) {
static const char err_str[] = "The following parameter had invalid length:";
void *arg, void *ext,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *chunk = arg;
struct sctp_paramhdr *param = ext;
struct sctp_chunk *abort = NULL;

return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
sizeof(err_str));
if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
goto discard;

/* Make the abort chunk. */
abort = sctp_make_violation_paramlen(asoc, chunk, param);
if (!abort)
goto nomem;

sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);

sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
SCTP_ERROR(ECONNABORTED));
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);

discard:
sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);

SCTP_INC_STATS(SCTP_MIB_ABORTEDS);

return SCTP_DISPOSITION_ABORT;
nomem:
return SCTP_DISPOSITION_NOMEM;
}

/* Handle a protocol violation when the peer trying to advance the
Expand Down

0 comments on commit ba01667

Please sign in to comment.