From: Roberto De Ioris <roberto@unbit.it>
To: linux-security-module@vger.kernel.org,
linux-kernel <linux-kernel@vger.kernel.org>
Subject: [ANNOUNCE] UidBind LSM 0.2
Date: Tue, 24 Apr 2007 16:34:22 +0200 [thread overview]
Message-ID: <1177425262.6547.24.camel@hagrid> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 647 bytes --]
Hi all,
this is the second release for UidBind LSM:
http://projects.unbit.it/uidbind/
UidBind allows call to bind() function only to the uid defined in a
configfs tree.
It is now possible to specify different uid (for the same port) on
different ipv4 addresses:
mkdir uidbind/8081
mkdir uidbind/8081/192.168.1.17
mkdir uidbind/8081/192.168.1.26
echo 1017 > uidbind/8081/192.168.1.17/uid
echo 1026 > uidbind/8081/192.168.1.26/uid
This version even fix some leek in version 0.1
Patch attached is still for vanilla 2.6.20.7
--
Roberto De Ioris
http://unbit.it
JID: roberto@jabber.unbit.it
Wii: 2999 4476 3509 0964
[-- Attachment #1.2: uidbind-lsm-0.2.patch --]
[-- Type: text/x-patch, Size: 15966 bytes --]
diff -Naur linux-2.6.20.7/security/Kconfig linux-2.6.20.7-uidbind/security/Kconfig
--- linux-2.6.20.7/security/Kconfig 2007-04-13 22:48:14.000000000 +0200
+++ linux-2.6.20.7-uidbind/security/Kconfig 2007-04-23 09:32:15.000000000 +0200
@@ -93,6 +93,18 @@
If you are unsure how to answer this question, answer N.
+config SECURITY_UIDBIND
+ tristate "UidBind"
+ depends on CONFIGFS_FS && SECURITY && SECURITY_NETWORK
+ help
+ This simple module allows call to bind() function only for
+ uid defined in a configfs tree.
+ The only supported socket is PF_INET.
+
+ See <http://projects.unbit.it/uidbind> for more information about
+ this module
+
+
source security/selinux/Kconfig
endmenu
diff -Naur linux-2.6.20.7/security/Makefile linux-2.6.20.7-uidbind/security/Makefile
--- linux-2.6.20.7/security/Makefile 2007-04-13 22:48:14.000000000 +0200
+++ linux-2.6.20.7-uidbind/security/Makefile 2007-04-23 09:30:37.000000000 +0200
@@ -16,3 +16,4 @@
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+obj-$(CONFIG_SECURITY_UIDBIND) += commoncap.o uidbind.o
diff -Naur linux-2.6.20.7/security/uidbind.c linux-2.6.20.7-uidbind/security/uidbind.c
--- linux-2.6.20.7/security/uidbind.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.20.7-uidbind/security/uidbind.c 2007-04-24 16:17:44.000000000 +0200
@@ -0,0 +1,467 @@
+/* UidBind 0.2 LSM
+ * Permit bind() function only to one uid
+ *
+ * See <http://projects.unbit.it/uidbind/> for (little) more info
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ *
+ * Changelog
+ *
+ * 20070423 -> version 0.1 (first release)
+ *
+ *
+ * 20070424 -> version 0.2 (bugfix for some erroneous string management, added tcp/udp and ipv4 addresses support in rules)
+ *
+*/
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/security.h>
+#include <linux/socket.h>
+#include <linux/inet.h>
+#include <net/ip.h>
+#include <linux/configfs.h>
+
+
+/* flag to keep track of how we were registered */
+static int secondary;
+
+static int debug = 1;
+
+
+#define MY_NAME "uidbind"
+#define UIDBIND_LABEL "[UidBind] "
+
+#define MAXPORTCHAR 6
+#define MAXADDRCHAR 16
+
+struct port_config_group {
+ struct config_group group;
+ uid_t uid;
+ uid_t tcp_uid;
+ uid_t udp_uid;
+};
+
+struct port_config_item {
+ struct config_item item;
+ uid_t uid;
+ uid_t tcp_uid;
+ uid_t udp_uid;
+};
+
+
+
+static struct config_item *port_addr_make(struct config_group *, const char *) ;
+static struct config_group *port_group_make(struct config_group *, const char *) ;
+static ssize_t port_groupattr_show(struct config_item *, struct configfs_attribute *, char *) ;
+static ssize_t port_groupattr_store(struct config_item *, struct configfs_attribute *, const char *, size_t) ;
+static ssize_t port_attr_show(struct config_item *, struct configfs_attribute *, char *) ;
+static ssize_t port_attr_store(struct config_item *, struct configfs_attribute *, const char *, size_t) ;
+
+
+static struct configfs_attribute port_uid_attr = { .ca_owner = THIS_MODULE, .ca_name = "uid", .ca_mode = S_IRUSR | S_IWUSR } ;
+static struct configfs_attribute port_tcp_attr = { .ca_owner = THIS_MODULE, .ca_name = "tcp_uid", .ca_mode = S_IRUSR | S_IWUSR } ;
+static struct configfs_attribute port_udp_attr = { .ca_owner = THIS_MODULE, .ca_name = "udp_uid", .ca_mode = S_IRUSR | S_IWUSR } ;
+
+/* port attributes */
+static struct configfs_attribute *port_attrs[] = { &port_uid_attr , &port_tcp_attr ,&port_udp_attr , NULL } ;
+
+static struct configfs_group_operations port_item_group_ops = { .make_item = port_addr_make } ;
+
+
+
+
+static void uidbind_group_release(struct config_item *item)
+{
+ kfree(container_of(to_config_group(item),struct port_config_group,group));
+}
+
+static void uidbind_item_release(struct config_item *item)
+{
+ kfree(container_of(item,struct port_config_item,item));
+}
+
+/* port ops */
+static struct configfs_item_operations port_addritem_ops = { .show_attribute = port_attr_show, .store_attribute = port_attr_store } ;
+static struct configfs_item_operations port_item_ops = {.release = uidbind_item_release, .show_attribute = port_groupattr_show, .store_attribute = port_groupattr_store } ;
+
+/* configfs types */
+static struct config_item_type port_type = { .ct_item_ops = &port_item_ops, .ct_group_ops = &port_item_group_ops , .ct_attrs = port_attrs, .ct_owner = THIS_MODULE } ;
+static struct config_item_type portaddr_type = { .ct_item_ops = &port_addritem_ops, .ct_attrs = port_attrs, .ct_owner = THIS_MODULE } ;
+
+
+static struct config_item *port_addr_make(struct config_group *group, const char *name) {
+ struct port_config_item *portitem ;
+ u8 ipv4addr[4];
+ const char *end;
+ int ret = 0 ;
+
+ /* valid ipv4 address ? */
+ ret = in4_pton(name, strlen(name), ipv4addr, -1, &end) ;
+
+ if (ret == 0) {
+ printk(KERN_ERR UIDBIND_LABEL "invalid ipv4 address: %s\n", name) ;
+ return NULL ;
+ }
+
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "ip validated by in4_pton: %u.%u.%u.%u\n", NIPQUAD(ipv4addr)) ;
+
+
+ portitem = kmalloc(sizeof(struct port_config_item), GFP_KERNEL);
+
+ if (!portitem)
+ return NULL ;
+
+
+ memset(portitem, 0 , sizeof(struct port_config_item)) ;
+ config_item_init_type_name(&portitem->item, name, &portaddr_type) ;
+
+ portitem->uid = 0 ;
+ portitem->tcp_uid = 0 ;
+ portitem->udp_uid = 0 ;
+
+ return &portitem->item ;
+}
+
+
+
+
+
+static struct config_group *port_group_make(struct config_group *group, const char *name) {
+
+ struct port_config_group *portgroup ;
+ unsigned short port_num ;
+
+ /* valid port number ? */
+ port_num = simple_strtoul(name,NULL,0) ;
+
+ if (port_num < 1024 || !port_num) {
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "Invalid port number: %s\n", name) ;
+
+ return NULL ;
+ }
+
+ portgroup = kmalloc(sizeof(struct port_config_group), GFP_KERNEL);
+
+ if (!portgroup) return NULL ;
+
+
+ memset(portgroup, 0 , sizeof(struct port_config_group)) ;
+
+ config_group_init_type_name(&portgroup->group, name, &port_type) ;
+
+ portgroup->uid = 0 ;
+ portgroup->tcp_uid = 0 ;
+ portgroup->udp_uid = 0 ;
+
+ printk(KERN_DEBUG UIDBIND_LABEL "uid %u\n", portgroup->uid) ;
+
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "Assigned default rule to port %s\n", name) ;
+
+ return &portgroup->group ;
+}
+
+
+static struct configfs_group_operations port_group_ops = { .make_group = port_group_make } ;
+static struct configfs_item_operations port_release_ops = { .release = uidbind_group_release } ;
+static struct config_item_type uidbind_type = { .ct_item_ops = &port_release_ops, .ct_group_ops = &port_group_ops, .ct_owner = THIS_MODULE } ;
+
+
+
+/* configfs subsys */
+static struct configfs_subsystem uidbind_subsys = { .su_group = { .cg_item = { .ci_namebuf = "uidbind", .ci_type = &uidbind_type} } } ;
+
+static ssize_t port_groupattr_show(struct config_item *item, struct configfs_attribute *attr, char *page) {
+ ssize_t ret = 0;
+ uid_t uid = 0 ;
+
+ struct port_config_group *port_config = container_of(to_config_group(item), struct port_config_group, group) ;
+
+ if (attr->ca_name == "uid") uid = port_config->uid ;
+ if (attr->ca_name == "tcp_uid") uid = port_config->tcp_uid ;
+ if (attr->ca_name == "udp_uid") uid = port_config->udp_uid ;
+
+
+ ret = sprintf(page, "%u\n", uid ) ;
+
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "Reading %s attr for item %s\n", attr->ca_name, item->ci_name) ;
+
+ return ret ;
+}
+
+static ssize_t port_groupattr_store(struct config_item *item, struct configfs_attribute *attr, const char *page, size_t count) {
+ ssize_t ret = -EINVAL;
+ uid_t uid = 0 ;
+
+ struct port_config_group *port_config = container_of(to_config_group(item), struct port_config_group, group) ;
+
+ uid = simple_strtoul(page, NULL, 0) ;
+
+
+ if (attr->ca_name == "uid") port_config->uid = uid ;
+ if (attr->ca_name == "tcp_uid") port_config->tcp_uid = uid ;
+ if (attr->ca_name == "udp_uid") port_config->udp_uid = uid ;
+
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "Assigned %s %u to item %s\n", attr->ca_name, uid, item->ci_name) ;
+
+ ret = count ;
+
+ return ret;
+}
+
+
+static ssize_t port_attr_show(struct config_item *item, struct configfs_attribute *attr, char *page) {
+ ssize_t ret = 0;
+ uid_t uid = 0 ;
+
+ struct port_config_item *port_config = container_of(item, struct port_config_item, item) ;
+
+ if (attr->ca_name == "uid") uid = port_config->uid ;
+ if (attr->ca_name == "tcp_uid") uid = port_config->tcp_uid ;
+ if (attr->ca_name == "udp_uid") uid = port_config->udp_uid ;
+
+ ret = sprintf(page, "%u\n", uid ) ;
+
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "Reading %s attr for item %s\n", attr->ca_name, item->ci_name) ;
+
+ return ret ;
+}
+
+static ssize_t port_attr_store(struct config_item *item, struct configfs_attribute *attr, const char *page, size_t count) {
+ ssize_t ret = -EINVAL;
+ uid_t uid = 0 ;
+
+ struct port_config_item *port_config = container_of(item, struct port_config_item, item) ;
+
+ uid = simple_strtoul(page, NULL, 0) ;
+
+
+ if (attr->ca_name == "uid") port_config->uid = uid ;
+ if (attr->ca_name == "tcp_uid") port_config->tcp_uid = uid ;
+ if (attr->ca_name == "udp_uid") port_config->udp_uid = uid ;
+
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "Assigned %s %u to item %s\n", attr->ca_name, uid, item->ci_name) ;
+
+ ret = count ;
+
+ return ret;
+}
+
+
+
+
+static int uidbind_socket_bind_check (struct socket *sock, struct sockaddr *address, int addrlen)
+{
+
+ u16 family ;
+ struct sockaddr_in *addr4 ;
+ struct config_item *portaddrconfig ;
+ struct config_item *portgroupconfig ;
+ struct port_config_group *portfoundgroup ;
+ struct port_config_item *portfoundaddr ;
+ unsigned short socket_port;
+ char strport[MAXPORTCHAR] ;
+ char ipaddr[MAXADDRCHAR] ;
+
+ if (current->uid == 0)
+ return 0 ;
+
+
+ /* check order
+ *
+ * uidbind/<port>/<ip>/<proto>_uid
+ * uidbind/<port>/<ip>/uid
+ * uidbind/<port>/<proto>_uid
+ * uidbind/<port>/uid
+ *
+ */
+
+ family = sock->sk->sk_family;
+
+
+ if (family == PF_INET) {
+
+ addr4 = (struct sockaddr_in *)address;
+ socket_port = ntohs(addr4->sin_port);
+ sprintf(ipaddr,"%u.%u.%u.%u",NIPQUAD(addr4->sin_addr.s_addr)) ;
+
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "bind() attempt on port %u (%u) interface %s by process [%s] uid [%u]\n", socket_port, sock->sk->sk_protocol, ipaddr, current->comm, current->uid) ;
+
+ sprintf(strport,"%u", socket_port) ;
+
+ portgroupconfig = config_group_find_obj(&uidbind_subsys.su_group,strport) ;
+
+ if (!portgroupconfig) {
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "Configuration for port %s unavailable\n", strport ) ;
+
+ return -EACCES;
+ }
+
+
+ portfoundgroup = container_of(to_config_group(portgroupconfig), struct port_config_group, group) ;
+
+ portaddrconfig = config_group_find_obj(&portfoundgroup->group,ipaddr) ;
+
+ /* configfs address specified ? */
+
+ if (portaddrconfig) {
+
+ portfoundaddr = container_of(portaddrconfig, struct port_config_item, item) ;
+
+ if (sock->sk->sk_protocol == IPPROTO_TCP) {
+ if (portfoundaddr->tcp_uid != 0) {
+ if (portfoundaddr->tcp_uid == current->uid) {
+ return 0 ;
+ }
+ }
+
+ }
+
+ if (sock->sk->sk_protocol == IPPROTO_UDP) {
+ if (portfoundaddr->udp_uid != 0) {
+ if (portfoundaddr->udp_uid == current->uid) {
+ return 0 ;
+ }
+ }
+ }
+
+
+ if (portfoundaddr->uid != 0) {
+ if (portfoundaddr->uid == current->uid) {
+ return 0 ;
+ }
+ }
+
+ }
+
+ /* address check failed ... */
+
+ if (sock->sk->sk_protocol == IPPROTO_TCP) {
+ if (portfoundgroup->tcp_uid != 0) {
+ if (portfoundgroup->tcp_uid == current->uid) {
+ return 0 ;
+ }
+ }
+ }
+
+ if (sock->sk->sk_protocol == IPPROTO_UDP) {
+ if (portfoundgroup->udp_uid != 0) {
+ if (portfoundgroup->udp_uid == current->uid) {
+ return 0 ;
+ }
+ }
+ }
+
+ if (portfoundgroup->uid == current->uid) {
+ return 0;
+ }
+
+ if (debug)
+ printk(KERN_DEBUG UIDBIND_LABEL "bind() by default permitted only to uid %u\n", portfoundgroup->uid) ;
+
+ return -EACCES ;
+
+ }
+
+ return 0;
+}
+
+static struct security_operations uidbind_security_ops = {
+ /* general capability */
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .settime = cap_settime,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = cap_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+
+ .inode_setxattr = cap_inode_setxattr,
+ .inode_removexattr = cap_inode_removexattr,
+
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+
+ .syslog = cap_syslog,
+
+ .vm_enough_memory = cap_vm_enough_memory,
+
+
+ /* uidbind hook */
+ .socket_bind = uidbind_socket_bind_check
+};
+
+
+static int __init uidbind_init (void)
+{
+
+ int ret ;
+
+ if (register_security (&uidbind_security_ops)) {
+ printk (KERN_INFO UIDBIND_LABEL "Failure registering module with the kernel\n");
+ if (mod_reg_security (MY_NAME, &uidbind_security_ops)) {
+ printk (KERN_INFO UIDBIND_LABEL "Failure registering module as secondary\n") ;
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+
+ config_group_init(&uidbind_subsys.su_group);
+ init_MUTEX(&uidbind_subsys.su_sem);
+ ret = configfs_register_subsystem(&uidbind_subsys);
+
+ if (ret) {
+ printk(KERN_ERR UIDBIND_LABEL "Error while registering configfs subsys\n") ;
+ configfs_unregister_subsystem(&uidbind_subsys);
+ return ret ;
+ }
+
+ printk (KERN_INFO UIDBIND_LABEL "Module initialized\n") ;
+ return 0;
+}
+
+static void __exit uidbind_exit (void)
+{
+ if (secondary) {
+ if (mod_unreg_security (MY_NAME, &uidbind_security_ops))
+ printk (KERN_INFO UIDBIND_LABEL "Failure unregistering module as primary\n") ;
+ } else {
+ if (unregister_security (&uidbind_security_ops)) {
+ printk (KERN_INFO UIDBIND_LABEL "Failure unregistering module\n") ;
+ }
+ }
+
+ configfs_unregister_subsystem(&uidbind_subsys) ;
+
+ printk (KERN_INFO UIDBIND_LABEL "Module removed\n");
+}
+
+
+
+security_initcall (uidbind_init);
+module_exit (uidbind_exit);
+
+MODULE_DESCRIPTION("UidBind 0.1");
+MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>");
+MODULE_LICENSE("GPL");
+
[-- Attachment #2: Questa è una parte del messaggio firmata digitalmente --]
[-- Type: application/pgp-signature, Size: 189 bytes --]
next reply other threads:[~2007-04-24 14:34 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-04-24 14:34 Roberto De Ioris [this message]
2007-04-24 20:13 ` [ANNOUNCE] UidBind LSM 0.2 Gerhard Mack
2007-04-24 20:40 ` Casey Schaufler
2007-04-24 22:11 ` Gerhard Mack
2007-04-25 7:28 ` Roberto De Ioris
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1177425262.6547.24.camel@hagrid \
--to=roberto@unbit.it \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.