linux-stable/security/selinux/netlink.c
Pablo Neira Ayuso a31f2d17b3 netlink: add netlink_kernel_cfg parameter to netlink_kernel_create
This patch adds the following structure:

struct netlink_kernel_cfg {
        unsigned int    groups;
        void            (*input)(struct sk_buff *skb);
        struct mutex    *cb_mutex;
};

That can be passed to netlink_kernel_create to set optional configurations
for netlink kernel sockets.

I've populated this structure by looking for NULL and zero parameters at the
existing code. The remaining parameters that always need to be set are still
left in the original interface.

That includes optional parameters for the netlink socket creation. This allows
easy extensibility of this interface in the future.

This patch also adapts all callers to use this new interface.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
2012-06-29 16:46:02 -07:00

126 lines
2.5 KiB
C

/*
* Netlink event notifications for SELinux.
*
* Author: James Morris <jmorris@redhat.com>
*
* Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*/
#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/netlink.h>
#include <linux/selinux_netlink.h>
#include <net/net_namespace.h>
#include <net/netlink.h>
#include "security.h"
static struct sock *selnl;
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 = alloc_skb(NLMSG_SPACE(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:
printk(KERN_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,
};
selnl = netlink_kernel_create(&init_net, NETLINK_SELINUX,
THIS_MODULE, &cfg);
if (selnl == NULL)
panic("SELinux: Cannot create netlink socket.");
netlink_set_nonroot(NETLINK_SELINUX, NL_NONROOT_RECV);
return 0;
}
__initcall(selnl_init);