1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * NetLabel CALIPSO/IPv6 Support
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This file defines the CALIPSO/IPv6 functions for the NetLabel system. The
6*4882a593Smuzhiyun * NetLabel system manages static and dynamic label mappings for network
7*4882a593Smuzhiyun * protocols such as CIPSO and CALIPSO.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * Authors: Paul Moore <paul@paul-moore.com>
10*4882a593Smuzhiyun * Huw Davies <huw@codeweavers.com>
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun /* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
14*4882a593Smuzhiyun * (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
15*4882a593Smuzhiyun */
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include <linux/types.h>
18*4882a593Smuzhiyun #include <linux/socket.h>
19*4882a593Smuzhiyun #include <linux/string.h>
20*4882a593Smuzhiyun #include <linux/skbuff.h>
21*4882a593Smuzhiyun #include <linux/audit.h>
22*4882a593Smuzhiyun #include <linux/slab.h>
23*4882a593Smuzhiyun #include <net/sock.h>
24*4882a593Smuzhiyun #include <net/netlink.h>
25*4882a593Smuzhiyun #include <net/genetlink.h>
26*4882a593Smuzhiyun #include <net/netlabel.h>
27*4882a593Smuzhiyun #include <net/calipso.h>
28*4882a593Smuzhiyun #include <linux/atomic.h>
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include "netlabel_user.h"
31*4882a593Smuzhiyun #include "netlabel_calipso.h"
32*4882a593Smuzhiyun #include "netlabel_mgmt.h"
33*4882a593Smuzhiyun #include "netlabel_domainhash.h"
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun /* Argument struct for calipso_doi_walk() */
36*4882a593Smuzhiyun struct netlbl_calipso_doiwalk_arg {
37*4882a593Smuzhiyun struct netlink_callback *nl_cb;
38*4882a593Smuzhiyun struct sk_buff *skb;
39*4882a593Smuzhiyun u32 seq;
40*4882a593Smuzhiyun };
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun /* Argument struct for netlbl_domhsh_walk() */
43*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg {
44*4882a593Smuzhiyun struct netlbl_audit *audit_info;
45*4882a593Smuzhiyun u32 doi;
46*4882a593Smuzhiyun };
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun /* NetLabel Generic NETLINK CALIPSO family */
49*4882a593Smuzhiyun static struct genl_family netlbl_calipso_gnl_family;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* NetLabel Netlink attribute policy */
52*4882a593Smuzhiyun static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = {
53*4882a593Smuzhiyun [NLBL_CALIPSO_A_DOI] = { .type = NLA_U32 },
54*4882a593Smuzhiyun [NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 },
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* NetLabel Command Handlers
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun /**
60*4882a593Smuzhiyun * netlbl_calipso_add_pass - Adds a CALIPSO pass DOI definition
61*4882a593Smuzhiyun * @info: the Generic NETLINK info block
62*4882a593Smuzhiyun * @audit_info: NetLabel audit information
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun * Description:
65*4882a593Smuzhiyun * Create a new CALIPSO_MAP_PASS DOI definition based on the given ADD message
66*4882a593Smuzhiyun * and add it to the CALIPSO engine. Return zero on success and non-zero on
67*4882a593Smuzhiyun * error.
68*4882a593Smuzhiyun *
69*4882a593Smuzhiyun */
netlbl_calipso_add_pass(struct genl_info * info,struct netlbl_audit * audit_info)70*4882a593Smuzhiyun static int netlbl_calipso_add_pass(struct genl_info *info,
71*4882a593Smuzhiyun struct netlbl_audit *audit_info)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun int ret_val;
74*4882a593Smuzhiyun struct calipso_doi *doi_def = NULL;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
77*4882a593Smuzhiyun if (!doi_def)
78*4882a593Smuzhiyun return -ENOMEM;
79*4882a593Smuzhiyun doi_def->type = CALIPSO_MAP_PASS;
80*4882a593Smuzhiyun doi_def->doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
81*4882a593Smuzhiyun ret_val = calipso_doi_add(doi_def, audit_info);
82*4882a593Smuzhiyun if (ret_val != 0)
83*4882a593Smuzhiyun calipso_doi_free(doi_def);
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun return ret_val;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /**
89*4882a593Smuzhiyun * netlbl_calipso_add - Handle an ADD message
90*4882a593Smuzhiyun * @skb: the NETLINK buffer
91*4882a593Smuzhiyun * @info: the Generic NETLINK info block
92*4882a593Smuzhiyun *
93*4882a593Smuzhiyun * Description:
94*4882a593Smuzhiyun * Create a new DOI definition based on the given ADD message and add it to the
95*4882a593Smuzhiyun * CALIPSO engine. Returns zero on success, negative values on failure.
96*4882a593Smuzhiyun *
97*4882a593Smuzhiyun */
netlbl_calipso_add(struct sk_buff * skb,struct genl_info * info)98*4882a593Smuzhiyun static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info)
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun int ret_val = -EINVAL;
102*4882a593Smuzhiyun struct netlbl_audit audit_info;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun if (!info->attrs[NLBL_CALIPSO_A_DOI] ||
105*4882a593Smuzhiyun !info->attrs[NLBL_CALIPSO_A_MTYPE])
106*4882a593Smuzhiyun return -EINVAL;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun netlbl_netlink_auditinfo(skb, &audit_info);
109*4882a593Smuzhiyun switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) {
110*4882a593Smuzhiyun case CALIPSO_MAP_PASS:
111*4882a593Smuzhiyun ret_val = netlbl_calipso_add_pass(info, &audit_info);
112*4882a593Smuzhiyun break;
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun if (ret_val == 0)
115*4882a593Smuzhiyun atomic_inc(&netlabel_mgmt_protocount);
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun return ret_val;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /**
121*4882a593Smuzhiyun * netlbl_calipso_list - Handle a LIST message
122*4882a593Smuzhiyun * @skb: the NETLINK buffer
123*4882a593Smuzhiyun * @info: the Generic NETLINK info block
124*4882a593Smuzhiyun *
125*4882a593Smuzhiyun * Description:
126*4882a593Smuzhiyun * Process a user generated LIST message and respond accordingly.
127*4882a593Smuzhiyun * Returns zero on success and negative values on error.
128*4882a593Smuzhiyun *
129*4882a593Smuzhiyun */
netlbl_calipso_list(struct sk_buff * skb,struct genl_info * info)130*4882a593Smuzhiyun static int netlbl_calipso_list(struct sk_buff *skb, struct genl_info *info)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun int ret_val;
133*4882a593Smuzhiyun struct sk_buff *ans_skb = NULL;
134*4882a593Smuzhiyun void *data;
135*4882a593Smuzhiyun u32 doi;
136*4882a593Smuzhiyun struct calipso_doi *doi_def;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (!info->attrs[NLBL_CALIPSO_A_DOI]) {
139*4882a593Smuzhiyun ret_val = -EINVAL;
140*4882a593Smuzhiyun goto list_failure;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun doi_def = calipso_doi_getdef(doi);
146*4882a593Smuzhiyun if (!doi_def) {
147*4882a593Smuzhiyun ret_val = -EINVAL;
148*4882a593Smuzhiyun goto list_failure;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
152*4882a593Smuzhiyun if (!ans_skb) {
153*4882a593Smuzhiyun ret_val = -ENOMEM;
154*4882a593Smuzhiyun goto list_failure_put;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun data = genlmsg_put_reply(ans_skb, info, &netlbl_calipso_gnl_family,
157*4882a593Smuzhiyun 0, NLBL_CALIPSO_C_LIST);
158*4882a593Smuzhiyun if (!data) {
159*4882a593Smuzhiyun ret_val = -ENOMEM;
160*4882a593Smuzhiyun goto list_failure_put;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun ret_val = nla_put_u32(ans_skb, NLBL_CALIPSO_A_MTYPE, doi_def->type);
164*4882a593Smuzhiyun if (ret_val != 0)
165*4882a593Smuzhiyun goto list_failure_put;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun calipso_doi_putdef(doi_def);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun genlmsg_end(ans_skb, data);
170*4882a593Smuzhiyun return genlmsg_reply(ans_skb, info);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun list_failure_put:
173*4882a593Smuzhiyun calipso_doi_putdef(doi_def);
174*4882a593Smuzhiyun list_failure:
175*4882a593Smuzhiyun kfree_skb(ans_skb);
176*4882a593Smuzhiyun return ret_val;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /**
180*4882a593Smuzhiyun * netlbl_calipso_listall_cb - calipso_doi_walk() callback for LISTALL
181*4882a593Smuzhiyun * @doi_def: the CALIPSO DOI definition
182*4882a593Smuzhiyun * @arg: the netlbl_calipso_doiwalk_arg structure
183*4882a593Smuzhiyun *
184*4882a593Smuzhiyun * Description:
185*4882a593Smuzhiyun * This function is designed to be used as a callback to the
186*4882a593Smuzhiyun * calipso_doi_walk() function for use in generating a response for a LISTALL
187*4882a593Smuzhiyun * message. Returns the size of the message on success, negative values on
188*4882a593Smuzhiyun * failure.
189*4882a593Smuzhiyun *
190*4882a593Smuzhiyun */
netlbl_calipso_listall_cb(struct calipso_doi * doi_def,void * arg)191*4882a593Smuzhiyun static int netlbl_calipso_listall_cb(struct calipso_doi *doi_def, void *arg)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun int ret_val = -ENOMEM;
194*4882a593Smuzhiyun struct netlbl_calipso_doiwalk_arg *cb_arg = arg;
195*4882a593Smuzhiyun void *data;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
198*4882a593Smuzhiyun cb_arg->seq, &netlbl_calipso_gnl_family,
199*4882a593Smuzhiyun NLM_F_MULTI, NLBL_CALIPSO_C_LISTALL);
200*4882a593Smuzhiyun if (!data)
201*4882a593Smuzhiyun goto listall_cb_failure;
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun ret_val = nla_put_u32(cb_arg->skb, NLBL_CALIPSO_A_DOI, doi_def->doi);
204*4882a593Smuzhiyun if (ret_val != 0)
205*4882a593Smuzhiyun goto listall_cb_failure;
206*4882a593Smuzhiyun ret_val = nla_put_u32(cb_arg->skb,
207*4882a593Smuzhiyun NLBL_CALIPSO_A_MTYPE,
208*4882a593Smuzhiyun doi_def->type);
209*4882a593Smuzhiyun if (ret_val != 0)
210*4882a593Smuzhiyun goto listall_cb_failure;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun genlmsg_end(cb_arg->skb, data);
213*4882a593Smuzhiyun return 0;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun listall_cb_failure:
216*4882a593Smuzhiyun genlmsg_cancel(cb_arg->skb, data);
217*4882a593Smuzhiyun return ret_val;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun /**
221*4882a593Smuzhiyun * netlbl_calipso_listall - Handle a LISTALL message
222*4882a593Smuzhiyun * @skb: the NETLINK buffer
223*4882a593Smuzhiyun * @cb: the NETLINK callback
224*4882a593Smuzhiyun *
225*4882a593Smuzhiyun * Description:
226*4882a593Smuzhiyun * Process a user generated LISTALL message and respond accordingly. Returns
227*4882a593Smuzhiyun * zero on success and negative values on error.
228*4882a593Smuzhiyun *
229*4882a593Smuzhiyun */
netlbl_calipso_listall(struct sk_buff * skb,struct netlink_callback * cb)230*4882a593Smuzhiyun static int netlbl_calipso_listall(struct sk_buff *skb,
231*4882a593Smuzhiyun struct netlink_callback *cb)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun struct netlbl_calipso_doiwalk_arg cb_arg;
234*4882a593Smuzhiyun u32 doi_skip = cb->args[0];
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun cb_arg.nl_cb = cb;
237*4882a593Smuzhiyun cb_arg.skb = skb;
238*4882a593Smuzhiyun cb_arg.seq = cb->nlh->nlmsg_seq;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun calipso_doi_walk(&doi_skip, netlbl_calipso_listall_cb, &cb_arg);
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun cb->args[0] = doi_skip;
243*4882a593Smuzhiyun return skb->len;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /**
247*4882a593Smuzhiyun * netlbl_calipso_remove_cb - netlbl_calipso_remove() callback for REMOVE
248*4882a593Smuzhiyun * @entry: LSM domain mapping entry
249*4882a593Smuzhiyun * @arg: the netlbl_domhsh_walk_arg structure
250*4882a593Smuzhiyun *
251*4882a593Smuzhiyun * Description:
252*4882a593Smuzhiyun * This function is intended for use by netlbl_calipso_remove() as the callback
253*4882a593Smuzhiyun * for the netlbl_domhsh_walk() function; it removes LSM domain map entries
254*4882a593Smuzhiyun * which are associated with the CALIPSO DOI specified in @arg. Returns zero on
255*4882a593Smuzhiyun * success, negative values on failure.
256*4882a593Smuzhiyun *
257*4882a593Smuzhiyun */
netlbl_calipso_remove_cb(struct netlbl_dom_map * entry,void * arg)258*4882a593Smuzhiyun static int netlbl_calipso_remove_cb(struct netlbl_dom_map *entry, void *arg)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg *cb_arg = arg;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun if (entry->def.type == NETLBL_NLTYPE_CALIPSO &&
263*4882a593Smuzhiyun entry->def.calipso->doi == cb_arg->doi)
264*4882a593Smuzhiyun return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /**
270*4882a593Smuzhiyun * netlbl_calipso_remove - Handle a REMOVE message
271*4882a593Smuzhiyun * @skb: the NETLINK buffer
272*4882a593Smuzhiyun * @info: the Generic NETLINK info block
273*4882a593Smuzhiyun *
274*4882a593Smuzhiyun * Description:
275*4882a593Smuzhiyun * Process a user generated REMOVE message and respond accordingly. Returns
276*4882a593Smuzhiyun * zero on success, negative values on failure.
277*4882a593Smuzhiyun *
278*4882a593Smuzhiyun */
netlbl_calipso_remove(struct sk_buff * skb,struct genl_info * info)279*4882a593Smuzhiyun static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun int ret_val = -EINVAL;
282*4882a593Smuzhiyun struct netlbl_domhsh_walk_arg cb_arg;
283*4882a593Smuzhiyun struct netlbl_audit audit_info;
284*4882a593Smuzhiyun u32 skip_bkt = 0;
285*4882a593Smuzhiyun u32 skip_chain = 0;
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun if (!info->attrs[NLBL_CALIPSO_A_DOI])
288*4882a593Smuzhiyun return -EINVAL;
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun netlbl_netlink_auditinfo(skb, &audit_info);
291*4882a593Smuzhiyun cb_arg.doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
292*4882a593Smuzhiyun cb_arg.audit_info = &audit_info;
293*4882a593Smuzhiyun ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
294*4882a593Smuzhiyun netlbl_calipso_remove_cb, &cb_arg);
295*4882a593Smuzhiyun if (ret_val == 0 || ret_val == -ENOENT) {
296*4882a593Smuzhiyun ret_val = calipso_doi_remove(cb_arg.doi, &audit_info);
297*4882a593Smuzhiyun if (ret_val == 0)
298*4882a593Smuzhiyun atomic_dec(&netlabel_mgmt_protocount);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun return ret_val;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun /* NetLabel Generic NETLINK Command Definitions
305*4882a593Smuzhiyun */
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun static const struct genl_small_ops netlbl_calipso_ops[] = {
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun .cmd = NLBL_CALIPSO_C_ADD,
310*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
311*4882a593Smuzhiyun .flags = GENL_ADMIN_PERM,
312*4882a593Smuzhiyun .doit = netlbl_calipso_add,
313*4882a593Smuzhiyun .dumpit = NULL,
314*4882a593Smuzhiyun },
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun .cmd = NLBL_CALIPSO_C_REMOVE,
317*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
318*4882a593Smuzhiyun .flags = GENL_ADMIN_PERM,
319*4882a593Smuzhiyun .doit = netlbl_calipso_remove,
320*4882a593Smuzhiyun .dumpit = NULL,
321*4882a593Smuzhiyun },
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun .cmd = NLBL_CALIPSO_C_LIST,
324*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
325*4882a593Smuzhiyun .flags = 0,
326*4882a593Smuzhiyun .doit = netlbl_calipso_list,
327*4882a593Smuzhiyun .dumpit = NULL,
328*4882a593Smuzhiyun },
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun .cmd = NLBL_CALIPSO_C_LISTALL,
331*4882a593Smuzhiyun .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
332*4882a593Smuzhiyun .flags = 0,
333*4882a593Smuzhiyun .doit = NULL,
334*4882a593Smuzhiyun .dumpit = netlbl_calipso_listall,
335*4882a593Smuzhiyun },
336*4882a593Smuzhiyun };
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun static struct genl_family netlbl_calipso_gnl_family __ro_after_init = {
339*4882a593Smuzhiyun .hdrsize = 0,
340*4882a593Smuzhiyun .name = NETLBL_NLTYPE_CALIPSO_NAME,
341*4882a593Smuzhiyun .version = NETLBL_PROTO_VERSION,
342*4882a593Smuzhiyun .maxattr = NLBL_CALIPSO_A_MAX,
343*4882a593Smuzhiyun .policy = calipso_genl_policy,
344*4882a593Smuzhiyun .module = THIS_MODULE,
345*4882a593Smuzhiyun .small_ops = netlbl_calipso_ops,
346*4882a593Smuzhiyun .n_small_ops = ARRAY_SIZE(netlbl_calipso_ops),
347*4882a593Smuzhiyun };
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /* NetLabel Generic NETLINK Protocol Functions
350*4882a593Smuzhiyun */
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun /**
353*4882a593Smuzhiyun * netlbl_calipso_genl_init - Register the CALIPSO NetLabel component
354*4882a593Smuzhiyun *
355*4882a593Smuzhiyun * Description:
356*4882a593Smuzhiyun * Register the CALIPSO packet NetLabel component with the Generic NETLINK
357*4882a593Smuzhiyun * mechanism. Returns zero on success, negative values on failure.
358*4882a593Smuzhiyun *
359*4882a593Smuzhiyun */
netlbl_calipso_genl_init(void)360*4882a593Smuzhiyun int __init netlbl_calipso_genl_init(void)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun return genl_register_family(&netlbl_calipso_gnl_family);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun static const struct netlbl_calipso_ops *calipso_ops;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun /**
368*4882a593Smuzhiyun * netlbl_calipso_ops_register - Register the CALIPSO operations
369*4882a593Smuzhiyun *
370*4882a593Smuzhiyun * Description:
371*4882a593Smuzhiyun * Register the CALIPSO packet engine operations.
372*4882a593Smuzhiyun *
373*4882a593Smuzhiyun */
374*4882a593Smuzhiyun const struct netlbl_calipso_ops *
netlbl_calipso_ops_register(const struct netlbl_calipso_ops * ops)375*4882a593Smuzhiyun netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun return xchg(&calipso_ops, ops);
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun EXPORT_SYMBOL(netlbl_calipso_ops_register);
380*4882a593Smuzhiyun
netlbl_calipso_ops_get(void)381*4882a593Smuzhiyun static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun return READ_ONCE(calipso_ops);
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun /**
387*4882a593Smuzhiyun * calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
388*4882a593Smuzhiyun * @doi_def: the DOI structure
389*4882a593Smuzhiyun * @audit_info: NetLabel audit information
390*4882a593Smuzhiyun *
391*4882a593Smuzhiyun * Description:
392*4882a593Smuzhiyun * The caller defines a new DOI for use by the CALIPSO engine and calls this
393*4882a593Smuzhiyun * function to add it to the list of acceptable domains. The caller must
394*4882a593Smuzhiyun * ensure that the mapping table specified in @doi_def->map meets all of the
395*4882a593Smuzhiyun * requirements of the mapping type (see calipso.h for details). Returns
396*4882a593Smuzhiyun * zero on success and non-zero on failure.
397*4882a593Smuzhiyun *
398*4882a593Smuzhiyun */
calipso_doi_add(struct calipso_doi * doi_def,struct netlbl_audit * audit_info)399*4882a593Smuzhiyun int calipso_doi_add(struct calipso_doi *doi_def,
400*4882a593Smuzhiyun struct netlbl_audit *audit_info)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun int ret_val = -ENOMSG;
403*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun if (ops)
406*4882a593Smuzhiyun ret_val = ops->doi_add(doi_def, audit_info);
407*4882a593Smuzhiyun return ret_val;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun /**
411*4882a593Smuzhiyun * calipso_doi_free - Frees a DOI definition
412*4882a593Smuzhiyun * @doi_def: the DOI definition
413*4882a593Smuzhiyun *
414*4882a593Smuzhiyun * Description:
415*4882a593Smuzhiyun * This function frees all of the memory associated with a DOI definition.
416*4882a593Smuzhiyun *
417*4882a593Smuzhiyun */
calipso_doi_free(struct calipso_doi * doi_def)418*4882a593Smuzhiyun void calipso_doi_free(struct calipso_doi *doi_def)
419*4882a593Smuzhiyun {
420*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun if (ops)
423*4882a593Smuzhiyun ops->doi_free(doi_def);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /**
427*4882a593Smuzhiyun * calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
428*4882a593Smuzhiyun * @doi: the DOI value
429*4882a593Smuzhiyun * @audit_info: NetLabel audit information
430*4882a593Smuzhiyun *
431*4882a593Smuzhiyun * Description:
432*4882a593Smuzhiyun * Removes a DOI definition from the CALIPSO engine. The NetLabel routines will
433*4882a593Smuzhiyun * be called to release their own LSM domain mappings as well as our own
434*4882a593Smuzhiyun * domain list. Returns zero on success and negative values on failure.
435*4882a593Smuzhiyun *
436*4882a593Smuzhiyun */
calipso_doi_remove(u32 doi,struct netlbl_audit * audit_info)437*4882a593Smuzhiyun int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun int ret_val = -ENOMSG;
440*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun if (ops)
443*4882a593Smuzhiyun ret_val = ops->doi_remove(doi, audit_info);
444*4882a593Smuzhiyun return ret_val;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun /**
448*4882a593Smuzhiyun * calipso_doi_getdef - Returns a reference to a valid DOI definition
449*4882a593Smuzhiyun * @doi: the DOI value
450*4882a593Smuzhiyun *
451*4882a593Smuzhiyun * Description:
452*4882a593Smuzhiyun * Searches for a valid DOI definition and if one is found it is returned to
453*4882a593Smuzhiyun * the caller. Otherwise NULL is returned. The caller must ensure that
454*4882a593Smuzhiyun * calipso_doi_putdef() is called when the caller is done.
455*4882a593Smuzhiyun *
456*4882a593Smuzhiyun */
calipso_doi_getdef(u32 doi)457*4882a593Smuzhiyun struct calipso_doi *calipso_doi_getdef(u32 doi)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun struct calipso_doi *ret_val = NULL;
460*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun if (ops)
463*4882a593Smuzhiyun ret_val = ops->doi_getdef(doi);
464*4882a593Smuzhiyun return ret_val;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /**
468*4882a593Smuzhiyun * calipso_doi_putdef - Releases a reference for the given DOI definition
469*4882a593Smuzhiyun * @doi_def: the DOI definition
470*4882a593Smuzhiyun *
471*4882a593Smuzhiyun * Description:
472*4882a593Smuzhiyun * Releases a DOI definition reference obtained from calipso_doi_getdef().
473*4882a593Smuzhiyun *
474*4882a593Smuzhiyun */
calipso_doi_putdef(struct calipso_doi * doi_def)475*4882a593Smuzhiyun void calipso_doi_putdef(struct calipso_doi *doi_def)
476*4882a593Smuzhiyun {
477*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun if (ops)
480*4882a593Smuzhiyun ops->doi_putdef(doi_def);
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun /**
484*4882a593Smuzhiyun * calipso_doi_walk - Iterate through the DOI definitions
485*4882a593Smuzhiyun * @skip_cnt: skip past this number of DOI definitions, updated
486*4882a593Smuzhiyun * @callback: callback for each DOI definition
487*4882a593Smuzhiyun * @cb_arg: argument for the callback function
488*4882a593Smuzhiyun *
489*4882a593Smuzhiyun * Description:
490*4882a593Smuzhiyun * Iterate over the DOI definition list, skipping the first @skip_cnt entries.
491*4882a593Smuzhiyun * For each entry call @callback, if @callback returns a negative value stop
492*4882a593Smuzhiyun * 'walking' through the list and return. Updates the value in @skip_cnt upon
493*4882a593Smuzhiyun * return. Returns zero on success, negative values on failure.
494*4882a593Smuzhiyun *
495*4882a593Smuzhiyun */
calipso_doi_walk(u32 * skip_cnt,int (* callback)(struct calipso_doi * doi_def,void * arg),void * cb_arg)496*4882a593Smuzhiyun int calipso_doi_walk(u32 *skip_cnt,
497*4882a593Smuzhiyun int (*callback)(struct calipso_doi *doi_def, void *arg),
498*4882a593Smuzhiyun void *cb_arg)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun int ret_val = -ENOMSG;
501*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun if (ops)
504*4882a593Smuzhiyun ret_val = ops->doi_walk(skip_cnt, callback, cb_arg);
505*4882a593Smuzhiyun return ret_val;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun /**
509*4882a593Smuzhiyun * calipso_sock_getattr - Get the security attributes from a sock
510*4882a593Smuzhiyun * @sk: the sock
511*4882a593Smuzhiyun * @secattr: the security attributes
512*4882a593Smuzhiyun *
513*4882a593Smuzhiyun * Description:
514*4882a593Smuzhiyun * Query @sk to see if there is a CALIPSO option attached to the sock and if
515*4882a593Smuzhiyun * there is return the CALIPSO security attributes in @secattr. This function
516*4882a593Smuzhiyun * requires that @sk be locked, or privately held, but it does not do any
517*4882a593Smuzhiyun * locking itself. Returns zero on success and negative values on failure.
518*4882a593Smuzhiyun *
519*4882a593Smuzhiyun */
calipso_sock_getattr(struct sock * sk,struct netlbl_lsm_secattr * secattr)520*4882a593Smuzhiyun int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun int ret_val = -ENOMSG;
523*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun if (ops)
526*4882a593Smuzhiyun ret_val = ops->sock_getattr(sk, secattr);
527*4882a593Smuzhiyun return ret_val;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /**
531*4882a593Smuzhiyun * calipso_sock_setattr - Add a CALIPSO option to a socket
532*4882a593Smuzhiyun * @sk: the socket
533*4882a593Smuzhiyun * @doi_def: the CALIPSO DOI to use
534*4882a593Smuzhiyun * @secattr: the specific security attributes of the socket
535*4882a593Smuzhiyun *
536*4882a593Smuzhiyun * Description:
537*4882a593Smuzhiyun * Set the CALIPSO option on the given socket using the DOI definition and
538*4882a593Smuzhiyun * security attributes passed to the function. This function requires
539*4882a593Smuzhiyun * exclusive access to @sk, which means it either needs to be in the
540*4882a593Smuzhiyun * process of being created or locked. Returns zero on success and negative
541*4882a593Smuzhiyun * values on failure.
542*4882a593Smuzhiyun *
543*4882a593Smuzhiyun */
calipso_sock_setattr(struct sock * sk,const struct calipso_doi * doi_def,const struct netlbl_lsm_secattr * secattr)544*4882a593Smuzhiyun int calipso_sock_setattr(struct sock *sk,
545*4882a593Smuzhiyun const struct calipso_doi *doi_def,
546*4882a593Smuzhiyun const struct netlbl_lsm_secattr *secattr)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun int ret_val = -ENOMSG;
549*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun if (ops)
552*4882a593Smuzhiyun ret_val = ops->sock_setattr(sk, doi_def, secattr);
553*4882a593Smuzhiyun return ret_val;
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /**
557*4882a593Smuzhiyun * calipso_sock_delattr - Delete the CALIPSO option from a socket
558*4882a593Smuzhiyun * @sk: the socket
559*4882a593Smuzhiyun *
560*4882a593Smuzhiyun * Description:
561*4882a593Smuzhiyun * Removes the CALIPSO option from a socket, if present.
562*4882a593Smuzhiyun *
563*4882a593Smuzhiyun */
calipso_sock_delattr(struct sock * sk)564*4882a593Smuzhiyun void calipso_sock_delattr(struct sock *sk)
565*4882a593Smuzhiyun {
566*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (ops)
569*4882a593Smuzhiyun ops->sock_delattr(sk);
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun
572*4882a593Smuzhiyun /**
573*4882a593Smuzhiyun * calipso_req_setattr - Add a CALIPSO option to a connection request socket
574*4882a593Smuzhiyun * @req: the connection request socket
575*4882a593Smuzhiyun * @doi_def: the CALIPSO DOI to use
576*4882a593Smuzhiyun * @secattr: the specific security attributes of the socket
577*4882a593Smuzhiyun *
578*4882a593Smuzhiyun * Description:
579*4882a593Smuzhiyun * Set the CALIPSO option on the given socket using the DOI definition and
580*4882a593Smuzhiyun * security attributes passed to the function. Returns zero on success and
581*4882a593Smuzhiyun * negative values on failure.
582*4882a593Smuzhiyun *
583*4882a593Smuzhiyun */
calipso_req_setattr(struct request_sock * req,const struct calipso_doi * doi_def,const struct netlbl_lsm_secattr * secattr)584*4882a593Smuzhiyun int calipso_req_setattr(struct request_sock *req,
585*4882a593Smuzhiyun const struct calipso_doi *doi_def,
586*4882a593Smuzhiyun const struct netlbl_lsm_secattr *secattr)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun int ret_val = -ENOMSG;
589*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun if (ops)
592*4882a593Smuzhiyun ret_val = ops->req_setattr(req, doi_def, secattr);
593*4882a593Smuzhiyun return ret_val;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun /**
597*4882a593Smuzhiyun * calipso_req_delattr - Delete the CALIPSO option from a request socket
598*4882a593Smuzhiyun * @req: the request socket
599*4882a593Smuzhiyun *
600*4882a593Smuzhiyun * Description:
601*4882a593Smuzhiyun * Removes the CALIPSO option from a request socket, if present.
602*4882a593Smuzhiyun *
603*4882a593Smuzhiyun */
calipso_req_delattr(struct request_sock * req)604*4882a593Smuzhiyun void calipso_req_delattr(struct request_sock *req)
605*4882a593Smuzhiyun {
606*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if (ops)
609*4882a593Smuzhiyun ops->req_delattr(req);
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun /**
613*4882a593Smuzhiyun * calipso_optptr - Find the CALIPSO option in the packet
614*4882a593Smuzhiyun * @skb: the packet
615*4882a593Smuzhiyun *
616*4882a593Smuzhiyun * Description:
617*4882a593Smuzhiyun * Parse the packet's IP header looking for a CALIPSO option. Returns a pointer
618*4882a593Smuzhiyun * to the start of the CALIPSO option on success, NULL if one if not found.
619*4882a593Smuzhiyun *
620*4882a593Smuzhiyun */
calipso_optptr(const struct sk_buff * skb)621*4882a593Smuzhiyun unsigned char *calipso_optptr(const struct sk_buff *skb)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun unsigned char *ret_val = NULL;
624*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun if (ops)
627*4882a593Smuzhiyun ret_val = ops->skbuff_optptr(skb);
628*4882a593Smuzhiyun return ret_val;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun /**
632*4882a593Smuzhiyun * calipso_getattr - Get the security attributes from a memory block.
633*4882a593Smuzhiyun * @calipso: the CALIPSO option
634*4882a593Smuzhiyun * @secattr: the security attributes
635*4882a593Smuzhiyun *
636*4882a593Smuzhiyun * Description:
637*4882a593Smuzhiyun * Inspect @calipso and return the security attributes in @secattr.
638*4882a593Smuzhiyun * Returns zero on success and negative values on failure.
639*4882a593Smuzhiyun *
640*4882a593Smuzhiyun */
calipso_getattr(const unsigned char * calipso,struct netlbl_lsm_secattr * secattr)641*4882a593Smuzhiyun int calipso_getattr(const unsigned char *calipso,
642*4882a593Smuzhiyun struct netlbl_lsm_secattr *secattr)
643*4882a593Smuzhiyun {
644*4882a593Smuzhiyun int ret_val = -ENOMSG;
645*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun if (ops)
648*4882a593Smuzhiyun ret_val = ops->opt_getattr(calipso, secattr);
649*4882a593Smuzhiyun return ret_val;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun /**
653*4882a593Smuzhiyun * calipso_skbuff_setattr - Set the CALIPSO option on a packet
654*4882a593Smuzhiyun * @skb: the packet
655*4882a593Smuzhiyun * @doi_def: the CALIPSO DOI to use
656*4882a593Smuzhiyun * @secattr: the security attributes
657*4882a593Smuzhiyun *
658*4882a593Smuzhiyun * Description:
659*4882a593Smuzhiyun * Set the CALIPSO option on the given packet based on the security attributes.
660*4882a593Smuzhiyun * Returns a pointer to the IP header on success and NULL on failure.
661*4882a593Smuzhiyun *
662*4882a593Smuzhiyun */
calipso_skbuff_setattr(struct sk_buff * skb,const struct calipso_doi * doi_def,const struct netlbl_lsm_secattr * secattr)663*4882a593Smuzhiyun int calipso_skbuff_setattr(struct sk_buff *skb,
664*4882a593Smuzhiyun const struct calipso_doi *doi_def,
665*4882a593Smuzhiyun const struct netlbl_lsm_secattr *secattr)
666*4882a593Smuzhiyun {
667*4882a593Smuzhiyun int ret_val = -ENOMSG;
668*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun if (ops)
671*4882a593Smuzhiyun ret_val = ops->skbuff_setattr(skb, doi_def, secattr);
672*4882a593Smuzhiyun return ret_val;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun /**
676*4882a593Smuzhiyun * calipso_skbuff_delattr - Delete any CALIPSO options from a packet
677*4882a593Smuzhiyun * @skb: the packet
678*4882a593Smuzhiyun *
679*4882a593Smuzhiyun * Description:
680*4882a593Smuzhiyun * Removes any and all CALIPSO options from the given packet. Returns zero on
681*4882a593Smuzhiyun * success, negative values on failure.
682*4882a593Smuzhiyun *
683*4882a593Smuzhiyun */
calipso_skbuff_delattr(struct sk_buff * skb)684*4882a593Smuzhiyun int calipso_skbuff_delattr(struct sk_buff *skb)
685*4882a593Smuzhiyun {
686*4882a593Smuzhiyun int ret_val = -ENOMSG;
687*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun if (ops)
690*4882a593Smuzhiyun ret_val = ops->skbuff_delattr(skb);
691*4882a593Smuzhiyun return ret_val;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun /**
695*4882a593Smuzhiyun * calipso_cache_invalidate - Invalidates the current CALIPSO cache
696*4882a593Smuzhiyun *
697*4882a593Smuzhiyun * Description:
698*4882a593Smuzhiyun * Invalidates and frees any entries in the CALIPSO cache. Returns zero on
699*4882a593Smuzhiyun * success and negative values on failure.
700*4882a593Smuzhiyun *
701*4882a593Smuzhiyun */
calipso_cache_invalidate(void)702*4882a593Smuzhiyun void calipso_cache_invalidate(void)
703*4882a593Smuzhiyun {
704*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun if (ops)
707*4882a593Smuzhiyun ops->cache_invalidate();
708*4882a593Smuzhiyun }
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun /**
711*4882a593Smuzhiyun * calipso_cache_add - Add an entry to the CALIPSO cache
712*4882a593Smuzhiyun * @calipso_ptr: the CALIPSO option
713*4882a593Smuzhiyun * @secattr: the packet's security attributes
714*4882a593Smuzhiyun *
715*4882a593Smuzhiyun * Description:
716*4882a593Smuzhiyun * Add a new entry into the CALIPSO label mapping cache.
717*4882a593Smuzhiyun * Returns zero on success, negative values on failure.
718*4882a593Smuzhiyun *
719*4882a593Smuzhiyun */
calipso_cache_add(const unsigned char * calipso_ptr,const struct netlbl_lsm_secattr * secattr)720*4882a593Smuzhiyun int calipso_cache_add(const unsigned char *calipso_ptr,
721*4882a593Smuzhiyun const struct netlbl_lsm_secattr *secattr)
722*4882a593Smuzhiyun
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun int ret_val = -ENOMSG;
725*4882a593Smuzhiyun const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun if (ops)
728*4882a593Smuzhiyun ret_val = ops->cache_add(calipso_ptr, secattr);
729*4882a593Smuzhiyun return ret_val;
730*4882a593Smuzhiyun }
731