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