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 */
audit_net_cb(struct audit_buffer * ab,void * va)7156974a6fSJohn Johansen void audit_net_cb(struct audit_buffer *ab, void *va)
7256974a6fSJohn Johansen {
7356974a6fSJohn Johansen struct common_audit_data *sa = va;
74c57bc80fSJohn Johansen struct apparmor_audit_data *ad = aad(sa);
7556974a6fSJohn Johansen
7656974a6fSJohn Johansen if (address_family_names[sa->u.net->family])
77f1d9b23cSRichard Guy Briggs audit_log_format(ab, " family=\"%s\"",
78f1d9b23cSRichard Guy Briggs address_family_names[sa->u.net->family]);
7956974a6fSJohn Johansen else
80f1d9b23cSRichard Guy Briggs audit_log_format(ab, " family=\"unknown(%d)\"",
81f1d9b23cSRichard Guy Briggs sa->u.net->family);
82c57bc80fSJohn Johansen if (sock_type_names[ad->net.type])
83f1d9b23cSRichard Guy Briggs audit_log_format(ab, " sock_type=\"%s\"",
84c57bc80fSJohn Johansen sock_type_names[ad->net.type]);
8556974a6fSJohn Johansen else
86f1d9b23cSRichard Guy Briggs audit_log_format(ab, " sock_type=\"unknown(%d)\"",
87c57bc80fSJohn Johansen ad->net.type);
88c57bc80fSJohn Johansen audit_log_format(ab, " protocol=%d", ad->net.protocol);
8956974a6fSJohn Johansen
90c57bc80fSJohn Johansen if (ad->request & NET_PERMS_MASK) {
9156974a6fSJohn Johansen audit_log_format(ab, " requested_mask=");
92c57bc80fSJohn Johansen aa_audit_perm_mask(ab, ad->request, NULL, 0,
9356974a6fSJohn Johansen net_mask_names, NET_PERMS_MASK);
9456974a6fSJohn Johansen
95c57bc80fSJohn Johansen if (ad->denied & NET_PERMS_MASK) {
9656974a6fSJohn Johansen audit_log_format(ab, " denied_mask=");
97c57bc80fSJohn Johansen aa_audit_perm_mask(ab, ad->denied, NULL, 0,
9856974a6fSJohn Johansen net_mask_names, NET_PERMS_MASK);
9956974a6fSJohn Johansen }
10056974a6fSJohn Johansen }
101c57bc80fSJohn Johansen if (ad->peer) {
10256974a6fSJohn Johansen audit_log_format(ab, " peer=");
10330b3669dSJohn Johansen aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
10456974a6fSJohn Johansen FLAGS_NONE, GFP_ATOMIC);
10556974a6fSJohn Johansen }
10656974a6fSJohn Johansen }
10756974a6fSJohn Johansen
10856974a6fSJohn Johansen /* Generic af perm */
aa_profile_af_perm(struct aa_profile * profile,struct apparmor_audit_data * ad,u32 request,u16 family,int type)109c57bc80fSJohn Johansen int aa_profile_af_perm(struct aa_profile *profile,
110c57bc80fSJohn Johansen struct apparmor_audit_data *ad, u32 request, u16 family,
111c57bc80fSJohn Johansen int type)
11256974a6fSJohn Johansen {
1131ad22fccSJohn Johansen struct aa_ruleset *rules = list_first_entry(&profile->rules,
1141ad22fccSJohn Johansen typeof(*rules), list);
11556974a6fSJohn Johansen struct aa_perms perms = { };
11633fc95d8SJohn Johansen aa_state_t state;
11756974a6fSJohn Johansen __be16 buffer[2];
11856974a6fSJohn Johansen
11956974a6fSJohn Johansen AA_BUG(family >= AF_MAX);
12056974a6fSJohn Johansen AA_BUG(type < 0 || type >= SOCK_MAX);
12156974a6fSJohn Johansen
12256974a6fSJohn Johansen if (profile_unconfined(profile))
12356974a6fSJohn Johansen return 0;
124217af7e2SJohn Johansen state = RULE_MEDIATES(rules, AA_CLASS_NET);
12556974a6fSJohn Johansen if (!state)
12656974a6fSJohn Johansen return 0;
12756974a6fSJohn Johansen
12856974a6fSJohn Johansen buffer[0] = cpu_to_be16(family);
12956974a6fSJohn Johansen buffer[1] = cpu_to_be16((u16) type);
130217af7e2SJohn Johansen state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer,
13156974a6fSJohn Johansen 4);
132217af7e2SJohn Johansen perms = *aa_lookup_perms(&rules->policy, state);
13356974a6fSJohn Johansen aa_apply_modes_to_perms(profile, &perms);
13456974a6fSJohn Johansen
135c57bc80fSJohn Johansen return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
13656974a6fSJohn Johansen }
13756974a6fSJohn Johansen
aa_af_perm(const struct cred * subj_cred,struct aa_label * label,const char * op,u32 request,u16 family,int type,int protocol)138*690f33e1SJohn Johansen int aa_af_perm(const struct cred *subj_cred, struct aa_label *label,
139*690f33e1SJohn Johansen const char *op, u32 request, u16 family, int type, int protocol)
14056974a6fSJohn Johansen {
14156974a6fSJohn Johansen struct aa_profile *profile;
142c57bc80fSJohn Johansen DEFINE_AUDIT_NET(ad, op, NULL, family, type, protocol);
14356974a6fSJohn Johansen
14456974a6fSJohn Johansen return fn_for_each_confined(label, profile,
145c57bc80fSJohn Johansen aa_profile_af_perm(profile, &ad, request, family,
14656974a6fSJohn Johansen type));
14756974a6fSJohn Johansen }
14856974a6fSJohn Johansen
aa_label_sk_perm(const struct cred * subj_cred,struct aa_label * label,const char * op,u32 request,struct sock * sk)149*690f33e1SJohn Johansen static int aa_label_sk_perm(const struct cred *subj_cred,
150*690f33e1SJohn Johansen struct aa_label *label,
151*690f33e1SJohn Johansen const char *op, u32 request,
15256974a6fSJohn Johansen struct sock *sk)
15356974a6fSJohn Johansen {
15495c0581fSJohn Johansen struct aa_sk_ctx *ctx = SK_CTX(sk);
1555f997580STony Jones int error = 0;
15656974a6fSJohn Johansen
15756974a6fSJohn Johansen AA_BUG(!label);
15856974a6fSJohn Johansen AA_BUG(!sk);
15956974a6fSJohn Johansen
16095c0581fSJohn Johansen if (ctx->label != kernel_t && !unconfined(label)) {
1615f997580STony Jones struct aa_profile *profile;
162c57bc80fSJohn Johansen DEFINE_AUDIT_SK(ad, op, sk);
16356974a6fSJohn Johansen
164*690f33e1SJohn Johansen ad.subj_cred = subj_cred;
1655f997580STony Jones error = fn_for_each_confined(label, profile,
166c57bc80fSJohn Johansen aa_profile_af_sk_perm(profile, &ad, request, sk));
16756974a6fSJohn Johansen }
16856974a6fSJohn Johansen
1695f997580STony Jones return error;
1705f997580STony Jones }
1715f997580STony Jones
aa_sk_perm(const char * op,u32 request,struct sock * sk)17256974a6fSJohn Johansen int aa_sk_perm(const char *op, u32 request, struct sock *sk)
17356974a6fSJohn Johansen {
17456974a6fSJohn Johansen struct aa_label *label;
17556974a6fSJohn Johansen int error;
17656974a6fSJohn Johansen
17756974a6fSJohn Johansen AA_BUG(!sk);
17856974a6fSJohn Johansen AA_BUG(in_interrupt());
17956974a6fSJohn Johansen
18056974a6fSJohn Johansen /* TODO: switch to begin_current_label ???? */
18156974a6fSJohn Johansen label = begin_current_label_crit_section();
182*690f33e1SJohn Johansen error = aa_label_sk_perm(current_cred(), label, op, request, sk);
18356974a6fSJohn Johansen end_current_label_crit_section(label);
18456974a6fSJohn Johansen
18556974a6fSJohn Johansen return error;
18656974a6fSJohn Johansen }
18756974a6fSJohn Johansen
18856974a6fSJohn Johansen
aa_sock_file_perm(const struct cred * subj_cred,struct aa_label * label,const char * op,u32 request,struct socket * sock)189*690f33e1SJohn Johansen int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label,
190*690f33e1SJohn Johansen const char *op, u32 request, struct socket *sock)
19156974a6fSJohn Johansen {
19256974a6fSJohn Johansen AA_BUG(!label);
19356974a6fSJohn Johansen AA_BUG(!sock);
19456974a6fSJohn Johansen AA_BUG(!sock->sk);
19556974a6fSJohn Johansen
196*690f33e1SJohn Johansen return aa_label_sk_perm(subj_cred, label, op, request, sock->sk);
19756974a6fSJohn Johansen }
198ab9f2115SMatthew Garrett
199e1af4779SArnd Bergmann #ifdef CONFIG_NETWORK_SECMARK
apparmor_secmark_init(struct aa_secmark * secmark)200ab9f2115SMatthew Garrett static int apparmor_secmark_init(struct aa_secmark *secmark)
201ab9f2115SMatthew Garrett {
202ab9f2115SMatthew Garrett struct aa_label *label;
203ab9f2115SMatthew Garrett
204ab9f2115SMatthew Garrett if (secmark->label[0] == '*') {
205ab9f2115SMatthew Garrett secmark->secid = AA_SECID_WILDCARD;
206ab9f2115SMatthew Garrett return 0;
207ab9f2115SMatthew Garrett }
208ab9f2115SMatthew Garrett
209ab9f2115SMatthew Garrett label = aa_label_strn_parse(&root_ns->unconfined->label,
210ab9f2115SMatthew Garrett secmark->label, strlen(secmark->label),
211ab9f2115SMatthew Garrett GFP_ATOMIC, false, false);
212ab9f2115SMatthew Garrett
213ab9f2115SMatthew Garrett if (IS_ERR(label))
214ab9f2115SMatthew Garrett return PTR_ERR(label);
215ab9f2115SMatthew Garrett
216ab9f2115SMatthew Garrett secmark->secid = label->secid;
217ab9f2115SMatthew Garrett
218ab9f2115SMatthew Garrett return 0;
219ab9f2115SMatthew Garrett }
220ab9f2115SMatthew Garrett
aa_secmark_perm(struct aa_profile * profile,u32 request,u32 secid,struct apparmor_audit_data * ad)221ab9f2115SMatthew Garrett static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
222c57bc80fSJohn Johansen struct apparmor_audit_data *ad)
223ab9f2115SMatthew Garrett {
224ab9f2115SMatthew Garrett int i, ret;
225ab9f2115SMatthew Garrett struct aa_perms perms = { };
2261ad22fccSJohn Johansen struct aa_ruleset *rules = list_first_entry(&profile->rules,
2271ad22fccSJohn Johansen typeof(*rules), list);
228ab9f2115SMatthew Garrett
229217af7e2SJohn Johansen if (rules->secmark_count == 0)
230ab9f2115SMatthew Garrett return 0;
231ab9f2115SMatthew Garrett
232217af7e2SJohn Johansen for (i = 0; i < rules->secmark_count; i++) {
233217af7e2SJohn Johansen if (!rules->secmark[i].secid) {
234217af7e2SJohn Johansen ret = apparmor_secmark_init(&rules->secmark[i]);
235ab9f2115SMatthew Garrett if (ret)
236ab9f2115SMatthew Garrett return ret;
237ab9f2115SMatthew Garrett }
238ab9f2115SMatthew Garrett
239217af7e2SJohn Johansen if (rules->secmark[i].secid == secid ||
240217af7e2SJohn Johansen rules->secmark[i].secid == AA_SECID_WILDCARD) {
241217af7e2SJohn Johansen if (rules->secmark[i].deny)
242ab9f2115SMatthew Garrett perms.deny = ALL_PERMS_MASK;
243ab9f2115SMatthew Garrett else
244ab9f2115SMatthew Garrett perms.allow = ALL_PERMS_MASK;
245ab9f2115SMatthew Garrett
246217af7e2SJohn Johansen if (rules->secmark[i].audit)
247ab9f2115SMatthew Garrett perms.audit = ALL_PERMS_MASK;
248ab9f2115SMatthew Garrett }
249ab9f2115SMatthew Garrett }
250ab9f2115SMatthew Garrett
251ab9f2115SMatthew Garrett aa_apply_modes_to_perms(profile, &perms);
252ab9f2115SMatthew Garrett
253c57bc80fSJohn Johansen return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
254ab9f2115SMatthew Garrett }
255ab9f2115SMatthew Garrett
apparmor_secmark_check(struct aa_label * label,char * op,u32 request,u32 secid,const struct sock * sk)256ab9f2115SMatthew Garrett int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
25741dd9596SFlorian Westphal u32 secid, const struct sock *sk)
258ab9f2115SMatthew Garrett {
259ab9f2115SMatthew Garrett struct aa_profile *profile;
260c57bc80fSJohn Johansen DEFINE_AUDIT_SK(ad, op, sk);
261ab9f2115SMatthew Garrett
262ab9f2115SMatthew Garrett return fn_for_each_confined(label, profile,
263ab9f2115SMatthew Garrett aa_secmark_perm(profile, request, secid,
264c57bc80fSJohn Johansen &ad));
265ab9f2115SMatthew Garrett }
266e1af4779SArnd Bergmann #endif
267