1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 256974a6fSJohn Johansen /* 356974a6fSJohn Johansen * AppArmor security module 456974a6fSJohn Johansen * 556974a6fSJohn Johansen * This file contains AppArmor network mediation 656974a6fSJohn Johansen * 756974a6fSJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 856974a6fSJohn Johansen * Copyright 2009-2017 Canonical Ltd. 956974a6fSJohn Johansen */ 1056974a6fSJohn Johansen 1156974a6fSJohn Johansen #include "include/apparmor.h" 1256974a6fSJohn Johansen #include "include/audit.h" 1356974a6fSJohn Johansen #include "include/cred.h" 1456974a6fSJohn Johansen #include "include/label.h" 1556974a6fSJohn Johansen #include "include/net.h" 1656974a6fSJohn Johansen #include "include/policy.h" 17ab9f2115SMatthew Garrett #include "include/secid.h" 1856974a6fSJohn Johansen 1956974a6fSJohn Johansen #include "net_names.h" 2056974a6fSJohn Johansen 2156974a6fSJohn Johansen 2256974a6fSJohn Johansen struct aa_sfs_entry aa_sfs_entry_network[] = { 2356974a6fSJohn Johansen AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), 2456974a6fSJohn Johansen { } 2556974a6fSJohn Johansen }; 2656974a6fSJohn Johansen 2756974a6fSJohn Johansen static const char * const net_mask_names[] = { 2856974a6fSJohn Johansen "unknown", 2956974a6fSJohn Johansen "send", 3056974a6fSJohn Johansen "receive", 3156974a6fSJohn Johansen "unknown", 3256974a6fSJohn Johansen 3356974a6fSJohn Johansen "create", 3456974a6fSJohn Johansen "shutdown", 3556974a6fSJohn Johansen "connect", 3656974a6fSJohn Johansen "unknown", 3756974a6fSJohn Johansen 3856974a6fSJohn Johansen "setattr", 3956974a6fSJohn Johansen "getattr", 4056974a6fSJohn Johansen "setcred", 4156974a6fSJohn Johansen "getcred", 4256974a6fSJohn Johansen 4356974a6fSJohn Johansen "chmod", 4456974a6fSJohn Johansen "chown", 4556974a6fSJohn Johansen "chgrp", 4656974a6fSJohn Johansen "lock", 4756974a6fSJohn Johansen 4856974a6fSJohn Johansen "mmap", 4956974a6fSJohn Johansen "mprot", 5056974a6fSJohn Johansen "unknown", 5156974a6fSJohn Johansen "unknown", 5256974a6fSJohn Johansen 5356974a6fSJohn Johansen "accept", 5456974a6fSJohn Johansen "bind", 5556974a6fSJohn Johansen "listen", 5656974a6fSJohn Johansen "unknown", 5756974a6fSJohn Johansen 5856974a6fSJohn Johansen "setopt", 5956974a6fSJohn Johansen "getopt", 6056974a6fSJohn Johansen "unknown", 6156974a6fSJohn Johansen "unknown", 6256974a6fSJohn Johansen 6356974a6fSJohn Johansen "unknown", 6456974a6fSJohn Johansen "unknown", 6556974a6fSJohn Johansen "unknown", 6656974a6fSJohn Johansen "unknown", 6756974a6fSJohn Johansen }; 6856974a6fSJohn Johansen 6956974a6fSJohn Johansen 7056974a6fSJohn Johansen /* audit callback for net specific fields */ 7156974a6fSJohn Johansen void audit_net_cb(struct audit_buffer *ab, void *va) 7256974a6fSJohn Johansen { 7356974a6fSJohn Johansen struct common_audit_data *sa = va; 7456974a6fSJohn Johansen 7556974a6fSJohn Johansen if (address_family_names[sa->u.net->family]) 76f1d9b23cSRichard Guy Briggs audit_log_format(ab, " family=\"%s\"", 77f1d9b23cSRichard Guy Briggs address_family_names[sa->u.net->family]); 7856974a6fSJohn Johansen else 79f1d9b23cSRichard Guy Briggs audit_log_format(ab, " family=\"unknown(%d)\"", 80f1d9b23cSRichard Guy Briggs sa->u.net->family); 8156974a6fSJohn Johansen if (sock_type_names[aad(sa)->net.type]) 82f1d9b23cSRichard Guy Briggs audit_log_format(ab, " sock_type=\"%s\"", 83f1d9b23cSRichard Guy Briggs sock_type_names[aad(sa)->net.type]); 8456974a6fSJohn Johansen else 85f1d9b23cSRichard Guy Briggs audit_log_format(ab, " sock_type=\"unknown(%d)\"", 86f1d9b23cSRichard Guy Briggs aad(sa)->net.type); 8756974a6fSJohn Johansen audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); 8856974a6fSJohn Johansen 8956974a6fSJohn Johansen if (aad(sa)->request & NET_PERMS_MASK) { 9056974a6fSJohn Johansen audit_log_format(ab, " requested_mask="); 9156974a6fSJohn Johansen aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0, 9256974a6fSJohn Johansen net_mask_names, NET_PERMS_MASK); 9356974a6fSJohn Johansen 9456974a6fSJohn Johansen if (aad(sa)->denied & NET_PERMS_MASK) { 9556974a6fSJohn Johansen audit_log_format(ab, " denied_mask="); 9656974a6fSJohn Johansen aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0, 9756974a6fSJohn Johansen net_mask_names, NET_PERMS_MASK); 9856974a6fSJohn Johansen } 9956974a6fSJohn Johansen } 10056974a6fSJohn Johansen if (aad(sa)->peer) { 10156974a6fSJohn Johansen audit_log_format(ab, " peer="); 10256974a6fSJohn Johansen aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 10356974a6fSJohn Johansen FLAGS_NONE, GFP_ATOMIC); 10456974a6fSJohn Johansen } 10556974a6fSJohn Johansen } 10656974a6fSJohn Johansen 10756974a6fSJohn Johansen /* Generic af perm */ 10856974a6fSJohn Johansen int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, 10956974a6fSJohn Johansen u32 request, u16 family, int type) 11056974a6fSJohn Johansen { 111*1ad22fccSJohn Johansen struct aa_ruleset *rules = list_first_entry(&profile->rules, 112*1ad22fccSJohn Johansen typeof(*rules), list); 11356974a6fSJohn Johansen struct aa_perms perms = { }; 11433fc95d8SJohn Johansen aa_state_t state; 11556974a6fSJohn Johansen __be16 buffer[2]; 11656974a6fSJohn Johansen 11756974a6fSJohn Johansen AA_BUG(family >= AF_MAX); 11856974a6fSJohn Johansen AA_BUG(type < 0 || type >= SOCK_MAX); 11956974a6fSJohn Johansen 12056974a6fSJohn Johansen if (profile_unconfined(profile)) 12156974a6fSJohn Johansen return 0; 122217af7e2SJohn Johansen state = RULE_MEDIATES(rules, AA_CLASS_NET); 12356974a6fSJohn Johansen if (!state) 12456974a6fSJohn Johansen return 0; 12556974a6fSJohn Johansen 12656974a6fSJohn Johansen buffer[0] = cpu_to_be16(family); 12756974a6fSJohn Johansen buffer[1] = cpu_to_be16((u16) type); 128217af7e2SJohn Johansen state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer, 12956974a6fSJohn Johansen 4); 130217af7e2SJohn Johansen perms = *aa_lookup_perms(&rules->policy, state); 13156974a6fSJohn Johansen aa_apply_modes_to_perms(profile, &perms); 13256974a6fSJohn Johansen 13356974a6fSJohn Johansen return aa_check_perms(profile, &perms, request, sa, audit_net_cb); 13456974a6fSJohn Johansen } 13556974a6fSJohn Johansen 13656974a6fSJohn Johansen int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, 13756974a6fSJohn Johansen int type, int protocol) 13856974a6fSJohn Johansen { 13956974a6fSJohn Johansen struct aa_profile *profile; 14056974a6fSJohn Johansen DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol); 14156974a6fSJohn Johansen 14256974a6fSJohn Johansen return fn_for_each_confined(label, profile, 14356974a6fSJohn Johansen aa_profile_af_perm(profile, &sa, request, family, 14456974a6fSJohn Johansen type)); 14556974a6fSJohn Johansen } 14656974a6fSJohn Johansen 14756974a6fSJohn Johansen static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, 14856974a6fSJohn Johansen struct sock *sk) 14956974a6fSJohn Johansen { 15095c0581fSJohn Johansen struct aa_sk_ctx *ctx = SK_CTX(sk); 1515f997580STony Jones int error = 0; 15256974a6fSJohn Johansen 15356974a6fSJohn Johansen AA_BUG(!label); 15456974a6fSJohn Johansen AA_BUG(!sk); 15556974a6fSJohn Johansen 15695c0581fSJohn Johansen if (ctx->label != kernel_t && !unconfined(label)) { 1575f997580STony Jones struct aa_profile *profile; 1585f997580STony Jones DEFINE_AUDIT_SK(sa, op, sk); 15956974a6fSJohn Johansen 1605f997580STony Jones error = fn_for_each_confined(label, profile, 16156974a6fSJohn Johansen aa_profile_af_sk_perm(profile, &sa, request, sk)); 16256974a6fSJohn Johansen } 16356974a6fSJohn Johansen 1645f997580STony Jones return error; 1655f997580STony Jones } 1665f997580STony Jones 16756974a6fSJohn Johansen int aa_sk_perm(const char *op, u32 request, struct sock *sk) 16856974a6fSJohn Johansen { 16956974a6fSJohn Johansen struct aa_label *label; 17056974a6fSJohn Johansen int error; 17156974a6fSJohn Johansen 17256974a6fSJohn Johansen AA_BUG(!sk); 17356974a6fSJohn Johansen AA_BUG(in_interrupt()); 17456974a6fSJohn Johansen 17556974a6fSJohn Johansen /* TODO: switch to begin_current_label ???? */ 17656974a6fSJohn Johansen label = begin_current_label_crit_section(); 17756974a6fSJohn Johansen error = aa_label_sk_perm(label, op, request, sk); 17856974a6fSJohn Johansen end_current_label_crit_section(label); 17956974a6fSJohn Johansen 18056974a6fSJohn Johansen return error; 18156974a6fSJohn Johansen } 18256974a6fSJohn Johansen 18356974a6fSJohn Johansen 18456974a6fSJohn Johansen int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, 18556974a6fSJohn Johansen struct socket *sock) 18656974a6fSJohn Johansen { 18756974a6fSJohn Johansen AA_BUG(!label); 18856974a6fSJohn Johansen AA_BUG(!sock); 18956974a6fSJohn Johansen AA_BUG(!sock->sk); 19056974a6fSJohn Johansen 19156974a6fSJohn Johansen return aa_label_sk_perm(label, op, request, sock->sk); 19256974a6fSJohn Johansen } 193ab9f2115SMatthew Garrett 194e1af4779SArnd Bergmann #ifdef CONFIG_NETWORK_SECMARK 195ab9f2115SMatthew Garrett static int apparmor_secmark_init(struct aa_secmark *secmark) 196ab9f2115SMatthew Garrett { 197ab9f2115SMatthew Garrett struct aa_label *label; 198ab9f2115SMatthew Garrett 199ab9f2115SMatthew Garrett if (secmark->label[0] == '*') { 200ab9f2115SMatthew Garrett secmark->secid = AA_SECID_WILDCARD; 201ab9f2115SMatthew Garrett return 0; 202ab9f2115SMatthew Garrett } 203ab9f2115SMatthew Garrett 204ab9f2115SMatthew Garrett label = aa_label_strn_parse(&root_ns->unconfined->label, 205ab9f2115SMatthew Garrett secmark->label, strlen(secmark->label), 206ab9f2115SMatthew Garrett GFP_ATOMIC, false, false); 207ab9f2115SMatthew Garrett 208ab9f2115SMatthew Garrett if (IS_ERR(label)) 209ab9f2115SMatthew Garrett return PTR_ERR(label); 210ab9f2115SMatthew Garrett 211ab9f2115SMatthew Garrett secmark->secid = label->secid; 212ab9f2115SMatthew Garrett 213ab9f2115SMatthew Garrett return 0; 214ab9f2115SMatthew Garrett } 215ab9f2115SMatthew Garrett 216ab9f2115SMatthew Garrett static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, 21741dd9596SFlorian Westphal struct common_audit_data *sa) 218ab9f2115SMatthew Garrett { 219ab9f2115SMatthew Garrett int i, ret; 220ab9f2115SMatthew Garrett struct aa_perms perms = { }; 221*1ad22fccSJohn Johansen struct aa_ruleset *rules = list_first_entry(&profile->rules, 222*1ad22fccSJohn Johansen typeof(*rules), list); 223ab9f2115SMatthew Garrett 224217af7e2SJohn Johansen if (rules->secmark_count == 0) 225ab9f2115SMatthew Garrett return 0; 226ab9f2115SMatthew Garrett 227217af7e2SJohn Johansen for (i = 0; i < rules->secmark_count; i++) { 228217af7e2SJohn Johansen if (!rules->secmark[i].secid) { 229217af7e2SJohn Johansen ret = apparmor_secmark_init(&rules->secmark[i]); 230ab9f2115SMatthew Garrett if (ret) 231ab9f2115SMatthew Garrett return ret; 232ab9f2115SMatthew Garrett } 233ab9f2115SMatthew Garrett 234217af7e2SJohn Johansen if (rules->secmark[i].secid == secid || 235217af7e2SJohn Johansen rules->secmark[i].secid == AA_SECID_WILDCARD) { 236217af7e2SJohn Johansen if (rules->secmark[i].deny) 237ab9f2115SMatthew Garrett perms.deny = ALL_PERMS_MASK; 238ab9f2115SMatthew Garrett else 239ab9f2115SMatthew Garrett perms.allow = ALL_PERMS_MASK; 240ab9f2115SMatthew Garrett 241217af7e2SJohn Johansen if (rules->secmark[i].audit) 242ab9f2115SMatthew Garrett perms.audit = ALL_PERMS_MASK; 243ab9f2115SMatthew Garrett } 244ab9f2115SMatthew Garrett } 245ab9f2115SMatthew Garrett 246ab9f2115SMatthew Garrett aa_apply_modes_to_perms(profile, &perms); 247ab9f2115SMatthew Garrett 248ab9f2115SMatthew Garrett return aa_check_perms(profile, &perms, request, sa, audit_net_cb); 249ab9f2115SMatthew Garrett } 250ab9f2115SMatthew Garrett 251ab9f2115SMatthew Garrett int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, 25241dd9596SFlorian Westphal u32 secid, const struct sock *sk) 253ab9f2115SMatthew Garrett { 254ab9f2115SMatthew Garrett struct aa_profile *profile; 255ab9f2115SMatthew Garrett DEFINE_AUDIT_SK(sa, op, sk); 256ab9f2115SMatthew Garrett 257ab9f2115SMatthew Garrett return fn_for_each_confined(label, profile, 258ab9f2115SMatthew Garrett aa_secmark_perm(profile, request, secid, 25941dd9596SFlorian Westphal &sa)); 260ab9f2115SMatthew Garrett } 261e1af4779SArnd Bergmann #endif 262