@@ -646,6 +646,67 @@ int aa_unix_peer_perm(const struct cred *subj_cred,
646646 peer_label );
647647}
648648
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+
649710/* This fn is only checked if something has changed in the security
650711 * boundaries. Otherwise cached info off file is sufficient
651712 */
@@ -655,6 +716,7 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
655716 struct socket * sock = (struct socket * ) file -> private_data ;
656717 struct sockaddr_un * addr , * peer_addr ;
657718 int addrlen , peer_addrlen ;
719+ struct aa_label * plabel = NULL ;
658720 struct sock * peer_sk = NULL ;
659721 u32 sk_req = request & ~NET_PEER_MASK ;
660722 struct path path ;
@@ -666,7 +728,6 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
666728 AA_BUG (!sock -> sk );
667729 AA_BUG (sock -> sk -> sk_family != PF_UNIX );
668730
669- /* TODO: update sock label with new task label */
670731 /* investigate only using lock via unix_peer_get()
671732 * addr only needs the memory barrier, but need to investigate
672733 * path
@@ -701,8 +762,12 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
701762 unix_fs_perm (op , request , subj_cred , label ,
702763 is_unix_fs (peer_sk ) ? & peer_path : NULL ));
703764 } else if (!is_sk_fs ) {
765+ struct aa_label * plabel ;
704766 struct aa_sk_ctx * pctx = aa_sock (peer_sk );
705767
768+ rcu_read_lock ();
769+ plabel = aa_get_label_rcu (& pctx -> label );
770+ rcu_read_unlock ();
706771 /* no fs check of aa_unix_peer_perm because conditions above
707772 * ensure they will never be done
708773 */
@@ -713,18 +778,26 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
713778 peer_addr , peer_addrlen ,
714779 is_unix_fs (peer_sk ) ?
715780 & 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 ,
718783 MAY_READ | MAY_WRITE , peer_sk ,
719784 is_unix_fs (peer_sk ) ?
720785 & peer_path : NULL ,
721786 addr , addrlen ,
722787 is_sk_fs ? & path : NULL ,
723788 label )));
789+ if (!error && !__aa_subj_label_is_cached (plabel , label ))
790+ update_peer_ctx (peer_sk , pctx , label );
724791 }
725792 sock_put (peer_sk );
726793
727794out :
728795
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+
729801 return error ;
730802}
803+
0 commit comments