18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AppArmor security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains AppArmor network mediation 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 88c2ecf20Sopenharmony_ci * Copyright 2009-2017 Canonical Ltd. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "include/apparmor.h" 128c2ecf20Sopenharmony_ci#include "include/audit.h" 138c2ecf20Sopenharmony_ci#include "include/cred.h" 148c2ecf20Sopenharmony_ci#include "include/label.h" 158c2ecf20Sopenharmony_ci#include "include/net.h" 168c2ecf20Sopenharmony_ci#include "include/policy.h" 178c2ecf20Sopenharmony_ci#include "include/secid.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "net_names.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct aa_sfs_entry aa_sfs_entry_network[] = { 238c2ecf20Sopenharmony_ci AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), 248c2ecf20Sopenharmony_ci { } 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic const char * const net_mask_names[] = { 288c2ecf20Sopenharmony_ci "unknown", 298c2ecf20Sopenharmony_ci "send", 308c2ecf20Sopenharmony_ci "receive", 318c2ecf20Sopenharmony_ci "unknown", 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci "create", 348c2ecf20Sopenharmony_ci "shutdown", 358c2ecf20Sopenharmony_ci "connect", 368c2ecf20Sopenharmony_ci "unknown", 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci "setattr", 398c2ecf20Sopenharmony_ci "getattr", 408c2ecf20Sopenharmony_ci "setcred", 418c2ecf20Sopenharmony_ci "getcred", 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci "chmod", 448c2ecf20Sopenharmony_ci "chown", 458c2ecf20Sopenharmony_ci "chgrp", 468c2ecf20Sopenharmony_ci "lock", 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci "mmap", 498c2ecf20Sopenharmony_ci "mprot", 508c2ecf20Sopenharmony_ci "unknown", 518c2ecf20Sopenharmony_ci "unknown", 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci "accept", 548c2ecf20Sopenharmony_ci "bind", 558c2ecf20Sopenharmony_ci "listen", 568c2ecf20Sopenharmony_ci "unknown", 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci "setopt", 598c2ecf20Sopenharmony_ci "getopt", 608c2ecf20Sopenharmony_ci "unknown", 618c2ecf20Sopenharmony_ci "unknown", 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci "unknown", 648c2ecf20Sopenharmony_ci "unknown", 658c2ecf20Sopenharmony_ci "unknown", 668c2ecf20Sopenharmony_ci "unknown", 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* audit callback for net specific fields */ 718c2ecf20Sopenharmony_civoid audit_net_cb(struct audit_buffer *ab, void *va) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct common_audit_data *sa = va; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (address_family_names[sa->u.net->family]) 768c2ecf20Sopenharmony_ci audit_log_format(ab, " family=\"%s\"", 778c2ecf20Sopenharmony_ci address_family_names[sa->u.net->family]); 788c2ecf20Sopenharmony_ci else 798c2ecf20Sopenharmony_ci audit_log_format(ab, " family=\"unknown(%d)\"", 808c2ecf20Sopenharmony_ci sa->u.net->family); 818c2ecf20Sopenharmony_ci if (sock_type_names[aad(sa)->net.type]) 828c2ecf20Sopenharmony_ci audit_log_format(ab, " sock_type=\"%s\"", 838c2ecf20Sopenharmony_ci sock_type_names[aad(sa)->net.type]); 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci audit_log_format(ab, " sock_type=\"unknown(%d)\"", 868c2ecf20Sopenharmony_ci aad(sa)->net.type); 878c2ecf20Sopenharmony_ci audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (aad(sa)->request & NET_PERMS_MASK) { 908c2ecf20Sopenharmony_ci audit_log_format(ab, " requested_mask="); 918c2ecf20Sopenharmony_ci aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0, 928c2ecf20Sopenharmony_ci net_mask_names, NET_PERMS_MASK); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (aad(sa)->denied & NET_PERMS_MASK) { 958c2ecf20Sopenharmony_ci audit_log_format(ab, " denied_mask="); 968c2ecf20Sopenharmony_ci aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0, 978c2ecf20Sopenharmony_ci net_mask_names, NET_PERMS_MASK); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci if (aad(sa)->peer) { 1018c2ecf20Sopenharmony_ci audit_log_format(ab, " peer="); 1028c2ecf20Sopenharmony_ci aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 1038c2ecf20Sopenharmony_ci FLAGS_NONE, GFP_ATOMIC); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/* Generic af perm */ 1088c2ecf20Sopenharmony_ciint aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, 1098c2ecf20Sopenharmony_ci u32 request, u16 family, int type) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct aa_perms perms = { }; 1128c2ecf20Sopenharmony_ci unsigned int state; 1138c2ecf20Sopenharmony_ci __be16 buffer[2]; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci AA_BUG(family >= AF_MAX); 1168c2ecf20Sopenharmony_ci AA_BUG(type < 0 || type >= SOCK_MAX); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (profile_unconfined(profile)) 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci state = PROFILE_MEDIATES(profile, AA_CLASS_NET); 1218c2ecf20Sopenharmony_ci if (!state) 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci buffer[0] = cpu_to_be16(family); 1258c2ecf20Sopenharmony_ci buffer[1] = cpu_to_be16((u16) type); 1268c2ecf20Sopenharmony_ci state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer, 1278c2ecf20Sopenharmony_ci 4); 1288c2ecf20Sopenharmony_ci aa_compute_perms(profile->policy.dfa, state, &perms); 1298c2ecf20Sopenharmony_ci aa_apply_modes_to_perms(profile, &perms); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return aa_check_perms(profile, &perms, request, sa, audit_net_cb); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciint aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, 1358c2ecf20Sopenharmony_ci int type, int protocol) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct aa_profile *profile; 1388c2ecf20Sopenharmony_ci DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return fn_for_each_confined(label, profile, 1418c2ecf20Sopenharmony_ci aa_profile_af_perm(profile, &sa, request, family, 1428c2ecf20Sopenharmony_ci type)); 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, 1468c2ecf20Sopenharmony_ci struct sock *sk) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci int error = 0; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci AA_BUG(!label); 1518c2ecf20Sopenharmony_ci AA_BUG(!sk); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (!unconfined(label)) { 1548c2ecf20Sopenharmony_ci struct aa_profile *profile; 1558c2ecf20Sopenharmony_ci DEFINE_AUDIT_SK(sa, op, sk); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci error = fn_for_each_confined(label, profile, 1588c2ecf20Sopenharmony_ci aa_profile_af_sk_perm(profile, &sa, request, sk)); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return error; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ciint aa_sk_perm(const char *op, u32 request, struct sock *sk) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct aa_label *label; 1678c2ecf20Sopenharmony_ci int error; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci AA_BUG(!sk); 1708c2ecf20Sopenharmony_ci AA_BUG(in_interrupt()); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* TODO: switch to begin_current_label ???? */ 1738c2ecf20Sopenharmony_ci label = begin_current_label_crit_section(); 1748c2ecf20Sopenharmony_ci error = aa_label_sk_perm(label, op, request, sk); 1758c2ecf20Sopenharmony_ci end_current_label_crit_section(label); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return error; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ciint aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, 1828c2ecf20Sopenharmony_ci struct socket *sock) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci AA_BUG(!label); 1858c2ecf20Sopenharmony_ci AA_BUG(!sock); 1868c2ecf20Sopenharmony_ci AA_BUG(!sock->sk); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci return aa_label_sk_perm(label, op, request, sock->sk); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK 1928c2ecf20Sopenharmony_cistatic int apparmor_secmark_init(struct aa_secmark *secmark) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci struct aa_label *label; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (secmark->label[0] == '*') { 1978c2ecf20Sopenharmony_ci secmark->secid = AA_SECID_WILDCARD; 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci label = aa_label_strn_parse(&root_ns->unconfined->label, 2028c2ecf20Sopenharmony_ci secmark->label, strlen(secmark->label), 2038c2ecf20Sopenharmony_ci GFP_ATOMIC, false, false); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (IS_ERR(label)) 2068c2ecf20Sopenharmony_ci return PTR_ERR(label); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci secmark->secid = label->secid; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return 0; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistatic int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid, 2148c2ecf20Sopenharmony_ci struct common_audit_data *sa, struct sock *sk) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci int i, ret; 2178c2ecf20Sopenharmony_ci struct aa_perms perms = { }; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (profile->secmark_count == 0) 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci for (i = 0; i < profile->secmark_count; i++) { 2238c2ecf20Sopenharmony_ci if (!profile->secmark[i].secid) { 2248c2ecf20Sopenharmony_ci ret = apparmor_secmark_init(&profile->secmark[i]); 2258c2ecf20Sopenharmony_ci if (ret) 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (profile->secmark[i].secid == secid || 2308c2ecf20Sopenharmony_ci profile->secmark[i].secid == AA_SECID_WILDCARD) { 2318c2ecf20Sopenharmony_ci if (profile->secmark[i].deny) 2328c2ecf20Sopenharmony_ci perms.deny = ALL_PERMS_MASK; 2338c2ecf20Sopenharmony_ci else 2348c2ecf20Sopenharmony_ci perms.allow = ALL_PERMS_MASK; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (profile->secmark[i].audit) 2378c2ecf20Sopenharmony_ci perms.audit = ALL_PERMS_MASK; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci aa_apply_modes_to_perms(profile, &perms); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return aa_check_perms(profile, &perms, request, sa, audit_net_cb); 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ciint apparmor_secmark_check(struct aa_label *label, char *op, u32 request, 2478c2ecf20Sopenharmony_ci u32 secid, struct sock *sk) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct aa_profile *profile; 2508c2ecf20Sopenharmony_ci DEFINE_AUDIT_SK(sa, op, sk); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return fn_for_each_confined(label, profile, 2538c2ecf20Sopenharmony_ci aa_secmark_perm(profile, request, secid, 2548c2ecf20Sopenharmony_ci &sa, sk)); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci#endif 257