@@ -415,6 +415,47 @@ int xt_check_match(struct xt_mtchk_param *par,
415415}
416416EXPORT_SYMBOL_GPL (xt_check_match );
417417
418+ /** xt_check_entry_match - check that matches end before start of target
419+ *
420+ * @match: beginning of xt_entry_match
421+ * @target: beginning of this rules target (alleged end of matches)
422+ * @alignment: alignment requirement of match structures
423+ *
424+ * Validates that all matches add up to the beginning of the target,
425+ * and that each match covers at least the base structure size.
426+ *
427+ * Return: 0 on success, negative errno on failure.
428+ */
429+ static int xt_check_entry_match (const char * match , const char * target ,
430+ const size_t alignment )
431+ {
432+ const struct xt_entry_match * pos ;
433+ int length = target - match ;
434+
435+ if (length == 0 ) /* no matches */
436+ return 0 ;
437+
438+ pos = (struct xt_entry_match * )match ;
439+ do {
440+ if ((unsigned long )pos % alignment )
441+ return - EINVAL ;
442+
443+ if (length < (int )sizeof (struct xt_entry_match ))
444+ return - EINVAL ;
445+
446+ if (pos -> u .match_size < sizeof (struct xt_entry_match ))
447+ return - EINVAL ;
448+
449+ if (pos -> u .match_size > length )
450+ return - EINVAL ;
451+
452+ length -= pos -> u .match_size ;
453+ pos = ((void * )((char * )(pos ) + (pos )-> u .match_size ));
454+ } while (length > 0 );
455+
456+ return 0 ;
457+ }
458+
418459#ifdef CONFIG_COMPAT
419460int xt_compat_add_offset (u_int8_t af , unsigned int offset , int delta )
420461{
@@ -570,7 +611,14 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,
570611 target_offset + sizeof (struct compat_xt_standard_target ) != next_offset )
571612 return - EINVAL ;
572613
573- return 0 ;
614+ /* compat_xt_entry match has less strict aligment requirements,
615+ * otherwise they are identical. In case of padding differences
616+ * we need to add compat version of xt_check_entry_match.
617+ */
618+ BUILD_BUG_ON (sizeof (struct compat_xt_entry_match ) != sizeof (struct xt_entry_match ));
619+
620+ return xt_check_entry_match (elems , base + target_offset ,
621+ __alignof__(struct compat_xt_entry_match ));
574622}
575623EXPORT_SYMBOL (xt_compat_check_entry_offsets );
576624#endif /* CONFIG_COMPAT */
@@ -583,17 +631,39 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets);
583631 * @target_offset: the arp/ip/ip6_t->target_offset
584632 * @next_offset: the arp/ip/ip6_t->next_offset
585633 *
586- * validates that target_offset and next_offset are sane.
587- * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version .
634+ * validates that target_offset and next_offset are sane and that all
635+ * match sizes (if any) align with the target offset .
588636 *
589637 * This function does not validate the targets or matches themselves, it
590- * only tests that all the offsets and sizes are correct.
638+ * only tests that all the offsets and sizes are correct, that all
639+ * match structures are aligned, and that the last structure ends where
640+ * the target structure begins.
641+ *
642+ * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version.
591643 *
592644 * The arp/ip/ip6t_entry structure @base must have passed following tests:
593645 * - it must point to a valid memory location
594646 * - base to base + next_offset must be accessible, i.e. not exceed allocated
595647 * length.
596648 *
649+ * A well-formed entry looks like this:
650+ *
651+ * ip(6)t_entry match [mtdata] match [mtdata] target [tgdata] ip(6)t_entry
652+ * e->elems[]-----' | |
653+ * matchsize | |
654+ * matchsize | |
655+ * | |
656+ * target_offset---------------------------------' |
657+ * next_offset---------------------------------------------------'
658+ *
659+ * elems[]: flexible array member at end of ip(6)/arpt_entry struct.
660+ * This is where matches (if any) and the target reside.
661+ * target_offset: beginning of target.
662+ * next_offset: start of the next rule; also: size of this rule.
663+ * Since targets have a minimum size, target_offset + minlen <= next_offset.
664+ *
665+ * Every match stores its size, sum of sizes must not exceed target_offset.
666+ *
597667 * Return: 0 on success, negative errno on failure.
598668 */
599669int xt_check_entry_offsets (const void * base ,
@@ -623,7 +693,8 @@ int xt_check_entry_offsets(const void *base,
623693 target_offset + sizeof (struct xt_standard_target ) != next_offset )
624694 return - EINVAL ;
625695
626- return 0 ;
696+ return xt_check_entry_match (elems , base + target_offset ,
697+ __alignof__(struct xt_entry_match ));
627698}
628699EXPORT_SYMBOL (xt_check_entry_offsets );
629700
0 commit comments