@@ -30,11 +30,10 @@ static inline struct sock *aa_unix_sk(struct unix_sock *u)
3030}
3131
3232static int unix_fs_perm (const char * op , u32 mask , const struct cred * subj_cred ,
33- struct aa_label * label , struct unix_sock * u )
33+ struct aa_label * label , struct path * path )
3434{
3535 AA_BUG (!label );
36- AA_BUG (!u );
37- AA_BUG (!is_unix_fs (aa_unix_sk (u )));
36+ AA_BUG (!path );
3837
3938 if (unconfined (label ) || !label_mediates (label , AA_CLASS_FILE ))
4039 return 0 ;
@@ -43,13 +42,13 @@ static int unix_fs_perm(const char *op, u32 mask, const struct cred *subj_cred,
4342 /* if !u->path.dentry socket is being shutdown - implicit delegation
4443 * until obj delegation is supported
4544 */
46- if (u -> path . dentry ) {
45+ if (path -> dentry ) {
4746 /* the sunpath may not be valid for this ns so use the path */
48- struct path_cond cond = { u -> path . dentry -> d_inode -> i_uid ,
49- u -> path . dentry -> d_inode -> i_mode
47+ struct path_cond cond = { path -> dentry -> d_inode -> i_uid ,
48+ path -> dentry -> d_inode -> i_mode
5049 };
5150
52- return aa_path_perm (op , subj_cred , label , & u -> path ,
51+ return aa_path_perm (op , subj_cred , label , path ,
5352 PATH_SOCK_COND , mask , & cond );
5453 } /* else implicitly delegated */
5554
@@ -102,18 +101,27 @@ static aa_state_t match_to_local(struct aa_policydb *policy,
102101 return state ;
103102}
104103
104+ struct sockaddr_un * aa_sunaddr (const struct unix_sock * u , int * addrlen )
105+ {
106+ struct unix_address * addr ;
107+
108+ /* memory barrier is sufficient see note in net/unix/af_unix.c */
109+ addr = smp_load_acquire (& u -> addr );
110+ if (addr ) {
111+ * addrlen = addr -> len ;
112+ return addr -> name ;
113+ }
114+ * addrlen = 0 ;
115+ return NULL ;
116+ }
117+
105118static aa_state_t match_to_sk (struct aa_policydb * policy ,
106119 aa_state_t state , u32 request ,
107120 struct unix_sock * u , struct aa_perms * * p ,
108121 const char * * info )
109122{
110- struct sockaddr_un * addr = NULL ;
111- int addrlen = 0 ;
112-
113- if (u -> addr ) {
114- addr = u -> addr -> name ;
115- addrlen = u -> addr -> len ;
116- }
123+ int addrlen ;
124+ struct sockaddr_un * addr = aa_sunaddr (u , & addrlen );
117125
118126 return match_to_local (policy , state , request , u -> sk .sk_type ,
119127 u -> sk .sk_protocol , addr , addrlen , p , info );
@@ -363,7 +371,8 @@ static int profile_opt_perm(struct aa_profile *profile, u32 request,
363371
364372/* null peer_label is allowed, in which case the peer_sk label is used */
365373static int profile_peer_perm (struct aa_profile * profile , u32 request ,
366- struct sock * sk , struct sock * peer_sk ,
374+ struct sock * sk , struct sockaddr_un * peer_addr ,
375+ int peer_addrlen ,
367376 struct aa_label * peer_label ,
368377 struct apparmor_audit_data * ad )
369378{
@@ -375,26 +384,16 @@ static int profile_peer_perm(struct aa_profile *profile, u32 request,
375384 AA_BUG (!profile );
376385 AA_BUG (profile_unconfined (profile ));
377386 AA_BUG (!sk );
378- AA_BUG (!peer_sk );
387+ AA_BUG (!peer_label );
379388 AA_BUG (!ad );
380- AA_BUG (is_unix_fs (peer_sk )); /* currently always calls unix_fs_perm */
381389
382390 state = RULE_MEDIATES_v9NET (rules );
383391 if (state ) {
384- struct aa_sk_ctx * peer_ctx = aa_sock (peer_sk );
385392 struct aa_profile * peerp ;
386- struct sockaddr_un * addr = NULL ;
387- int len = 0 ;
388393
389- if (unix_sk (peer_sk )-> addr ) {
390- addr = unix_sk (peer_sk )-> addr -> name ;
391- len = unix_sk (peer_sk )-> addr -> len ;
392- }
393394 state = match_to_peer (rules -> policy , state , request ,
394395 unix_sk (sk ),
395- addr , len , & p , & ad -> info );
396- if (!peer_label )
397- peer_label = peer_ctx -> label ;
396+ peer_addr , peer_addrlen , & p , & ad -> info );
398397
399398 return fn_for_each_in_ns (peer_label , peerp ,
400399 match_label (profile , rules , state , request ,
@@ -422,9 +421,8 @@ int aa_unix_create_perm(struct aa_label *label, int family, int type,
422421 return 0 ;
423422}
424423
425- int aa_unix_label_sk_perm (const struct cred * subj_cred ,
426- struct aa_label * label , const char * op , u32 request ,
427- struct sock * sk )
424+ int aa_unix_label_sk_perm (const struct cred * subj_cred , struct aa_label * label ,
425+ const char * op , u32 request , struct sock * sk )
428426{
429427 if (!unconfined (label )) {
430428 struct aa_profile * profile ;
@@ -436,35 +434,27 @@ int aa_unix_label_sk_perm(const struct cred *subj_cred,
436434 return 0 ;
437435}
438436
439- static int unix_label_sock_perm (const struct cred * subj_cred ,
440- struct aa_label * label , const char * op ,
441- u32 request , struct socket * sock )
442- {
443- if (unconfined (label ))
444- return 0 ;
445- if (is_unix_fs (sock -> sk ))
446- return unix_fs_perm (op , request , subj_cred , label ,
447- unix_sk (sock -> sk ));
448-
449- return aa_unix_label_sk_perm (subj_cred , label , op , request , sock -> sk );
450- }
451-
452437/* revalidation, get/set attr, shutdown */
453438int aa_unix_sock_perm (const char * op , u32 request , struct socket * sock )
454439{
455440 struct aa_label * label ;
456441 int error ;
457442
458443 label = begin_current_label_crit_section ();
459- error = unix_label_sock_perm (current_cred (), label , op , request , sock );
444+ if (is_unix_fs (sock -> sk ))
445+ error = unix_fs_perm (op , request , current_cred (), label ,
446+ & unix_sk (sock -> sk )-> path );
447+ else
448+ error = aa_unix_label_sk_perm (current_cred (), label , op ,
449+ request , sock -> sk );
460450 end_current_label_crit_section (label );
461451
462452 return error ;
463453}
464454
465455static int valid_addr (struct sockaddr * addr , int addr_len )
466456{
467- struct sockaddr_un * sunaddr = ( struct sockaddr_un * ) addr ;
457+ struct sockaddr_un * sunaddr = unix_addr ( addr ) ;
468458
469459 /* addr_len == offsetof(struct sockaddr_un, sun_path) is autobind */
470460 if (addr_len < offsetof(struct sockaddr_un , sun_path ) ||
@@ -586,6 +576,22 @@ int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock,
586576 return error ;
587577}
588578
579+ static int unix_peer_perm (const struct cred * subj_cred ,
580+ struct aa_label * label , const char * op , u32 request ,
581+ struct sock * sk , struct sockaddr_un * peer_addr ,
582+ int peer_addrlen , struct aa_label * peer_label )
583+ {
584+ struct aa_profile * profile ;
585+ DEFINE_AUDIT_SK (ad , op , subj_cred , sk );
586+
587+ ad .net .addr = peer_addr ;
588+ ad .net .addrlen = peer_addrlen ;
589+
590+ return fn_for_each_confined (label , profile ,
591+ profile_peer_perm (profile , request , sk ,
592+ peer_addr , peer_addrlen , peer_label , & ad ));
593+ }
594+
589595/**
590596 *
591597 * Requires: lock held on both @sk and @peer_sk
@@ -602,58 +608,37 @@ int aa_unix_peer_perm(const struct cred *subj_cred,
602608 AA_BUG (!label );
603609 AA_BUG (!sk );
604610 AA_BUG (!peer_sk );
611+ AA_BUG (!peer_label );
605612
606613 if (is_unix_fs (aa_unix_sk (peeru ))) {
607- return unix_fs_perm (op , request , subj_cred , label , peeru );
614+ return unix_fs_perm (op , request , subj_cred , label ,
615+ & peeru -> path );
608616 } else if (is_unix_fs (aa_unix_sk (u ))) {
609- return unix_fs_perm (op , request , subj_cred , label , u );
617+ return unix_fs_perm (op , request , subj_cred , label , & u -> path );
610618 } else if (!unconfined (label )) {
611- struct aa_profile * profile ;
612- DEFINE_AUDIT_SK (ad , op , subj_cred , sk );
613-
614- ad .net .peer_sk = peer_sk ;
619+ int plen ;
620+ struct sockaddr_un * paddr = aa_sunaddr (unix_sk (peer_sk ),
621+ & plen );
615622
616- return fn_for_each_confined (label , profile ,
617- profile_peer_perm (profile , request , sk ,
618- peer_sk , peer_label , & ad ));
623+ return unix_peer_perm (subj_cred , label , op , request ,
624+ sk , paddr , plen , peer_label );
619625 }
620626
621627 return 0 ;
622628}
623629
624- static void unix_state_double_lock (struct sock * sk1 , struct sock * sk2 )
625- {
626- if (unlikely (sk1 == sk2 ) || !sk2 ) {
627- unix_state_lock (sk1 );
628- return ;
629- }
630- if (sk1 < sk2 ) {
631- unix_state_lock (sk1 );
632- unix_state_lock (sk2 );
633- } else {
634- unix_state_lock (sk2 );
635- unix_state_lock (sk1 );
636- }
637- }
638-
639- static void unix_state_double_unlock (struct sock * sk1 , struct sock * sk2 )
640- {
641- if (unlikely (sk1 == sk2 ) || !sk2 ) {
642- unix_state_unlock (sk1 );
643- return ;
644- }
645- unix_state_unlock (sk1 );
646- unix_state_unlock (sk2 );
647- }
648-
649- /* TODO: examine replacing double lock with cached addr */
650-
630+ /* This fn is only checked if something has changed in the security
631+ * boundaries. Otherwise cached info off file is sufficient
632+ */
651633int aa_unix_file_perm (const struct cred * subj_cred , struct aa_label * label ,
652634 const char * op , u32 request , struct file * file )
653635{
654636 struct socket * sock = (struct socket * ) file -> private_data ;
637+ struct sockaddr_un * addr , * peer_addr ;
638+ int addrlen , peer_addrlen ;
655639 struct sock * peer_sk = NULL ;
656640 u32 sk_req = request & ~NET_PEER_MASK ;
641+ struct path path ;
657642 bool is_sk_fs ;
658643 int error = 0 ;
659644
@@ -663,40 +648,60 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
663648 AA_BUG (sock -> sk -> sk_family != PF_UNIX );
664649
665650 /* TODO: update sock label with new task label */
651+ /* investigate only using lock via unix_peer_get()
652+ * addr only needs the memory barrier, but need to investigate
653+ * path
654+ */
666655 unix_state_lock (sock -> sk );
667656 peer_sk = unix_peer (sock -> sk );
668657 if (peer_sk )
669658 sock_hold (peer_sk );
670659
671660 is_sk_fs = is_unix_fs (sock -> sk );
661+ addr = aa_sunaddr (unix_sk (sock -> sk ), & addrlen );
662+ path = unix_sk (sock -> sk )-> path ;
663+ unix_state_unlock (sock -> sk );
664+
672665 if (is_sk_fs && peer_sk )
673666 sk_req = request ;
674- if (sk_req )
675- error = unix_label_sock_perm (subj_cred , label , op , sk_req ,
676- sock );
677- unix_state_unlock (sock -> sk );
667+ if (sk_req ) {
668+ if (is_sk_fs )
669+ error = unix_fs_perm (op , sk_req , subj_cred , label ,
670+ & path );
671+ else
672+ error = aa_unix_label_sk_perm (subj_cred , label , op ,
673+ sk_req , sock -> sk );
674+ }
678675 if (!peer_sk )
679- return error ;
676+ goto out ;
677+
678+ peer_addr = aa_sunaddr (unix_sk (peer_sk ), & peer_addrlen );
680679
681- unix_state_double_lock (sock -> sk , peer_sk );
680+ struct path peer_path ;
681+
682+ peer_path = unix_sk (peer_sk )-> path ;
682683 if (!is_sk_fs && is_unix_fs (peer_sk )) {
683684 last_error (error ,
684685 unix_fs_perm (op , request , subj_cred , label ,
685- unix_sk ( peer_sk ) ));
686+ & peer_path ));
686687 } else if (!is_sk_fs ) {
687688 struct aa_sk_ctx * pctx = aa_sock (peer_sk );
688689
690+ /* no fs check of aa_unix_peer_perm because conditions above
691+ * ensure they will never be done
692+ */
689693 last_error (error ,
690- xcheck (aa_unix_peer_perm (subj_cred , label , op ,
691- MAY_READ | MAY_WRITE ,
692- sock -> sk , peer_sk , NULL ),
693- aa_unix_peer_perm (file -> f_cred , pctx -> label , op ,
694- MAY_READ | MAY_WRITE ,
695- peer_sk , sock -> sk , label )));
694+ xcheck (unix_peer_perm (subj_cred , label , op ,
695+ MAY_READ | MAY_WRITE , sock -> sk ,
696+ peer_addr , peer_addrlen ,
697+ pctx -> label ),
698+ unix_peer_perm (file -> f_cred , pctx -> label , op ,
699+ MAY_READ | MAY_WRITE , peer_sk ,
700+ addr , addrlen , label )));
696701 }
697- unix_state_double_unlock (sock -> sk , peer_sk );
698-
699702 sock_put (peer_sk );
700703
704+ out :
705+
701706 return error ;
702707}
0 commit comments