update_sk_ctx will, under certain circumstances, replace a socket's
ctx->peer_lastupdate, but it does not put the refcount on that value after
doing the update. Properly put the old value to avoid refcount leaks.

Signed-off-by: Ryan Lee <[email protected]>
---
 security/apparmor/af_unix.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/security/apparmor/af_unix.c b/security/apparmor/af_unix.c
index 2730f4ad08d3..f17dc208e776 100644
--- a/security/apparmor/af_unix.c
+++ b/security/apparmor/af_unix.c
@@ -649,7 +649,7 @@ int aa_unix_peer_perm(const struct cred *subj_cred,
 static bool update_sk_ctx(struct sock *sk, struct aa_label *label,
                          struct aa_label *plabel)
 {
-       struct aa_label *l, *old;
+       struct aa_label *l, *old, *old_plastupdate;
        struct aa_sk_ctx *ctx = aa_sock(sk);
        bool update_sk;
        bool plabel_used = false;
@@ -674,7 +674,9 @@ static bool update_sk_ctx(struct sock *sk, struct aa_label 
*label,
                } else
                        aa_put_label(l);
        }
-       if (plabel && rcu_access_pointer(ctx->peer_lastupdate) != plabel) {
+       old_plastupdate = rcu_dereference_protected(ctx->peer_lastupdate,
+                                               
lockdep_is_held(&unix_sk(sk)->lock));
+       if (plabel && old_plastupdate != plabel) {
                old = rcu_dereference_protected(ctx->peer, 
lockdep_is_held(&unix_sk(sk)->lock));
 
                if (old == plabel) {
@@ -686,6 +688,9 @@ static bool update_sk_ctx(struct sock *sk, struct aa_label 
*label,
                        aa_put_label(old);
                        plabel_used = true;
                } /* else race or a subset - don't update */
+
+               if (plabel_used)
+                       aa_put_label(old_plastupdate);
        }
        spin_unlock(&unix_sk(sk)->lock);
        return plabel_used;
-- 
2.43.0


Reply via email to