162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AppArmor security module 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file contains AppArmor network mediation 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 862306a36Sopenharmony_ci * Copyright 2009-2017 Canonical Ltd. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "include/apparmor.h" 1262306a36Sopenharmony_ci#include "include/audit.h" 1362306a36Sopenharmony_ci#include "include/cred.h" 1462306a36Sopenharmony_ci#include "include/label.h" 1562306a36Sopenharmony_ci#include "include/net.h" 1662306a36Sopenharmony_ci#include "include/policy.h" 1762306a36Sopenharmony_ci#include "include/secid.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "net_names.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistruct aa_sfs_entry aa_sfs_entry_network[] = { 2362306a36Sopenharmony_ci AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), 2462306a36Sopenharmony_ci { } 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic const char * const net_mask_names[] = { 2862306a36Sopenharmony_ci "unknown", 2962306a36Sopenharmony_ci "send", 3062306a36Sopenharmony_ci "receive", 3162306a36Sopenharmony_ci "unknown", 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci "create", 3462306a36Sopenharmony_ci "shutdown", 3562306a36Sopenharmony_ci "connect", 3662306a36Sopenharmony_ci "unknown", 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci "setattr", 3962306a36Sopenharmony_ci "getattr", 4062306a36Sopenharmony_ci "setcred", 4162306a36Sopenharmony_ci "getcred", 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci "chmod", 4462306a36Sopenharmony_ci "chown", 4562306a36Sopenharmony_ci "chgrp", 4662306a36Sopenharmony_ci "lock", 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci "mmap", 4962306a36Sopenharmony_ci "mprot", 5062306a36Sopenharmony_ci "unknown", 5162306a36Sopenharmony_ci "unknown", 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci "accept", 5462306a36Sopenharmony_ci "bind", 5562306a36Sopenharmony_ci "listen", 5662306a36Sopenharmony_ci "unknown", 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci "setopt", 5962306a36Sopenharmony_ci "getopt", 6062306a36Sopenharmony_ci "unknown", 6162306a36Sopenharmony_ci "unknown", 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci "unknown", 6462306a36Sopenharmony_ci "unknown", 6562306a36Sopenharmony_ci "unknown", 6662306a36Sopenharmony_ci "unknown", 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* audit callback for net specific fields */ 7162306a36Sopenharmony_civoid audit_net_cb(struct audit_buffer *ab, void *va) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct common_audit_data *sa = va; 7462306a36Sopenharmony_ci struct apparmor_audit_data *ad = aad(sa); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (address_family_names[sa->u.net->family]) 7762306a36Sopenharmony_ci audit_log_format(ab, " family=\"%s\"", 7862306a36Sopenharmony_ci address_family_names[sa->u.net->family]); 7962306a36Sopenharmony_ci else 8062306a36Sopenharmony_ci audit_log_format(ab, " family=\"unknown(%d)\"", 8162306a36Sopenharmony_ci sa->u.net->family); 8262306a36Sopenharmony_ci if (sock_type_names[ad->net.type]) 8362306a36Sopenharmony_ci audit_log_format(ab, " sock_type=\"%s\"", 8462306a36Sopenharmony_ci sock_type_names[ad->net.type]); 8562306a36Sopenharmony_ci else 8662306a36Sopenharmony_ci audit_log_format(ab, " sock_type=\"unknown(%d)\"", 8762306a36Sopenharmony_ci ad->net.type); 8862306a36Sopenharmony_ci audit_log_format(ab, " protocol=%d", ad->net.protocol); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (ad->request & NET_PERMS_MASK) { 9162306a36Sopenharmony_ci audit_log_format(ab, " requested_mask="); 9262306a36Sopenharmony_ci aa_audit_perm_mask(ab, ad->request, NULL, 0, 9362306a36Sopenharmony_ci net_mask_names, NET_PERMS_MASK); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci if (ad->denied & NET_PERMS_MASK) { 9662306a36Sopenharmony_ci audit_log_format(ab, " denied_mask="); 9762306a36Sopenharmony_ci aa_audit_perm_mask(ab, ad->denied, NULL, 0, 9862306a36Sopenharmony_ci net_mask_names, NET_PERMS_MASK); 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci if (ad->peer) { 10262306a36Sopenharmony_ci audit_log_format(ab, " peer="); 10362306a36Sopenharmony_ci aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, 10462306a36Sopenharmony_ci FLAGS_NONE, GFP_ATOMIC); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* Generic af perm */ 10962306a36Sopenharmony_ciint aa_profile_af_perm(struct aa_profile *profile, 11062306a36Sopenharmony_ci struct apparmor_audit_data *ad, u32 request, u16 family, 11162306a36Sopenharmony_ci int type) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct aa_ruleset *rules = list_first_entry(&profile->rules, 11462306a36Sopenharmony_ci typeof(*rules), list); 11562306a36Sopenharmony_ci struct aa_perms perms = { }; 11662306a36Sopenharmony_ci aa_state_t state; 11762306a36Sopenharmony_ci __be16 buffer[2]; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci AA_BUG(family >= AF_MAX); 12062306a36Sopenharmony_ci AA_BUG(type < 0 || type >= SOCK_MAX); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (profile_unconfined(profile)) 12362306a36Sopenharmony_ci return 0; 12462306a36Sopenharmony_ci state = RULE_MEDIATES(rules, AA_CLASS_NET); 12562306a36Sopenharmony_ci if (!state) 12662306a36Sopenharmony_ci return 0; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci buffer[0] = cpu_to_be16(family); 12962306a36Sopenharmony_ci buffer[1] = cpu_to_be16((u16) type); 13062306a36Sopenharmony_ci state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer, 13162306a36Sopenharmony_ci 4); 13262306a36Sopenharmony_ci perms = *aa_lookup_perms(&rules->policy, state); 13362306a36Sopenharmony_ci aa_apply_modes_to_perms(profile, &perms); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return aa_check_perms(profile, &perms, request, ad, audit_net_cb); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ciint aa_af_perm(const struct cred *subj_cred, struct aa_label *label, 13962306a36Sopenharmony_ci const char *op, u32 request, u16 family, int type, int protocol) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct aa_profile *profile; 14262306a36Sopenharmony_ci DEFINE_AUDIT_NET(ad, op, NULL, family, type, protocol); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return fn_for_each_confined(label, profile, 14562306a36Sopenharmony_ci aa_profile_af_perm(profile, &ad, request, family, 14662306a36Sopenharmony_ci type)); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int aa_label_sk_perm(const struct cred *subj_cred, 15062306a36Sopenharmony_ci struct aa_label *label, 15162306a36Sopenharmony_ci const char *op, u32 request, 15262306a36Sopenharmony_ci struct sock *sk) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct aa_sk_ctx *ctx = SK_CTX(sk); 15562306a36Sopenharmony_ci int error = 0; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci AA_BUG(!label); 15862306a36Sopenharmony_ci AA_BUG(!sk); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (ctx->label != kernel_t && !unconfined(label)) { 16162306a36Sopenharmony_ci struct aa_profile *profile; 16262306a36Sopenharmony_ci DEFINE_AUDIT_SK(ad, op, sk); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ad.subj_cred = subj_cred; 16562306a36Sopenharmony_ci error = fn_for_each_confined(label, profile, 16662306a36Sopenharmony_ci aa_profile_af_sk_perm(profile, &ad, request, sk)); 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return error; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ciint aa_sk_perm(const char *op, u32 request, struct sock *sk) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct aa_label *label; 17562306a36Sopenharmony_ci int error; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci AA_BUG(!sk); 17862306a36Sopenharmony_ci AA_BUG(in_interrupt()); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* TODO: switch to begin_current_label ???? */ 18162306a36Sopenharmony_ci label = begin_current_label_crit_section(); 18262306a36Sopenharmony_ci error = aa_label_sk_perm(current_cred(), label, op, request, sk); 18362306a36Sopenharmony_ci end_current_label_crit_section(label); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return error; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ciint aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label, 19062306a36Sopenharmony_ci const char *op, u32 request, struct socket *sock) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci AA_BUG(!label); 19362306a36Sopenharmony_ci AA_BUG(!sock); 19462306a36Sopenharmony_ci AA_BUG(!sock->sk); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return aa_label_sk_perm(subj_cred, label, op, request, sock->sk); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK 20062306a36Sopenharmony_cistatic int apparmor_secmark_init(struct aa_secmark *secmark) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct aa_label *label; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (secmark->label[0] == '*') { 20562306a36Sopenharmony_ci secmark->secid = AA_SECID_WILDCARD; 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci label = aa_label_strn_parse(&root_ns->unconfined->label, 21062306a36Sopenharmony_ci secmark->label, strlen(secmark->label), 21162306a36Sopenharmony_ci GFP_ATOMIC, false, false); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (IS_ERR(label)) 21462306a36Sopenharmony_ci return PTR_ERR(label); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci secmark->secid = label->secid; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, 22262306a36Sopenharmony_ci struct apparmor_audit_data *ad) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci int i, ret; 22562306a36Sopenharmony_ci struct aa_perms perms = { }; 22662306a36Sopenharmony_ci struct aa_ruleset *rules = list_first_entry(&profile->rules, 22762306a36Sopenharmony_ci typeof(*rules), list); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (rules->secmark_count == 0) 23062306a36Sopenharmony_ci return 0; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci for (i = 0; i < rules->secmark_count; i++) { 23362306a36Sopenharmony_ci if (!rules->secmark[i].secid) { 23462306a36Sopenharmony_ci ret = apparmor_secmark_init(&rules->secmark[i]); 23562306a36Sopenharmony_ci if (ret) 23662306a36Sopenharmony_ci return ret; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (rules->secmark[i].secid == secid || 24062306a36Sopenharmony_ci rules->secmark[i].secid == AA_SECID_WILDCARD) { 24162306a36Sopenharmony_ci if (rules->secmark[i].deny) 24262306a36Sopenharmony_ci perms.deny = ALL_PERMS_MASK; 24362306a36Sopenharmony_ci else 24462306a36Sopenharmony_ci perms.allow = ALL_PERMS_MASK; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (rules->secmark[i].audit) 24762306a36Sopenharmony_ci perms.audit = ALL_PERMS_MASK; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci aa_apply_modes_to_perms(profile, &perms); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return aa_check_perms(profile, &perms, request, ad, audit_net_cb); 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ciint apparmor_secmark_check(struct aa_label *label, char *op, u32 request, 25762306a36Sopenharmony_ci u32 secid, const struct sock *sk) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci struct aa_profile *profile; 26062306a36Sopenharmony_ci DEFINE_AUDIT_SK(ad, op, sk); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return fn_for_each_confined(label, profile, 26362306a36Sopenharmony_ci aa_secmark_perm(profile, request, secid, 26462306a36Sopenharmony_ci &ad)); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci#endif 267