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