@@ -44,6 +44,10 @@ struct inet_diag_entry {
44
44
u16 dport ;
45
45
u16 family ;
46
46
u16 userlocks ;
47
+ #if IS_ENABLED (CONFIG_IPV6 )
48
+ struct in6_addr saddr_storage ; /* for IPv4-mapped-IPv6 addresses */
49
+ struct in6_addr daddr_storage ; /* for IPv4-mapped-IPv6 addresses */
50
+ #endif
47
51
};
48
52
49
53
static DEFINE_MUTEX (inet_diag_table_mutex );
@@ -428,25 +432,31 @@ static int inet_diag_bc_run(const struct nlattr *_bc,
428
432
break ;
429
433
}
430
434
431
- if (cond -> prefix_len == 0 )
432
- break ;
433
-
434
435
if (op -> code == INET_DIAG_BC_S_COND )
435
436
addr = entry -> saddr ;
436
437
else
437
438
addr = entry -> daddr ;
438
439
440
+ if (cond -> family != AF_UNSPEC &&
441
+ cond -> family != entry -> family ) {
442
+ if (entry -> family == AF_INET6 &&
443
+ cond -> family == AF_INET ) {
444
+ if (addr [0 ] == 0 && addr [1 ] == 0 &&
445
+ addr [2 ] == htonl (0xffff ) &&
446
+ bitstring_match (addr + 3 ,
447
+ cond -> addr ,
448
+ cond -> prefix_len ))
449
+ break ;
450
+ }
451
+ yes = 0 ;
452
+ break ;
453
+ }
454
+
455
+ if (cond -> prefix_len == 0 )
456
+ break ;
439
457
if (bitstring_match (addr , cond -> addr ,
440
458
cond -> prefix_len ))
441
459
break ;
442
- if (entry -> family == AF_INET6 &&
443
- cond -> family == AF_INET ) {
444
- if (addr [0 ] == 0 && addr [1 ] == 0 &&
445
- addr [2 ] == htonl (0xffff ) &&
446
- bitstring_match (addr + 3 , cond -> addr ,
447
- cond -> prefix_len ))
448
- break ;
449
- }
450
460
yes = 0 ;
451
461
break ;
452
462
}
@@ -509,36 +519,95 @@ static int valid_cc(const void *bc, int len, int cc)
509
519
return 0 ;
510
520
}
511
521
522
+ /* Validate an inet_diag_hostcond. */
523
+ static bool valid_hostcond (const struct inet_diag_bc_op * op , int len ,
524
+ int * min_len )
525
+ {
526
+ int addr_len ;
527
+ struct inet_diag_hostcond * cond ;
528
+
529
+ /* Check hostcond space. */
530
+ * min_len += sizeof (struct inet_diag_hostcond );
531
+ if (len < * min_len )
532
+ return false;
533
+ cond = (struct inet_diag_hostcond * )(op + 1 );
534
+
535
+ /* Check address family and address length. */
536
+ switch (cond -> family ) {
537
+ case AF_UNSPEC :
538
+ addr_len = 0 ;
539
+ break ;
540
+ case AF_INET :
541
+ addr_len = sizeof (struct in_addr );
542
+ break ;
543
+ case AF_INET6 :
544
+ addr_len = sizeof (struct in6_addr );
545
+ break ;
546
+ default :
547
+ return false;
548
+ }
549
+ * min_len += addr_len ;
550
+ if (len < * min_len )
551
+ return false;
552
+
553
+ /* Check prefix length (in bits) vs address length (in bytes). */
554
+ if (cond -> prefix_len > 8 * addr_len )
555
+ return false;
556
+
557
+ return true;
558
+ }
559
+
560
+ /* Validate a port comparison operator. */
561
+ static inline bool valid_port_comparison (const struct inet_diag_bc_op * op ,
562
+ int len , int * min_len )
563
+ {
564
+ /* Port comparisons put the port in a follow-on inet_diag_bc_op. */
565
+ * min_len += sizeof (struct inet_diag_bc_op );
566
+ if (len < * min_len )
567
+ return false;
568
+ return true;
569
+ }
570
+
512
571
static int inet_diag_bc_audit (const void * bytecode , int bytecode_len )
513
572
{
514
573
const void * bc = bytecode ;
515
574
int len = bytecode_len ;
516
575
517
576
while (len > 0 ) {
518
577
const struct inet_diag_bc_op * op = bc ;
578
+ int min_len = sizeof (struct inet_diag_bc_op );
519
579
520
580
//printk("BC: %d %d %d {%d} / %d\n", op->code, op->yes, op->no, op[1].no, len);
521
581
switch (op -> code ) {
522
- case INET_DIAG_BC_AUTO :
523
582
case INET_DIAG_BC_S_COND :
524
583
case INET_DIAG_BC_D_COND :
584
+ if (!valid_hostcond (bc , len , & min_len ))
585
+ return - EINVAL ;
586
+ break ;
525
587
case INET_DIAG_BC_S_GE :
526
588
case INET_DIAG_BC_S_LE :
527
589
case INET_DIAG_BC_D_GE :
528
590
case INET_DIAG_BC_D_LE :
529
- case INET_DIAG_BC_JMP :
530
- if (op -> no < 4 || op -> no > len + 4 || op -> no & 3 )
531
- return - EINVAL ;
532
- if (op -> no < len &&
533
- !valid_cc (bytecode , bytecode_len , len - op -> no ))
591
+ if (!valid_port_comparison (bc , len , & min_len ))
534
592
return - EINVAL ;
535
593
break ;
594
+ case INET_DIAG_BC_AUTO :
595
+ case INET_DIAG_BC_JMP :
536
596
case INET_DIAG_BC_NOP :
537
597
break ;
538
598
default :
539
599
return - EINVAL ;
540
600
}
541
- if (op -> yes < 4 || op -> yes > len + 4 || op -> yes & 3 )
601
+
602
+ if (op -> code != INET_DIAG_BC_NOP ) {
603
+ if (op -> no < min_len || op -> no > len + 4 || op -> no & 3 )
604
+ return - EINVAL ;
605
+ if (op -> no < len &&
606
+ !valid_cc (bytecode , bytecode_len , len - op -> no ))
607
+ return - EINVAL ;
608
+ }
609
+
610
+ if (op -> yes < min_len || op -> yes > len + 4 || op -> yes & 3 )
542
611
return - EINVAL ;
543
612
bc += op -> yes ;
544
613
len -= op -> yes ;
@@ -596,6 +665,36 @@ static int inet_twsk_diag_dump(struct inet_timewait_sock *tw,
596
665
cb -> nlh -> nlmsg_seq , NLM_F_MULTI , cb -> nlh );
597
666
}
598
667
668
+ /* Get the IPv4, IPv6, or IPv4-mapped-IPv6 local and remote addresses
669
+ * from a request_sock. For IPv4-mapped-IPv6 we must map IPv4 to IPv6.
670
+ */
671
+ static inline void inet_diag_req_addrs (const struct sock * sk ,
672
+ const struct request_sock * req ,
673
+ struct inet_diag_entry * entry )
674
+ {
675
+ struct inet_request_sock * ireq = inet_rsk (req );
676
+
677
+ #if IS_ENABLED (CONFIG_IPV6 )
678
+ if (sk -> sk_family == AF_INET6 ) {
679
+ if (req -> rsk_ops -> family == AF_INET6 ) {
680
+ entry -> saddr = inet6_rsk (req )-> loc_addr .s6_addr32 ;
681
+ entry -> daddr = inet6_rsk (req )-> rmt_addr .s6_addr32 ;
682
+ } else if (req -> rsk_ops -> family == AF_INET ) {
683
+ ipv6_addr_set_v4mapped (ireq -> loc_addr ,
684
+ & entry -> saddr_storage );
685
+ ipv6_addr_set_v4mapped (ireq -> rmt_addr ,
686
+ & entry -> daddr_storage );
687
+ entry -> saddr = entry -> saddr_storage .s6_addr32 ;
688
+ entry -> daddr = entry -> daddr_storage .s6_addr32 ;
689
+ }
690
+ } else
691
+ #endif
692
+ {
693
+ entry -> saddr = & ireq -> loc_addr ;
694
+ entry -> daddr = & ireq -> rmt_addr ;
695
+ }
696
+ }
697
+
599
698
static int inet_diag_fill_req (struct sk_buff * skb , struct sock * sk ,
600
699
struct request_sock * req ,
601
700
struct user_namespace * user_ns ,
@@ -637,8 +736,10 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
637
736
r -> idiag_inode = 0 ;
638
737
#if IS_ENABLED (CONFIG_IPV6 )
639
738
if (r -> idiag_family == AF_INET6 ) {
640
- * (struct in6_addr * )r -> id .idiag_src = inet6_rsk (req )-> loc_addr ;
641
- * (struct in6_addr * )r -> id .idiag_dst = inet6_rsk (req )-> rmt_addr ;
739
+ struct inet_diag_entry entry ;
740
+ inet_diag_req_addrs (sk , req , & entry );
741
+ memcpy (r -> id .idiag_src , entry .saddr , sizeof (struct in6_addr ));
742
+ memcpy (r -> id .idiag_dst , entry .daddr , sizeof (struct in6_addr ));
642
743
}
643
744
#endif
644
745
@@ -691,18 +792,7 @@ static int inet_diag_dump_reqs(struct sk_buff *skb, struct sock *sk,
691
792
continue ;
692
793
693
794
if (bc ) {
694
- entry .saddr =
695
- #if IS_ENABLED (CONFIG_IPV6 )
696
- (entry .family == AF_INET6 ) ?
697
- inet6_rsk (req )-> loc_addr .s6_addr32 :
698
- #endif
699
- & ireq -> loc_addr ;
700
- entry .daddr =
701
- #if IS_ENABLED (CONFIG_IPV6 )
702
- (entry .family == AF_INET6 ) ?
703
- inet6_rsk (req )-> rmt_addr .s6_addr32 :
704
- #endif
705
- & ireq -> rmt_addr ;
795
+ inet_diag_req_addrs (sk , req , & entry );
706
796
entry .dport = ntohs (ireq -> rmt_port );
707
797
708
798
if (!inet_diag_bc_run (bc , & entry ))
0 commit comments