lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Fri, 14 Dec 2007 11:38:09 +0100 (CET)
From:	Arnauld Michelizza <am@...c.net>
To:	netdev@...r.kernel.org
Subject: [patch] authorize some users to bind on specifics priv ports


Really simpler and usable than POSIX/capabilities and I think it 
covers basics needs for sysadmins... at least, it covers mine :-)

   www-data$ nc -l -p 80 -v
   Can't grab 0.0.0.0:80 with bind : Permission denied

   root# id -u www-data
   33
   root# port_acl_set +80 www-data
   root# cat /proc/net/port_acl
   80: 33

   www-data$ nc -l -p 80 -v
   listening on [any] 80 ...



diff -r --unidirectional-new-file -u linux-2.6.23/arch/i386/kernel/syscall_table.S linux-2.6.23-patched/arch/i386/kernel/syscall_table.S
--- linux-2.6.23/arch/i386/kernel/syscall_table.S	2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/arch/i386/kernel/syscall_table.S	2007-12-13 14:29:40.000000000 +0100
@@ -324,3 +324,4 @@
  	.long sys_timerfd
  	.long sys_eventfd
  	.long sys_fallocate
+	.long sys_port_acl_set		/* 325 */
diff -r --unidirectional-new-file -u linux-2.6.23/include/asm-i386/unistd.h linux-2.6.23-patched/include/asm-i386/unistd.h
--- linux-2.6.23/include/asm-i386/unistd.h	2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/include/asm-i386/unistd.h	2007-12-13 14:29:40.000000000 +0100
@@ -330,10 +330,11 @@
  #define __NR_timerfd		322
  #define __NR_eventfd		323
  #define __NR_fallocate		324
+#define __NR_port_acl_set	325

  #ifdef __KERNEL__

-#define NR_syscalls 325
+#define NR_syscalls 326

  #define __ARCH_WANT_IPC_PARSE_VERSION
  #define __ARCH_WANT_OLD_READDIR
diff -r --unidirectional-new-file -u linux-2.6.23/include/net/port_acl.h linux-2.6.23-patched/include/net/port_acl.h
--- linux-2.6.23/include/net/port_acl.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.23-patched/include/net/port_acl.h	2007-12-13 15:17:40.000000000 +0100
@@ -0,0 +1,15 @@
+#include <linux/types.h>
+
+struct port_acl {
+       uid_t           uid;
+       struct port_acl *next;
+};
+
+#ifdef __PORT_ACL__
+       struct port_acl *port_acl_list[1024];
+#else
+       extern struct port_acl *port_acl_list[1024];
+#endif
+
+extern int port_acl(short int);
+extern int port_acl_get_info(char *, char **, off_t, int); 
diff -r --unidirectional-new-file -u linux-2.6.23/kernel/sys.c linux-2.6.23-patched/kernel/sys.c
--- linux-2.6.23/kernel/sys.c	2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/kernel/sys.c	2007-12-13 16:01:24.000000000 +0100
@@ -43,6 +43,9 @@
  #include <asm/io.h>
  #include <asm/unistd.h>

+#define __PORT_ACL__
+#include <net/port_acl.h>
+
  #ifndef SET_UNALIGN_CTL
  # define SET_UNALIGN_CTL(a,b)	(-EINVAL)
  #endif
@@ -2356,4 +2359,89 @@

  	return ret;
  }
+
+/*
+ * The following lines were added to implement port_acl secured
+ * mecanism :
+ * port_acl_add - add to a user the authorisation to acces a particular port
+ * port_acl_remove - remove to a user that authorisation
+ * sys_port_acl_set - front end for port_acl_add and port_acl_remove
+ */
+long port_acl_add(short int snum, uid_t uid)
+{
+       struct port_acl *ptr, *new;
+
+       /* we verify if the permition is already set for that user */
+       ptr = port_acl_list[snum];
+
+       while (ptr != NULL) {
+               if (ptr->uid == uid)
+                       return -EBUSY;
+               if (ptr->next == NULL)
+                       break;
+               ptr = ptr->next;
+       }
+
+       /* ok, we haven't found the user and ptr is a pointer on the
+       last structure */
+       new = kmalloc( sizeof(struct port_acl), GFP_KERNEL); 
+       new->next = NULL;
+       new->uid = uid;
+
+       if(ptr == NULL)
+               port_acl_list[snum] = new;
+       else
+               ptr->next = new;
+
+       return 0;
+}
+
+long port_acl_remove(short int snum, uid_t uid)
+{
+       struct port_acl *ptr, *prev = 0;
+
+       /* we verify if the permition is already set for that user */
+       ptr = port_acl_list[snum];
+
+       while (ptr != NULL) {
+               /* we found the user */
+               if (ptr->uid == uid) {
+                       if (ptr == port_acl_list[snum]) {
+                               port_acl_list[snum] = ptr->next;
+                       }
+                       else {
+                               prev->next = ptr->next;
+                       } 
+                       kfree(ptr);
+                       return 0;
+               }
+               prev = ptr;
+               ptr = ptr->next;
+       }
+
+       return -ENODATA;
+}
+
+asmlinkage long sys_port_acl_set(short int snum, uid_t uid, int act)
+{
+       /* the owner of the process must be root */
+       if (current->uid != 0)
+               return -EACCES;
+
+       /* we verify that the port is valid */
+       if (snum<0 || snum>1023)
+               return -EINVAL;
+
+       if (uid<1 || uid>65534)
+               return -EINVAL;
+
+       if (act == 0)
+               return port_acl_remove(snum, uid);
+       else if (act == 1)
+               return port_acl_add(snum, uid);
+       else
+               return -EPERM;
+}
+
+
  EXPORT_SYMBOL_GPL(orderly_poweroff);
