SCTP: Fix to encode PROTOCOL VIOLATION error cause correctly

PROTOCOL VIOLATION error cause in ABORT is bad encode when make abort
chunk. When SCTP encode ABORT chunk with PROTOCOL VIOLATION error cause,
it just add the error messages to PROTOCOL VIOLATION error cause, the
rest four bytes(struct sctp_paramhdr) is just add to the chunk, not
change the length of error cause. This cause the ABORT chunk to be a bad
format. The chunk is like this:

ABORT chunk
Chunk type: ABORT (6)
Chunk flags: 0x00
Chunk length: 72 (*1)
Protocol violation cause
Cause code: Protocol violation (0x000d)
Cause length: 62 (*2)
Cause information: 5468652063756D756C61746976652074736E2061636B2062...
Cause padding: 0000
[Needless] 00030010
Chunk Length(*1) = 72 but Cause length(*2) only 62, not include the
extend 4 bytes.
((72 - sizeof(chunk_hdr)) = 68) != (62 +3) / 4 * 4

Signed-off-by: Wei Yongjun <yjwei@cn.fujitsu.com>
Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>

authored by Wei Yongjun and committed by Vlad Yasevich 00f1c2df 8d614ade

+56 -24
+1 -1
include/net/sctp/sm.h
··· 214 214 const struct sctp_chunk *); 215 215 struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *, 216 216 const struct sctp_chunk *); 217 - void sctp_init_cause(struct sctp_chunk *, __be16 cause, const void *, size_t); 217 + void sctp_init_cause(struct sctp_chunk *, __be16 cause, size_t); 218 218 struct sctp_chunk *sctp_make_abort(const struct sctp_association *, 219 219 const struct sctp_chunk *, 220 220 const size_t hint);
+1
include/net/sctp/structs.h
··· 726 726 struct iovec *data); 727 727 void sctp_chunk_free(struct sctp_chunk *); 728 728 void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data); 729 + void *sctp_addto_param(struct sctp_chunk *, int len, const void *data); 729 730 struct sctp_chunk *sctp_chunkify(struct sk_buff *, 730 731 const struct sctp_association *, 731 732 struct sock *);
+52 -21
net/sctp/sm_make_chunk.c
··· 110 110 * abort chunk. 111 111 */ 112 112 void sctp_init_cause(struct sctp_chunk *chunk, __be16 cause_code, 113 - const void *payload, size_t paylen) 113 + size_t paylen) 114 114 { 115 115 sctp_errhdr_t err; 116 116 __u16 len; ··· 120 120 len = sizeof(sctp_errhdr_t) + paylen; 121 121 err.length = htons(len); 122 122 chunk->subh.err_hdr = sctp_addto_chunk(chunk, sizeof(sctp_errhdr_t), &err); 123 - sctp_addto_chunk(chunk, paylen, payload); 124 123 } 125 124 126 125 /* 3.3.2 Initiation (INIT) (1) ··· 779 780 780 781 /* Put the tsn back into network byte order. */ 781 782 payload = htonl(tsn); 782 - sctp_init_cause(retval, SCTP_ERROR_NO_DATA, (const void *)&payload, 783 - sizeof(payload)); 783 + sctp_init_cause(retval, SCTP_ERROR_NO_DATA, sizeof(payload)); 784 + sctp_addto_chunk(retval, sizeof(payload), (const void *)&payload); 784 785 785 786 /* RFC 2960 6.4 Multi-homed SCTP Endpoints 786 787 * ··· 822 823 goto err_copy; 823 824 } 824 825 825 - sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, payload, paylen); 826 + sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, paylen); 827 + sctp_addto_chunk(retval, paylen, payload); 826 828 827 829 if (paylen) 828 830 kfree(payload); ··· 850 850 struct sctp_paramhdr phdr; 851 851 852 852 retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen 853 - + sizeof(sctp_chunkhdr_t)); 853 + + sizeof(sctp_paramhdr_t)); 854 854 if (!retval) 855 855 goto end; 856 856 857 - sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen); 857 + sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, paylen 858 + + sizeof(sctp_paramhdr_t)); 858 859 859 860 phdr.type = htons(chunk->chunk_hdr->type); 860 861 phdr.length = chunk->chunk_hdr->length; 861 - sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr); 862 + sctp_addto_chunk(retval, paylen, payload); 863 + sctp_addto_param(retval, sizeof(sctp_paramhdr_t), &phdr); 862 864 863 865 end: 864 866 return retval; ··· 957 955 if (!retval) 958 956 goto nodata; 959 957 960 - sctp_init_cause(retval, cause_code, payload, paylen); 958 + sctp_init_cause(retval, cause_code, paylen); 959 + sctp_addto_chunk(retval, paylen, payload); 961 960 962 961 nodata: 963 962 return retval; ··· 1141 1138 1142 1139 /* Adjust the chunk length field. */ 1143 1140 chunk->chunk_hdr->length = htons(chunklen + padlen + len); 1141 + chunk->chunk_end = skb_tail_pointer(chunk->skb); 1142 + 1143 + return target; 1144 + } 1145 + 1146 + /* Append bytes to the end of a parameter. Will panic if chunk is not big 1147 + * enough. 1148 + */ 1149 + void *sctp_addto_param(struct sctp_chunk *chunk, int len, const void *data) 1150 + { 1151 + void *target; 1152 + int chunklen = ntohs(chunk->chunk_hdr->length); 1153 + 1154 + target = skb_put(chunk->skb, len); 1155 + 1156 + memcpy(target, data, len); 1157 + 1158 + /* Adjust the chunk length field. */ 1159 + chunk->chunk_hdr->length = htons(chunklen + len); 1144 1160 chunk->chunk_end = skb_tail_pointer(chunk->skb); 1145 1161 1146 1162 return target; ··· 1499 1477 __be32 n = htonl(usecs); 1500 1478 1501 1479 sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE, 1502 - &n, sizeof(n)); 1480 + sizeof(n)); 1481 + sctp_addto_chunk(*errp, sizeof(n), &n); 1503 1482 *error = -SCTP_IERROR_STALE_COOKIE; 1504 1483 } else 1505 1484 *error = -SCTP_IERROR_NOMEM; ··· 1590 1567 report.num_missing = htonl(1); 1591 1568 report.type = paramtype; 1592 1569 sctp_init_cause(*errp, SCTP_ERROR_MISS_PARAM, 1593 - &report, sizeof(report)); 1570 + sizeof(report)); 1571 + sctp_addto_chunk(*errp, sizeof(report), &report); 1594 1572 } 1595 1573 1596 1574 /* Stop processing this chunk. */ ··· 1609 1585 *errp = sctp_make_op_error_space(asoc, chunk, 0); 1610 1586 1611 1587 if (*errp) 1612 - sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0); 1588 + sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, 0); 1613 1589 1614 1590 /* Stop processing this chunk. */ 1615 1591 return 0; ··· 1630 1606 *errp = sctp_make_op_error_space(asoc, chunk, payload_len); 1631 1607 1632 1608 if (*errp) { 1633 - sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error, 1634 - sizeof(error)); 1635 - sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param); 1609 + sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, 1610 + sizeof(error) + sizeof(sctp_paramhdr_t)); 1611 + sctp_addto_chunk(*errp, sizeof(error), error); 1612 + sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param); 1636 1613 } 1637 1614 1638 1615 return 0; ··· 1654 1629 if (!*errp) 1655 1630 *errp = sctp_make_op_error_space(asoc, chunk, len); 1656 1631 1657 - if (*errp) 1658 - sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, 1659 - param.v, len); 1632 + if (*errp) { 1633 + sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED, len); 1634 + sctp_addto_chunk(*errp, len, param.v); 1635 + } 1660 1636 1661 1637 /* Stop processing this chunk. */ 1662 1638 return 0; ··· 1709 1683 *errp = sctp_make_op_error_space(asoc, chunk, 1710 1684 ntohs(chunk->chunk_hdr->length)); 1711 1685 1712 - if (*errp) 1686 + if (*errp) { 1713 1687 sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, 1714 - param.v, 1715 1688 WORD_ROUND(ntohs(param.p->length))); 1689 + sctp_addto_chunk(*errp, 1690 + WORD_ROUND(ntohs(param.p->length)), 1691 + param.v); 1692 + } 1716 1693 1717 1694 break; 1718 1695 case SCTP_PARAM_ACTION_SKIP: ··· 1730 1701 1731 1702 if (*errp) { 1732 1703 sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM, 1733 - param.v, 1734 1704 WORD_ROUND(ntohs(param.p->length))); 1705 + sctp_addto_chunk(*errp, 1706 + WORD_ROUND(ntohs(param.p->length)), 1707 + param.v); 1735 1708 } else { 1736 1709 /* If there is no memory for generating the ERROR 1737 1710 * report as specified, an ABORT will be triggered
+2 -2
net/sctp/sm_statefuns.c
··· 3362 3362 abort = sctp_make_abort(asoc, asconf_ack, 3363 3363 sizeof(sctp_errhdr_t)); 3364 3364 if (abort) { 3365 - sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, NULL, 0); 3365 + sctp_init_cause(abort, SCTP_ERROR_ASCONF_ACK, 0); 3366 3366 sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, 3367 3367 SCTP_CHUNK(abort)); 3368 3368 } ··· 3392 3392 abort = sctp_make_abort(asoc, asconf_ack, 3393 3393 sizeof(sctp_errhdr_t)); 3394 3394 if (abort) { 3395 - sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, NULL, 0); 3395 + sctp_init_cause(abort, SCTP_ERROR_RSRC_LOW, 0); 3396 3396 sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, 3397 3397 SCTP_CHUNK(abort)); 3398 3398 }