apparmor: make sure unix socket labeling is correctly updated.

When a unix socket is passed into a different confinement domain make
sure its cached mediation labeling is updated to correctly reflect
which domains are using the socket.

Fixes: c05e705812 ("apparmor: add fine grained af_unix mediation")
Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen 2025-06-19 22:11:52 -07:00
parent 6456ccbd2f
commit 88fec3526e
6 changed files with 231 additions and 62 deletions

View file

@ -646,6 +646,67 @@ int aa_unix_peer_perm(const struct cred *subj_cred,
peer_label); peer_label);
} }
/* sk_plabel for comparison only */
static void update_sk_ctx(struct sock *sk, struct aa_label *label,
struct aa_label *plabel)
{
struct aa_label *l, *old;
struct aa_sk_ctx *ctx = aa_sock(sk);
bool update_sk;
rcu_read_lock();
update_sk = (plabel &&
(plabel != rcu_access_pointer(ctx->peer_lastupdate) ||
!aa_label_is_subset(plabel, rcu_dereference(ctx->peer)))) ||
!__aa_subj_label_is_cached(label, rcu_dereference(ctx->label));
rcu_read_unlock();
if (!update_sk)
return;
spin_lock(&unix_sk(sk)->lock);
old = rcu_dereference_protected(ctx->label,
lockdep_is_held(&unix_sk(sk)->lock));
l = aa_label_merge(old, label, GFP_ATOMIC);
if (l) {
if (l != old) {
rcu_assign_pointer(ctx->label, l);
aa_put_label(old);
} else
aa_put_label(l);
}
if (plabel && rcu_access_pointer(ctx->peer_lastupdate) != plabel) {
old = rcu_dereference_protected(ctx->peer, lockdep_is_held(&unix_sk(sk)->lock));
if (old == plabel) {
rcu_assign_pointer(ctx->peer_lastupdate, plabel);
} else if (aa_label_is_subset(plabel, old)) {
rcu_assign_pointer(ctx->peer_lastupdate, plabel);
rcu_assign_pointer(ctx->peer, aa_get_label(plabel));
aa_put_label(old);
} /* else race or a subset - don't update */
}
spin_unlock(&unix_sk(sk)->lock);
}
static void update_peer_ctx(struct sock *sk, struct aa_sk_ctx *ctx,
struct aa_label *label)
{
struct aa_label *l, *old;
spin_lock(&unix_sk(sk)->lock);
old = rcu_dereference_protected(ctx->peer,
lockdep_is_held(&unix_sk(sk)->lock));
l = aa_label_merge(old, label, GFP_ATOMIC);
if (l) {
if (l != old) {
rcu_assign_pointer(ctx->peer, l);
aa_put_label(old);
} else
aa_put_label(l);
}
spin_unlock(&unix_sk(sk)->lock);
}
/* This fn is only checked if something has changed in the security /* This fn is only checked if something has changed in the security
* boundaries. Otherwise cached info off file is sufficient * boundaries. Otherwise cached info off file is sufficient
*/ */
@ -655,6 +716,7 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
struct socket *sock = (struct socket *) file->private_data; struct socket *sock = (struct socket *) file->private_data;
struct sockaddr_un *addr, *peer_addr; struct sockaddr_un *addr, *peer_addr;
int addrlen, peer_addrlen; int addrlen, peer_addrlen;
struct aa_label *plabel = NULL;
struct sock *peer_sk = NULL; struct sock *peer_sk = NULL;
u32 sk_req = request & ~NET_PEER_MASK; u32 sk_req = request & ~NET_PEER_MASK;
struct path path; struct path path;
@ -666,7 +728,6 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
AA_BUG(!sock->sk); AA_BUG(!sock->sk);
AA_BUG(sock->sk->sk_family != PF_UNIX); AA_BUG(sock->sk->sk_family != PF_UNIX);
/* TODO: update sock label with new task label */
/* investigate only using lock via unix_peer_get() /* investigate only using lock via unix_peer_get()
* addr only needs the memory barrier, but need to investigate * addr only needs the memory barrier, but need to investigate
* path * path
@ -701,8 +762,12 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
unix_fs_perm(op, request, subj_cred, label, unix_fs_perm(op, request, subj_cred, label,
is_unix_fs(peer_sk) ? &peer_path : NULL)); is_unix_fs(peer_sk) ? &peer_path : NULL));
} else if (!is_sk_fs) { } else if (!is_sk_fs) {
struct aa_label *plabel;
struct aa_sk_ctx *pctx = aa_sock(peer_sk); struct aa_sk_ctx *pctx = aa_sock(peer_sk);
rcu_read_lock();
plabel = aa_get_label_rcu(&pctx->label);
rcu_read_unlock();
/* no fs check of aa_unix_peer_perm because conditions above /* no fs check of aa_unix_peer_perm because conditions above
* ensure they will never be done * ensure they will never be done
*/ */
@ -713,18 +778,26 @@ int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label,
peer_addr, peer_addrlen, peer_addr, peer_addrlen,
is_unix_fs(peer_sk) ? is_unix_fs(peer_sk) ?
&peer_path : NULL, &peer_path : NULL,
pctx->label), plabel),
unix_peer_perm(file->f_cred, pctx->label, op, unix_peer_perm(file->f_cred, plabel, op,
MAY_READ | MAY_WRITE, peer_sk, MAY_READ | MAY_WRITE, peer_sk,
is_unix_fs(peer_sk) ? is_unix_fs(peer_sk) ?
&peer_path : NULL, &peer_path : NULL,
addr, addrlen, addr, addrlen,
is_sk_fs ? &path : NULL, is_sk_fs ? &path : NULL,
label))); label)));
if (!error && !__aa_subj_label_is_cached(plabel, label))
update_peer_ctx(peer_sk, pctx, label);
} }
sock_put(peer_sk); sock_put(peer_sk);
out: out:
/* update peer cache to latest successful perm check */
if (error == 0)
update_sk_ctx(sock->sk, label, plabel);
aa_put_label(plabel);
return error; return error;
} }