diff -r --unidirectional-new-file -u linux-2.6.23/net/ipv4/af_inet.c linux-2.6.23-patched/net/ipv4/af_inet.c
--- linux-2.6.23/net/ipv4/af_inet.c	2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/net/ipv4/af_inet.c	2007-12-13 15:58:55.000000000 +0100
@@ -112,6 +112,7 @@
  #include <net/ipip.h>
  #include <net/inet_common.h>
  #include <net/xfrm.h>
+#include <net/port_acl.h>
  #ifdef CONFIG_IP_MROUTE
  #include <linux/mroute.h>
  #endif
@@ -457,7 +458,7 @@

  	snum = ntohs(addr->sin_port);
  	err = -EACCES;
-	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE) && !port_acl(snum))
  		goto out;

  	/*      We keep a pair of addresses. rcv_saddr is the one
@@ -1456,6 +1457,8 @@
  {
  	int rc = 0;

+	proc_net_create ("port_acl", 0, port_acl_get_info); 
+
  	if (raw_proc_init())
  		goto out_raw;
  	if (tcp4_proc_init())
@@ -1466,6 +1469,7 @@
  		goto out_fib;
  	if (ip_misc_proc_init())
  		goto out_misc;
+
  out:
  	return rc;
  out_misc:
@@ -1486,6 +1490,7 @@
  {
  	return 0;
  }
+
  #endif /* CONFIG_PROC_FS */

  MODULE_ALIAS_NETPROTO(PF_INET);
diff -r --unidirectional-new-file -u linux-2.6.23/net/ipv4/Makefile linux-2.6.23-patched/net/ipv4/Makefile
--- linux-2.6.23/net/ipv4/Makefile	2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/net/ipv4/Makefile	2007-12-13 14:29:40.000000000 +0100
@@ -10,7 +10,7 @@
  	     tcp_minisocks.o tcp_cong.o \
  	     datagram.o raw.o udp.o udplite.o \
  	     arp.o icmp.o devinet.o af_inet.o  igmp.o \
-	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
+	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o port_acl.o

  obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
  obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
diff -r --unidirectional-new-file -u linux-2.6.23/net/ipv4/port_acl.c linux-2.6.23-patched/net/ipv4/port_acl.c
--- linux-2.6.23/net/ipv4/port_acl.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.23-patched/net/ipv4/port_acl.c	2007-12-13 16:01:12.000000000 +0100
@@ -0,0 +1,54 @@
+/*
+ * This is an implementation of acces list applied
+ * to privileged ports.
+ */
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <net/port_acl.h>
+
+/*
+ * yields 1 if the owner of the current process is authorized to
+ * bind the port given in argument
+ */
+int port_acl(short int snum)
+{
+       struct port_acl *ptr;
+       ptr = port_acl_list[snum]; 
+
+       while (ptr != NULL) {
+               if (ptr->uid == current->uid)
+                       return 1;
+               ptr = ptr->next; 
+       }
+
+       return 0;
+}
+
+
+/*
+ *     Report privileged port authorization
+ */
+int port_acl_get_info(char *buffer, char **start, off_t offset, int length)
+{
+       int p;
+       int len = 0;
+       int limit = length - 80;
+       struct port_acl *ptr;
+
+       /* for every port below 1024, we search privileged uid */
+       for (p=0;p<1024;p++) {
+               ptr = port_acl_list[p];
+               if (ptr != NULL) {
+                       len += sprintf(buffer+len,"%d:", p);
+                       do {
+                               len += sprintf(buffer+len," %d", ptr->uid);
+                               ptr = ptr->next;
+                       } while (ptr != NULL && len < limit);
+                       len += sprintf(buffer+len,"\n");
+               }
+       }
+ 
+       return len;
+}




port_acl_set.c
---
/*
  *	Add or remove to a user the authorisation to acces
  *	a particular port via the following system call :
  *		int sys_port_acl_set(short int snum, uid_t uid, int act)
  */

#include <syscall.h>
#include <linux/unistd.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>


int main(int argc, char **argv)
{
   int ret;
   int pnum, action;
   struct passwd *user;

   /* parse args */
   if (argc<3) {
     fprintf(stderr, "usage : %s <+->service login\n", argv[0]);
     exit(1);
   }

   switch (*argv[1]) {
   case '+' :
     action = 1 ; break;
   case '-' :
     action = 0 ; break;
   default :
     fprintf(stderr,"action '%c' is not valid\n", *argv[1]);
     exit(1);
   }

   pnum = atoi(argv[1]+1);

   user = getpwnam(argv[2]);
   if (!user) {
     fprintf(stderr,"%s is not a valid user\n", argv[2]);
     exit(1);
   }

   /* display a nice message */
   if (action == 1) {
     printf("add access on port %d to user: %s(%d)\n", pnum, argv[2], user->pw_uid);
   }
   else {
     printf("remove access on port %d to user: %s(%d)\n", pnum, argv[2], user->pw_uid);
   }

   ret = syscall(__NR_port_acl_set, pnum, user->pw_uid, action);

   if (ret!=0) {
     perror("");
     exit(2);
   }
   return 0;
}

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