@@ -646,6 +646,67 @@ int aa_unix_peer_perm(const struct cred *subj_cred,
646
646
peer_label );
647
647
}
648
648
649
+ /* sk_plabel for comparison only */
650
+ static void update_sk_ctx (struct sock * sk , struct aa_label * label ,
651
+ struct aa_label * plabel )
652
+ {
653
+ struct aa_label * l , * old ;
654
+ struct aa_sk_ctx * ctx = aa_sock (sk );
655
+ bool update_sk ;
656
+
657
+ rcu_read_lock ();
658
+ update_sk = (plabel &&
659
+ (plabel != rcu_access_pointer (ctx -> peer_lastupdate ) ||
660
+ !aa_label_is_subset (plabel , rcu_dereference (ctx -> peer )))) ||
661
+ !__aa_subj_label_is_cached (label , rcu_dereference (ctx -> label ));
662
+ rcu_read_unlock ();
663
+ if (!update_sk )
664
+ return ;
665
+
666
+ spin_lock (& unix_sk (sk )-> lock );
667
+ old = rcu_dereference_protected (ctx -> label ,
668
+ lockdep_is_held (& unix_sk (sk )-> lock ));
669
+ l = aa_label_merge (old , label , GFP_ATOMIC );
670
+ if (l ) {
671
+ if (l != old ) {
672
+ rcu_assign_pointer (ctx -> label , l );
673
+ aa_put_label (old );
674
+ } else
675
+ aa_put_label (l );
676
+ }
677
+ if (plabel && rcu_access_pointer (ctx -> peer_lastupdate ) != plabel ) {
678
+ old = rcu_dereference_protected (ctx -> peer , lockdep_is_held (& unix_sk (sk )-> lock ));
679
+
680
+ if (old == plabel ) {
681
+ rcu_assign_pointer (ctx -> peer_lastupdate , plabel );
682
+ } else if (aa_label_is_subset (plabel , old )) {
683
+ rcu_assign_pointer (ctx -> peer_lastupdate , plabel );
684
+ rcu_assign_pointer (ctx -> peer , aa_get_label (plabel ));
685
+ aa_put_label (old );
686
+ } /* else race or a subset - don't update */
687
+ }
688
+ spin_unlock (& unix_sk (sk )-> lock );
689
+ }
690
+
691
+ static void update_peer_ctx (struct sock * sk , struct aa_sk_ctx * ctx ,
692
+ struct aa_label * label )
693
+ {
694
+ struct aa_label * l , * old ;
695
+
696
+ spin_lock (& unix_sk (sk )-> lock );
697
+ old = rcu_dereference_protected (ctx -> peer ,
698
+ lockdep_is_held (& unix_sk (sk )-> lock ));
699
+ l = aa_label_merge (old , label , GFP_ATOMIC );
700
+ if (l ) {
701
+ if (l != old ) {
702
+ rcu_assign_pointer (ctx -> peer , l );
703
+ aa_put_label (old );
704
+ } else
705
+ aa_put_label (l );
706
+ }
707
+ spin_unlock (& unix_sk (sk )-> lock );
708
+ }
709
+
649
710
/* This fn is only checked if something has changed in the security
650
711
* boundaries. Otherwise cached info off file is sufficient
651
712
*/
@@ -655,6 +716,7 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
655
716
struct socket * sock = (struct socket * ) file -> private_data ;
656
717
struct sockaddr_un * addr , * peer_addr ;
657
718
int addrlen , peer_addrlen ;
719
+ struct aa_label * plabel = NULL ;
658
720
struct sock * peer_sk = NULL ;
659
721
u32 sk_req = request & ~NET_PEER_MASK ;
660
722
struct path path ;
@@ -666,7 +728,6 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
666
728
AA_BUG (!sock -> sk );
667
729
AA_BUG (sock -> sk -> sk_family != PF_UNIX );
668
730
669
- /* TODO: update sock label with new task label */
670
731
/* investigate only using lock via unix_peer_get()
671
732
* addr only needs the memory barrier, but need to investigate
672
733
* path
@@ -701,8 +762,12 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
701
762
unix_fs_perm (op , request , subj_cred , label ,
702
763
is_unix_fs (peer_sk ) ? & peer_path : NULL ));
703
764
} else if (!is_sk_fs ) {
765
+ struct aa_label * plabel ;
704
766
struct aa_sk_ctx * pctx = aa_sock (peer_sk );
705
767
768
+ rcu_read_lock ();
769
+ plabel = aa_get_label_rcu (& pctx -> label );
770
+ rcu_read_unlock ();
706
771
/* no fs check of aa_unix_peer_perm because conditions above
707
772
* ensure they will never be done
708
773
*/
@@ -713,18 +778,26 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
713
778
peer_addr , peer_addrlen ,
714
779
is_unix_fs (peer_sk ) ?
715
780
& peer_path : NULL ,
716
- pctx -> label ),
717
- unix_peer_perm (file -> f_cred , pctx -> label , op ,
781
+ plabel ),
782
+ unix_peer_perm (file -> f_cred , plabel , op ,
718
783
MAY_READ | MAY_WRITE , peer_sk ,
719
784
is_unix_fs (peer_sk ) ?
720
785
& peer_path : NULL ,
721
786
addr , addrlen ,
722
787
is_sk_fs ? & path : NULL ,
723
788
label )));
789
+ if (!error && !__aa_subj_label_is_cached (plabel , label ))
790
+ update_peer_ctx (peer_sk , pctx , label );
724
791
}
725
792
sock_put (peer_sk );
726
793
727
794
out :
728
795
796
+ /* update peer cache to latest successful perm check */
797
+ if (error == 0 )
798
+ update_sk_ctx (sock -> sk , label , plabel );
799
+ aa_put_label (plabel );
800
+
729
801
return error ;
730
802
}
803
+
0 commit comments