@@ -643,46 +643,57 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
643643int
644644slhc_remember (struct slcompress * comp , unsigned char * icp , int isize )
645645{
646- struct cstate * cs ;
647- unsigned ihl ;
648-
646+ const struct tcphdr * th ;
649647 unsigned char index ;
648+ struct iphdr * iph ;
649+ struct cstate * cs ;
650+ unsigned int ihl ;
650651
651- if (isize < 20 ) {
652- /* The packet is shorter than a legal IP header */
652+ /* The packet is shorter than a legal IP header.
653+ * Also make sure isize is positive.
654+ */
655+ if (isize < (int )sizeof (struct iphdr )) {
656+ runt :
653657 comp -> sls_i_runt ++ ;
654- return slhc_toss ( comp );
658+ return slhc_toss (comp );
655659 }
660+ iph = (struct iphdr * )icp ;
656661 /* Peek at the IP header's IHL field to find its length */
657- ihl = icp [0 ] & 0xf ;
658- if (ihl < 20 / 4 ){
659- /* The IP header length field is too small */
660- comp -> sls_i_runt ++ ;
661- return slhc_toss ( comp );
662- }
663- index = icp [9 ];
664- icp [9 ] = IPPROTO_TCP ;
662+ ihl = iph -> ihl ;
663+ /* The IP header length field is too small,
664+ * or packet is shorter than the IP header followed
665+ * by minimal tcp header.
666+ */
667+ if (ihl < 5 || isize < ihl * 4 + sizeof (struct tcphdr ))
668+ goto runt ;
669+
670+ index = iph -> protocol ;
671+ iph -> protocol = IPPROTO_TCP ;
665672
666673 if (ip_fast_csum (icp , ihl )) {
667674 /* Bad IP header checksum; discard */
668675 comp -> sls_i_badcheck ++ ;
669- return slhc_toss ( comp );
676+ return slhc_toss (comp );
670677 }
671- if (index > comp -> rslot_limit ) {
678+ if (index > comp -> rslot_limit ) {
672679 comp -> sls_i_error ++ ;
673680 return slhc_toss (comp );
674681 }
675-
682+ th = (struct tcphdr * )(icp + ihl * 4 );
683+ if (th -> doff < sizeof (struct tcphdr ) / 4 )
684+ goto runt ;
685+ if (isize < ihl * 4 + th -> doff * 4 )
686+ goto runt ;
676687 /* Update local state */
677688 cs = & comp -> rstate [comp -> recv_current = index ];
678689 comp -> flags &=~ SLF_TOSS ;
679- memcpy (& cs -> cs_ip ,icp , 20 );
680- memcpy (& cs -> cs_tcp ,icp + ihl * 4 , 20 );
690+ memcpy (& cs -> cs_ip , iph , sizeof ( * iph ) );
691+ memcpy (& cs -> cs_tcp , th , sizeof ( * th ) );
681692 if (ihl > 5 )
682- memcpy (cs -> cs_ipopt , icp + sizeof ( struct iphdr ) , (ihl - 5 ) * 4 );
683- if (cs -> cs_tcp . doff > 5 )
684- memcpy (cs -> cs_tcpopt , icp + ihl * 4 + sizeof ( struct tcphdr ) , (cs -> cs_tcp . doff - 5 ) * 4 );
685- cs -> cs_hsize = ihl * 2 + cs -> cs_tcp . doff * 2 ;
693+ memcpy (cs -> cs_ipopt , & iph [ 1 ] , (ihl - 5 ) * 4 );
694+ if (th -> doff > 5 )
695+ memcpy (cs -> cs_tcpopt , & th [ 1 ] , (th -> doff - 5 ) * 4 );
696+ cs -> cs_hsize = ihl * 2 + th -> doff * 2 ;
686697 cs -> initialized = true;
687698 /* Put headers back on packet
688699 * Neither header checksum is recalculated
0 commit comments