// SPDX-License-Identifier: GPL-2.0-only /* * AppArmor security module * * This file contains AppArmor af_unix fine grained mediation * * Copyright 2023 Canonical Ltd. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2 of the * License.
*/
if (unconfined(label) || !label_mediates(label, AA_CLASS_FILE)) return 0;
mask &= NET_FS_PERMS; /* if !u->path.dentry socket is being shutdown - implicit delegation * until obj delegation is supported
*/ if (path->dentry) { /* the sunpath may not be valid for this ns so use the path */ struct inode *inode = path->dentry->d_inode;
vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_idmap(path->mnt), inode); struct path_cond cond = {
.uid = vfsuid_into_kuid(vfsuid),
.mode = inode->i_mode,
};
/* match_addr special constants */ #define ABSTRACT_ADDR "\x00"/* abstract socket addr */ #define ANONYMOUS_ADDR "\x01"/* anonymous endpoint, no addr */ #define DISCONNECTED_ADDR "\x02"/* addr is another namespace */ #define SHUTDOWN_ADDR "\x03"/* path addr is shutdown and cleared */ #define FS_ADDR "/"/* path addr in fs */
static aa_state_t match_addr(struct aa_dfa *dfa, aa_state_t state, struct sockaddr_un *addr, int addrlen)
{ if (addr) /* include leading \0 */
state = aa_dfa_match_len(dfa, state, addr->sun_path,
unix_addr_len(addrlen)); else
state = aa_dfa_match_len(dfa, state, ANONYMOUS_ADDR, 1); /* todo: could change to out of band for cleaner separation */
state = aa_dfa_null_transition(dfa, state);
return state;
}
static aa_state_t match_to_local(struct aa_policydb *policy,
aa_state_t state, u32 request, int type, int protocol, struct sockaddr_un *addr, int addrlen, struct aa_perms **p, constchar **info)
{
state = aa_match_to_prot(policy, state, request, PF_UNIX, type,
protocol, NULL, info); if (state) {
state = match_addr(policy->dfa, state, addr, addrlen); if (state) { /* todo: local label matching */
state = aa_dfa_null_transition(policy->dfa, state); if (!state)
*info = "failed local label match";
} else {
*info = "failed local address match";
}
}
/* unix sock creation comes before we know if the socket will be an fs * socket * v6 - semantics are handled by mapping in profile load * v7 - semantics require sock create for tasks creating an fs socket. * v8 - same as v7
*/ staticint profile_create_perm(struct aa_profile *profile, int family, int type, int protocol, struct apparmor_audit_data *ad)
{ struct aa_ruleset *rules = profile->label.rules[0];
aa_state_t state;
state = RULE_MEDIATES_v9NET(rules); if (state) { if (is_unix_fs(sk)) return unix_fs_perm(ad->op, request, ad->subj_cred,
&profile->label,
&unix_sk(sk)->path);
state = match_to_sk(rules->policy, state, request, unix_sk(sk),
&p, &ad->info);
state = RULE_MEDIATES_v9NET(rules); if (state) { if (is_unix_fs(sk)) return unix_fs_perm(ad->op, AA_MAY_ACCEPT,
ad->subj_cred, &profile->label,
&unix_sk(sk)->path);
state = match_to_sk(rules->policy, state, AA_MAY_ACCEPT,
unix_sk(sk), &p, &ad->info);
state = RULE_MEDIATES_v9NET(rules); if (state) {
__be16 b = cpu_to_be16(optname); if (is_unix_fs(sk)) return unix_fs_perm(ad->op, request,
ad->subj_cred, &profile->label,
&unix_sk(sk)->path);
state = match_to_cmd(rules->policy, state, request, unix_sk(sk),
CMD_OPT, &p, &ad->info); if (state && !p) {
state = aa_dfa_match_len(rules->policy->dfa, state,
(char *) &b, 2); if (!state)
ad->info = "failed sockopt match";
} return aa_do_perms(profile, rules->policy, state, request, p,
ad);
}
int aa_unix_create_perm(struct aa_label *label, int family, int type, int protocol)
{ if (!unconfined(label)) { struct aa_profile *profile;
DEFINE_AUDIT_NET(ad, OP_CREATE, current_cred(), NULL, family,
type, protocol);
/* * unix connections are covered by the * - unix_stream_connect (stream) and unix_may_send hooks (dgram) * - fs connect is handled by open * This is just here to document this is not needed for af_unix * int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address, int addrlen) { return 0; }
*/
int aa_unix_listen_perm(struct socket *sock, int backlog)
{ struct aa_profile *profile; struct aa_label *label; int error = 0;
label = begin_current_label_crit_section(); if (!unconfined(label)) {
DEFINE_AUDIT_SK(ad, OP_LISTEN, current_cred(), sock->sk);
/* * dgram handled by unix_may_sendmsg, right to send on stream done at connect * could do per msg unix_stream here, but connect + socket transfer is * sufficient. This is just here to document this is not needed for af_unix * * sendmsg, recvmsg int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock, struct msghdr *msg, int size) { return 0; }
*/
int aa_unix_opt_perm(constchar *op, u32 request, struct socket *sock, int level, int optname)
{ struct aa_profile *profile; struct aa_label *label; int error = 0;
label = begin_current_label_crit_section(); if (!unconfined(label)) {
DEFINE_AUDIT_SK(ad, op, current_cred(), sock->sk);
/* investigate only using lock via unix_peer_get() * addr only needs the memory barrier, but need to investigate * path
*/
unix_state_lock(sock->sk);
peer_sk = unix_peer(sock->sk); if (peer_sk)
sock_hold(peer_sk);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.