View file

@ -561,19 +561,35 @@ static int __file_sock_perm(const char *op, const struct cred *subj_cred,
return error; return error;
} }
/* wrapper fn to indicate semantics of the check */
static bool __subj_label_is_cached(struct aa_label *subj_label,
struct aa_label *obj_label)
{
return aa_label_is_subset(obj_label, subj_label);
}
/* for now separate fn to indicate semantics of the check */ /* for now separate fn to indicate semantics of the check */
static bool __file_is_delegated(struct aa_label *obj_label) static bool __file_is_delegated(struct aa_label *obj_label)
{ {
return unconfined(obj_label); return unconfined(obj_label);
} }
static bool __unix_needs_revalidation(struct file *file, struct aa_label *label,
u32 request)
{
struct socket *sock = (struct socket *) file->private_data;
lockdep_assert_in_rcu_read_lock();
if (!S_ISSOCK(file_inode(file)->i_mode))
return false;
if (request & NET_PEER_MASK)
return false;
if (sock->sk->sk_family == PF_UNIX) {
struct aa_sk_ctx *ctx = aa_sock(sock->sk);
if (rcu_access_pointer(ctx->peer) !=
rcu_access_pointer(ctx->peer_lastupdate))
return true;
return !__aa_subj_label_is_cached(rcu_dereference(ctx->label),
label);
}
return false;
}
/** /**
* aa_file_perm - do permission revalidation check & audit for @file * aa_file_perm - do permission revalidation check & audit for @file
* @op: operation being checked * @op: operation being checked
@ -612,14 +628,15 @@ int aa_file_perm(const char *op, const struct cred *subj_cred,
*/ */
denied = request & ~fctx->allow; denied = request & ~fctx->allow;
if (unconfined(label) || __file_is_delegated(flabel) || if (unconfined(label) || __file_is_delegated(flabel) ||
(!denied && __subj_label_is_cached(label, flabel))) { __unix_needs_revalidation(file, label, request) ||
(!denied && __aa_subj_label_is_cached(label, flabel))) {
rcu_read_unlock(); rcu_read_unlock();
goto done; goto done;
} }
/* slow path - revalidate access */
flabel = aa_get_newest_label(flabel); flabel = aa_get_newest_label(flabel);
rcu_read_unlock(); rcu_read_unlock();
/* TODO: label cross check */
if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry)) if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry))
error = __file_path_perm(op, subj_cred, label, flabel, file, error = __file_path_perm(op, subj_cred, label, flabel, file,

View file

@ -415,6 +415,13 @@ static inline void aa_put_label(struct aa_label *l)
kref_put(&l->count, aa_label_kref); kref_put(&l->count, aa_label_kref);
} }
/* wrapper fn to indicate semantics of the check */
static inline bool __aa_subj_label_is_cached(struct aa_label *subj_label,
struct aa_label *obj_label)
{
return aa_label_is_subset(obj_label, subj_label);
}
struct aa_proxy *aa_alloc_proxy(struct aa_label *l, gfp_t gfp); struct aa_proxy *aa_alloc_proxy(struct aa_label *l, gfp_t gfp);
void aa_proxy_kref(struct kref *kref); void aa_proxy_kref(struct kref *kref);

