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 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-23 10:47:07.000000000 +0200 @@ -0,0 +1,263 @@ +/* UidBind 0.1 LSM + * Permit bind() function only to one uid + * + * See 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. + * +*/ + + +#include +#include +#include +#include +#include +#include +#include + + +/* flag to keep track of how we were registered */ +static int secondary; + +static int debug = 1; + + +#define MY_NAME "uidbind" +#define UIDBIND_LABEL "[UidBind] " + +struct port_config_item { + struct config_item item; + uid_t uid; +}; + +static ssize_t port_attr_show(struct config_item *item, struct configfs_attribute *attr, char *page) { + ssize_t ret = 0; + + struct port_config_item *port_config = container_of(item, struct port_config_item, item) ; + ret = sprintf(page, "%u\n", port_config->uid ) ; + + if (debug) + printk(KERN_DEBUG UIDBIND_LABEL "Reading uid attr for port %s\n", 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 ; + + struct port_config_item *port_config = container_of(item, struct port_config_item, item) ; + + uid = simple_strtoul(page, NULL, 0) ; + + if (!uid) + return ret ; + + + port_config->uid = uid ; + + if (debug) + printk(KERN_DEBUG UIDBIND_LABEL "Assigned uid %u to port %s\n", uid, item->ci_name) ; + + ret = count ; + + return ret; +} + +static struct configfs_attribute port_uid_attr = { .ca_owner = THIS_MODULE, .ca_name = "uid", .ca_mode = S_IRUSR | S_IWUSR } ; + +/* port attributes */ +static struct configfs_attribute *port_attrs[] = { &port_uid_attr , NULL } ; + +/* port ops */ +static struct configfs_item_operations port_item_ops = { .show_attribute = port_attr_show, .store_attribute = port_attr_store } ; + +/* port item */ +static struct config_item_type port_type = { .ct_item_ops = &port_item_ops, .ct_attrs = port_attrs, .ct_owner = THIS_MODULE } ; + + + + +static struct config_item *port_item_make(struct config_group *group, const char *name) { + + struct port_config_item *portitem ; + unsigned short port_num ; + + 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 ; + } + + 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, &port_type) ; + + portitem->uid = 0 ; + + if (debug) + printk(KERN_DEBUG UIDBIND_LABEL "Assigned default rule to port %s\n", name) ; + + return &portitem->item ; +} + + +static struct configfs_group_operations uidbind_group_ops = { + .make_item = port_item_make, +}; + +/* configfs uidbind */ +static struct config_item_type uidbind_type = { .ct_group_ops = &uidbind_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 int uidbind_socket_bind_check (struct socket *sock, struct sockaddr *address, int addrlen) +{ + + u16 family ; + struct sockaddr_in *addr4 = NULL; + struct config_item *portconfig = NULL ; + struct port_config_item *portitem = NULL ; + unsigned short socket_port; + char *strport = "\0" ; + + if (current->uid == 0) + return 0 ; + + family = sock->sk->sk_family; + + + if (family == PF_INET) { + + addr4 = (struct sockaddr_in *)address; + socket_port = ntohs(addr4->sin_port); + + if (debug) + printk(KERN_DEBUG UIDBIND_LABEL "bind() attempt on port %d by process [%s] uid [%d]\n", socket_port, current->comm, current->uid) ; + + sprintf(strport,"%u", socket_port) ; + + portconfig = config_group_find_obj(&uidbind_subsys.su_group,strport) ; + + if (!portconfig) { + if (debug) + printk(KERN_DEBUG UIDBIND_LABEL "Configuration for port %s unavailable\n", strport ) ; + + return -EPERM; + } + + portitem = container_of(portconfig, struct port_config_item, item) ; + + if (portitem->uid != current->uid) { + if (debug) + printk(KERN_DEBUG UIDBIND_LABEL "bind() permitted only to uid %u\n", portitem->uid) ; + return -EPERM; + } + + } + + 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 "); +MODULE_LICENSE("GPL"); +