xref: /OK3568_Linux_fs/kernel/security/selinux/netlink.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Netlink event notifications for SELinux.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Author: James Morris <jmorris@redhat.com>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun #include <linux/init.h>
10*4882a593Smuzhiyun #include <linux/types.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/stddef.h>
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/export.h>
15*4882a593Smuzhiyun #include <linux/skbuff.h>
16*4882a593Smuzhiyun #include <linux/selinux_netlink.h>
17*4882a593Smuzhiyun #include <net/net_namespace.h>
18*4882a593Smuzhiyun #include <net/netlink.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include "security.h"
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun static struct sock *selnl;
23*4882a593Smuzhiyun 
selnl_msglen(int msgtype)24*4882a593Smuzhiyun static int selnl_msglen(int msgtype)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	int ret = 0;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	switch (msgtype) {
29*4882a593Smuzhiyun 	case SELNL_MSG_SETENFORCE:
30*4882a593Smuzhiyun 		ret = sizeof(struct selnl_msg_setenforce);
31*4882a593Smuzhiyun 		break;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	case SELNL_MSG_POLICYLOAD:
34*4882a593Smuzhiyun 		ret = sizeof(struct selnl_msg_policyload);
35*4882a593Smuzhiyun 		break;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	default:
38*4882a593Smuzhiyun 		BUG();
39*4882a593Smuzhiyun 	}
40*4882a593Smuzhiyun 	return ret;
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun 
selnl_add_payload(struct nlmsghdr * nlh,int len,int msgtype,void * data)43*4882a593Smuzhiyun static void selnl_add_payload(struct nlmsghdr *nlh, int len, int msgtype, void *data)
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	switch (msgtype) {
46*4882a593Smuzhiyun 	case SELNL_MSG_SETENFORCE: {
47*4882a593Smuzhiyun 		struct selnl_msg_setenforce *msg = nlmsg_data(nlh);
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 		memset(msg, 0, len);
50*4882a593Smuzhiyun 		msg->val = *((int *)data);
51*4882a593Smuzhiyun 		break;
52*4882a593Smuzhiyun 	}
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	case SELNL_MSG_POLICYLOAD: {
55*4882a593Smuzhiyun 		struct selnl_msg_policyload *msg = nlmsg_data(nlh);
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun 		memset(msg, 0, len);
58*4882a593Smuzhiyun 		msg->seqno = *((u32 *)data);
59*4882a593Smuzhiyun 		break;
60*4882a593Smuzhiyun 	}
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	default:
63*4882a593Smuzhiyun 		BUG();
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
selnl_notify(int msgtype,void * data)67*4882a593Smuzhiyun static void selnl_notify(int msgtype, void *data)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	int len;
70*4882a593Smuzhiyun 	sk_buff_data_t tmp;
71*4882a593Smuzhiyun 	struct sk_buff *skb;
72*4882a593Smuzhiyun 	struct nlmsghdr *nlh;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	len = selnl_msglen(msgtype);
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	skb = nlmsg_new(len, GFP_USER);
77*4882a593Smuzhiyun 	if (!skb)
78*4882a593Smuzhiyun 		goto oom;
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	tmp = skb->tail;
81*4882a593Smuzhiyun 	nlh = nlmsg_put(skb, 0, 0, msgtype, len, 0);
82*4882a593Smuzhiyun 	if (!nlh)
83*4882a593Smuzhiyun 		goto out_kfree_skb;
84*4882a593Smuzhiyun 	selnl_add_payload(nlh, len, msgtype, data);
85*4882a593Smuzhiyun 	nlh->nlmsg_len = skb->tail - tmp;
86*4882a593Smuzhiyun 	NETLINK_CB(skb).dst_group = SELNLGRP_AVC;
87*4882a593Smuzhiyun 	netlink_broadcast(selnl, skb, 0, SELNLGRP_AVC, GFP_USER);
88*4882a593Smuzhiyun out:
89*4882a593Smuzhiyun 	return;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun out_kfree_skb:
92*4882a593Smuzhiyun 	kfree_skb(skb);
93*4882a593Smuzhiyun oom:
94*4882a593Smuzhiyun 	pr_err("SELinux:  OOM in %s\n", __func__);
95*4882a593Smuzhiyun 	goto out;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
selnl_notify_setenforce(int val)98*4882a593Smuzhiyun void selnl_notify_setenforce(int val)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	selnl_notify(SELNL_MSG_SETENFORCE, &val);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun 
selnl_notify_policyload(u32 seqno)103*4882a593Smuzhiyun void selnl_notify_policyload(u32 seqno)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun 	selnl_notify(SELNL_MSG_POLICYLOAD, &seqno);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
selnl_init(void)108*4882a593Smuzhiyun static int __init selnl_init(void)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	struct netlink_kernel_cfg cfg = {
111*4882a593Smuzhiyun 		.groups	= SELNLGRP_MAX,
112*4882a593Smuzhiyun 		.flags	= NL_CFG_F_NONROOT_RECV,
113*4882a593Smuzhiyun 	};
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	selnl = netlink_kernel_create(&init_net, NETLINK_SELINUX, &cfg);
116*4882a593Smuzhiyun 	if (selnl == NULL)
117*4882a593Smuzhiyun 		panic("SELinux:  Cannot create netlink socket.");
118*4882a593Smuzhiyun 	return 0;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun __initcall(selnl_init);
122