View file

@ -47,8 +47,9 @@
#define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \ #define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \
AA_MAY_ACCEPT) AA_MAY_ACCEPT)
struct aa_sk_ctx { struct aa_sk_ctx {
struct aa_label *label; struct aa_label __rcu *label;
struct aa_label *peer; struct aa_label __rcu *peer;
struct aa_label __rcu *peer_lastupdate; /* ptr cmp only, no deref */
}; };
static inline struct aa_sk_ctx *aa_sock(const struct sock *sk) static inline struct aa_sk_ctx *aa_sock(const struct sock *sk)

View file

@ -508,7 +508,6 @@ static int apparmor_file_alloc_security(struct file *file)
struct aa_file_ctx *ctx = file_ctx(file); struct aa_file_ctx *ctx = file_ctx(file);
struct aa_label *label = begin_current_label_crit_section(); struct aa_label *label = begin_current_label_crit_section();
spin_lock_init(&ctx->lock);
rcu_assign_pointer(ctx->label, aa_get_label(label)); rcu_assign_pointer(ctx->label, aa_get_label(label));
end_current_label_crit_section(label); end_current_label_crit_section(label);
return 0; return 0;
@ -1076,12 +1075,29 @@ static int apparmor_userns_create(const struct cred *cred)
return error; return error;
} }
static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t gfp)
{
struct aa_sk_ctx *ctx = aa_sock(sk);
struct aa_label *label;
bool needput;
label = __begin_current_label_crit_section(&needput);
//spin_lock_init(&ctx->lock);
rcu_assign_pointer(ctx->label, aa_get_label(label));
rcu_assign_pointer(ctx->peer, NULL);
rcu_assign_pointer(ctx->peer_lastupdate, NULL);
__end_current_label_crit_section(label, needput);
return 0;
}
static void apparmor_sk_free_security(struct sock *sk) static void apparmor_sk_free_security(struct sock *sk)
{ {
struct aa_sk_ctx *ctx = aa_sock(sk); struct aa_sk_ctx *ctx = aa_sock(sk);
aa_put_label(ctx->label); /* dead these won't be updated any more */
aa_put_label(ctx->peer); aa_put_label(rcu_dereference_protected(ctx->label, true));
aa_put_label(rcu_dereference_protected(ctx->peer, true));
aa_put_label(rcu_dereference_protected(ctx->peer_lastupdate, true));
} }
/** /**
@ -1095,13 +1111,22 @@ static void apparmor_sk_clone_security(const struct sock *sk,
struct aa_sk_ctx *ctx = aa_sock(sk); struct aa_sk_ctx *ctx = aa_sock(sk);
struct aa_sk_ctx *new = aa_sock(newsk); struct aa_sk_ctx *new = aa_sock(newsk);
if (new->label) /* not actually in use yet */
aa_put_label(new->label); if (rcu_access_pointer(ctx->label) != rcu_access_pointer(new->label)) {
new->label = aa_get_label(ctx->label); aa_put_label(rcu_dereference_protected(new->label, true));
rcu_assign_pointer(new->label, aa_get_label_rcu(&ctx->label));
}
if (new->peer) if (rcu_access_pointer(ctx->peer) != rcu_access_pointer(new->peer)) {
aa_put_label(new->peer); aa_put_label(rcu_dereference_protected(new->peer, true));
new->peer = aa_get_label(ctx->peer); rcu_assign_pointer(new->peer, aa_get_label_rcu(&ctx->peer));
}
if (rcu_access_pointer(ctx->peer_lastupdate) != rcu_access_pointer(new->peer_lastupdate)) {
aa_put_label(rcu_dereference_protected(new->peer_lastupdate, true));
rcu_assign_pointer(new->peer_lastupdate,
aa_get_label_rcu(&ctx->peer_lastupdate));
}
} }
static int unix_connect_perm(const struct cred *cred, struct aa_label *label, static int unix_connect_perm(const struct cred *cred, struct aa_label *label,
@ -1112,11 +1137,15 @@ static int unix_connect_perm(const struct cred *cred, struct aa_label *label,
error = aa_unix_peer_perm(cred, label, OP_CONNECT, error = aa_unix_peer_perm(cred, label, OP_CONNECT,
(AA_MAY_CONNECT | AA_MAY_SEND | AA_MAY_RECEIVE), (AA_MAY_CONNECT | AA_MAY_SEND | AA_MAY_RECEIVE),
sk, peer_sk, peer_ctx->label); sk, peer_sk,
rcu_dereference_protected(peer_ctx->label,
lockdep_is_held(&unix_sk(peer_sk)->lock)));
if (!is_unix_fs(peer_sk)) { if (!is_unix_fs(peer_sk)) {
last_error(error, last_error(error,
aa_unix_peer_perm(cred, aa_unix_peer_perm(cred,
peer_ctx->label, OP_CONNECT, rcu_dereference_protected(peer_ctx->label,
lockdep_is_held(&unix_sk(peer_sk)->lock)),
OP_CONNECT,
(AA_MAY_ACCEPT | AA_MAY_SEND | AA_MAY_RECEIVE), (AA_MAY_ACCEPT | AA_MAY_SEND | AA_MAY_RECEIVE),
peer_sk, sk, label)); peer_sk, sk, label));
} }
@ -1124,15 +1153,31 @@ static int unix_connect_perm(const struct cred *cred, struct aa_label *label,
return error; return error;
} }
/* lockdep check in unix_connect_perm - push sks here to check */
static void unix_connect_peers(struct aa_sk_ctx *sk_ctx, static void unix_connect_peers(struct aa_sk_ctx *sk_ctx,
struct aa_sk_ctx *peer_ctx) struct aa_sk_ctx *peer_ctx)
{ {
/* Cross reference the peer labels for SO_PEERSEC */ /* Cross reference the peer labels for SO_PEERSEC */
aa_put_label(peer_ctx->peer); struct aa_label *label = rcu_dereference_protected(sk_ctx->label, true);
aa_put_label(sk_ctx->peer);
peer_ctx->peer = aa_get_label(sk_ctx->label); aa_get_label(label);
sk_ctx->peer = aa_get_label(peer_ctx->label); aa_put_label(rcu_dereference_protected(peer_ctx->peer,
true));
rcu_assign_pointer(peer_ctx->peer, label); /* transfer cnt */
label = aa_get_label(rcu_dereference_protected(peer_ctx->label,
true));
//spin_unlock(&peer_ctx->lock);
//spin_lock(&sk_ctx->lock);
aa_put_label(rcu_dereference_protected(sk_ctx->peer,
true));
aa_put_label(rcu_dereference_protected(sk_ctx->peer_lastupdate,
true));
rcu_assign_pointer(sk_ctx->peer, aa_get_label(label));
rcu_assign_pointer(sk_ctx->peer_lastupdate, label); /* transfer cnt */
//spin_unlock(&sk_ctx->lock);
} }
/** /**
@ -1158,8 +1203,10 @@ static int apparmor_unix_stream_connect(struct sock *sk, struct sock *peer_sk,
return error; return error;
/* newsk doesn't go through post_create */ /* newsk doesn't go through post_create */
AA_BUG(new_ctx->label); AA_BUG(rcu_access_pointer(new_ctx->label));
new_ctx->label = aa_get_label(peer_ctx->label); rcu_assign_pointer(new_ctx->label,
aa_get_label(rcu_dereference_protected(peer_ctx->label,
true)));
/* Cross reference the peer labels for SO_PEERSEC */ /* Cross reference the peer labels for SO_PEERSEC */
unix_connect_peers(sk_ctx, new_ctx); unix_connect_peers(sk_ctx, new_ctx);
@ -1184,11 +1231,14 @@ static int apparmor_unix_may_send(struct socket *sock, struct socket *peer)
label = __begin_current_label_crit_section(&needput); label = __begin_current_label_crit_section(&needput);
error = xcheck(aa_unix_peer_perm(current_cred(), error = xcheck(aa_unix_peer_perm(current_cred(),
label, OP_SENDMSG, AA_MAY_SEND, label, OP_SENDMSG, AA_MAY_SEND,
sock->sk, peer->sk, peer_ctx->label), sock->sk, peer->sk,
rcu_dereference_protected(peer_ctx->label,
true)),
aa_unix_peer_perm(peer->file ? peer->file->f_cred : NULL, aa_unix_peer_perm(peer->file ? peer->file->f_cred : NULL,
peer_ctx->label, OP_SENDMSG, rcu_dereference_protected(peer_ctx->label,
AA_MAY_RECEIVE, true),
peer->sk, sock->sk, label)); OP_SENDMSG, AA_MAY_RECEIVE, peer->sk,
sock->sk, label));
__end_current_label_crit_section(label, needput); __end_current_label_crit_section(label, needput);
return error; return error;
@ -1246,8 +1296,9 @@ static int apparmor_socket_post_create(struct socket *sock, int family,
if (sock->sk) { if (sock->sk) {
struct aa_sk_ctx *ctx = aa_sock(sock->sk); struct aa_sk_ctx *ctx = aa_sock(sock->sk);
aa_put_label(ctx->label); /* still not live */
ctx->label = aa_get_label(label); aa_put_label(rcu_dereference_protected(ctx->label, true));
rcu_assign_pointer(ctx->label, aa_get_label(label));
} }
aa_put_label(label); aa_put_label(label);
@ -1260,23 +1311,27 @@ static int apparmor_socket_socketpair(struct socket *socka,
struct aa_sk_ctx *a_ctx = aa_sock(socka->sk); struct aa_sk_ctx *a_ctx = aa_sock(socka->sk);
struct aa_sk_ctx *b_ctx = aa_sock(sockb->sk); struct aa_sk_ctx *b_ctx = aa_sock(sockb->sk);
struct aa_label *label; struct aa_label *label;
int error = 0;
aa_put_label(a_ctx->label);
aa_put_label(b_ctx->label);
/* socks not live yet - initial values set in sk_alloc */
label = begin_current_label_crit_section(); label = begin_current_label_crit_section();
a_ctx->label = aa_get_label(label); if (rcu_access_pointer(a_ctx->label) != label) {
b_ctx->label = aa_get_label(label); AA_BUG("a_ctx != label");
aa_put_label(rcu_dereference_protected(a_ctx->label, true));
rcu_assign_pointer(a_ctx->label, aa_get_label(label));
}
if (rcu_access_pointer(b_ctx->label) != label) {
AA_BUG("b_ctx != label");
aa_put_label(rcu_dereference_protected(b_ctx->label, true));
rcu_assign_pointer(b_ctx->label, aa_get_label(label));
}
if (socka->sk->sk_family == PF_UNIX) { if (socka->sk->sk_family == PF_UNIX) {
/* unix socket pairs by-pass unix_stream_connect */ /* unix socket pairs by-pass unix_stream_connect */
if (!error)
unix_connect_peers(a_ctx, b_ctx); unix_connect_peers(a_ctx, b_ctx);
} }
end_current_label_crit_section(label); end_current_label_crit_section(label);
return error; return 0;
} }
/** /**
@ -1430,6 +1485,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{ {
struct aa_sk_ctx *ctx = aa_sock(sk); struct aa_sk_ctx *ctx = aa_sock(sk);
int error;
if (!skb->secmark) if (!skb->secmark)
return 0; return 0;
@ -1438,11 +1494,15 @@ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* If reach here before socket_post_create hook is called, in which * If reach here before socket_post_create hook is called, in which
* case label is null, drop the packet. * case label is null, drop the packet.
*/ */
if (!ctx->label) if (!rcu_access_pointer(ctx->label))
return -EACCES; return -EACCES;
return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE, rcu_read_lock();
skb->secmark, sk); error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_RECVMSG,
AA_MAY_RECEIVE, skb->secmark, sk);
rcu_read_unlock();
return error;
} }
#endif #endif
@ -1452,8 +1512,8 @@ static struct aa_label *sk_peer_get_label(struct sock *sk)
struct aa_sk_ctx *ctx = aa_sock(sk); struct aa_sk_ctx *ctx = aa_sock(sk);
struct aa_label *label = ERR_PTR(-ENOPROTOOPT); struct aa_label *label = ERR_PTR(-ENOPROTOOPT);
if (ctx->peer) if (rcu_access_pointer(ctx->peer))
return aa_get_label(ctx->peer); return aa_get_label_rcu(&ctx->peer);
if (sk->sk_family != PF_UNIX) if (sk->sk_family != PF_UNIX)
return ERR_PTR(-ENOPROTOOPT); return ERR_PTR(-ENOPROTOOPT);
@ -1480,12 +1540,12 @@ static int apparmor_socket_getpeersec_stream(struct socket *sock,
struct aa_label *label; struct aa_label *label;
struct aa_label *peer; struct aa_label *peer;
label = begin_current_label_crit_section();
peer = sk_peer_get_label(sock->sk); peer = sk_peer_get_label(sock->sk);
if (IS_ERR(peer)) { if (IS_ERR(peer)) {
error = PTR_ERR(peer); error = PTR_ERR(peer);
goto done; goto done;
} }
label = begin_current_label_crit_section();
slen = aa_label_asxprint(&name, labels_ns(label), peer, slen = aa_label_asxprint(&name, labels_ns(label), peer,
FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
FLAG_HIDDEN_UNCONFINED, GFP_KERNEL); FLAG_HIDDEN_UNCONFINED, GFP_KERNEL);
@ -1506,9 +1566,9 @@ done_len:
error = -EFAULT; error = -EFAULT;
done_put: done_put:
end_current_label_crit_section(label);
aa_put_label(peer); aa_put_label(peer);
done: done:
end_current_label_crit_section(label);
kfree(name); kfree(name);
return error; return error;
} }
@ -1544,8 +1604,9 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
{ {
struct aa_sk_ctx *ctx = aa_sock(sk); struct aa_sk_ctx *ctx = aa_sock(sk);
if (!ctx->label) /* setup - not live */
ctx->label = aa_get_current_label(); if (!rcu_access_pointer(ctx->label))
rcu_assign_pointer(ctx->label, aa_get_current_label());
} }
#ifdef CONFIG_NETWORK_SECMARK #ifdef CONFIG_NETWORK_SECMARK
@ -1553,12 +1614,17 @@ static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb
struct request_sock *req) struct request_sock *req)
{ {
struct aa_sk_ctx *ctx = aa_sock(sk); struct aa_sk_ctx *ctx = aa_sock(sk);
int error;
if (!skb->secmark) if (!skb->secmark)
return 0; return 0;
return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT, rcu_read_lock();
skb->secmark, sk); error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_CONNECT,
AA_MAY_CONNECT, skb->secmark, sk);
rcu_read_unlock();
return error;
} }
#endif #endif
@ -1615,6 +1681,7 @@ static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
@ -2266,6 +2333,7 @@ static unsigned int apparmor_ip_postroute(void *priv,
{ {
struct aa_sk_ctx *ctx; struct aa_sk_ctx *ctx;
struct sock *sk; struct sock *sk;
int error;
if (!skb->secmark) if (!skb->secmark)
return NF_ACCEPT; return NF_ACCEPT;
@ -2275,8 +2343,11 @@ static unsigned int apparmor_ip_postroute(void *priv,
return NF_ACCEPT; return NF_ACCEPT;
ctx = aa_sock(sk); ctx = aa_sock(sk);
if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND, rcu_read_lock();
skb->secmark, sk)) error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_SENDMSG,
AA_MAY_SEND, skb->secmark, sk);
rcu_read_unlock();
if (!error)
return NF_ACCEPT; return NF_ACCEPT;
return NF_DROP_ERR(-ECONNREFUSED); return NF_DROP_ERR(-ECONNREFUSED);

View file

@ -292,7 +292,7 @@ static int aa_label_sk_perm(const struct cred *subj_cred,
AA_BUG(!label); AA_BUG(!label);
AA_BUG(!sk); AA_BUG(!sk);
if (ctx->label != kernel_t && !unconfined(label)) { if (rcu_access_pointer(ctx->label) != kernel_t && !unconfined(label)) {
struct aa_profile *profile; struct aa_profile *profile;
DEFINE_AUDIT_SK(ad, op, subj_cred, sk); DEFINE_AUDIT_SK(ad, op, subj_cred, sk);