Skip to contentSkip to conversation

2.6.25: access permission filesystem 0.21

PATCH In review Olaf Dietsche 3 participants 4 messages May 12, 2008 – May 16, 2008

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 2.6.25: access permission filesystem 0.21

This patch adds a new permission managing file system. Furthermore, it adds two modules, which make use of this file system.

One module allows granting capabilities based on user-/groupid. The second module allows to grant access to lower numbered ports based on user-/groupid, too.

Changes:
- updated to 2.6.25
- Add ignore CAP_NET_BIND_SERVICE option
- Specify license as "GPL v2"
- Fix access to nonexistent file
- Prevent changing file attributes by anybody

This patch is available at:
<http://www.olafdietsche.de/linux/accessfs/>

Regards, Olaf.

Documentation/filesystems/accessfs.txt new file +41 -0
new file mode 100644
index 0000000..bf135b5
@@ -0,0 +1,41 @@
+Accessfs is a permission managing filesystem. It allows to control access to
+system resources, based on file permissions. The recommended mount point for
+this file-system is /proc/access, which will appear automatically in the
+/proc filesystem.
+
+Currently there are two modules using accessfs, userports and usercaps.
+
+With userports, you will be able to control access to IP ports based
+on user-/groupid.
+
+There's no need anymore to run internet daemons as root. You can
+individually configure which user/program can bind to protected ports
+(by default, below 1024).
+
+For example, you can say, user www is allowed to bind to port 80 or
+user mail is allowed to bind to port 25. Then, you can run apache as
+user www and sendmail as user mail. Now, you don't have to rely on
+apache or sendmail giving up superuser rights to enhance security.
+
+To use this option, you need to mount the access file system
+and do a chown on the appropriate ports:
+
+# mount -t accessfs none /proc/access
+# chown www /proc/access/net/ip/bind/80
+# chown mail /proc/access/net/ip/bind/25
+
+You can grant access to a group for individual ports as well. Just say:
+
+# chgrp lp /proc/access/net/ip/bind/515
+# chown g+x /proc/access/net/ip/bind/515
+
+With usercaps, you will be able to grant capabilities based on
+user-/groupid (root by default).
+
+For example you can create a group raw and change the capability
+net_raw to this group:
+
+# chgrp raw /proc/access/capabilities/net_raw
+# chmod ug+x /proc/access/capabilities/net_raw
+# chgrp raw /sbin/ping
+# chmod u-s /sbin/ping; chmod g+s /sbin/ping
fs/Kconfig +1 -0
index c509123..32fd12d 100644
@@ -1462,6 +1462,7 @@ config ROMFS_FS
 	  If you don't know whether you need it, then you don't need it:
 	  answer N.
 
+source "fs/accessfs/Kconfig"
 
 config SYSV_FS
 	tristate "System V/Xenix/V7/Coherent file system support"
fs/Makefile +1 -0
index 1e7a11b..25049a8 100644
@@ -119,3 +119,4 @@ obj-$(CONFIG_HPPFS)		+= hppfs/
 obj-$(CONFIG_DEBUG_FS)		+= debugfs/
 obj-$(CONFIG_OCFS2_FS)		+= ocfs2/
 obj-$(CONFIG_GFS2_FS)           += gfs2/
+obj-$(CONFIG_ACCESS_FS)		+= accessfs/
fs/accessfs/Kconfig new file +64 -0

64 lines not on this page · raw message

fs/accessfs/Makefile new file +11 -0
new file mode 100644
index 0000000..63a5647
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux accessfs routines.
+#
+
+obj-$(CONFIG_ACCESS_FS) += accessfs.o
+obj-$(CONFIG_ACCESSFS_USER_CAPABILITIES) += usercaps.o
+obj-$(CONFIG_ACCESSFS_USER_PORTS) += userports.o
+
+accessfs-objs := inode.o
+usercaps-objs := capabilities.o
+userports-objs := ip.o
fs/accessfs/capabilities.c new file +107 -0

107 lines not on this page · raw message

fs/accessfs/inode.c new file +434 -0

434 lines not on this page · raw message

fs/accessfs/ip.c new file +98 -0

98 lines not on this page · raw message

include/linux/accessfs_fs.h new file +42 -0

42 lines not on this page · raw message

include/net/sock.h +43 -0

47 lines not on this page · raw message

net/Kconfig +12 -0
index 6627c6a..0708d82 100644
@@ -65,6 +65,18 @@ config INET
 if INET
 source "net/ipv4/Kconfig"
 source "net/ipv6/Kconfig"
+
+config NET_HOOKS
+	bool "IP: Networking hooks (Experimental)"
+	depends on INET && EXPERIMENTAL
+	default n
+	help
+	  This option enables other kernel parts or modules to hook into the
+	  networking area and provide fine grained control over the access to
+	  IP ports.
+
+	  If you're unsure, say N.
+
 source "net/netlabel/Kconfig"
 
 endif # if INET
net/Makefile +1 -0
index b7a1364..6caa359 100644
@@ -53,6 +53,7 @@ obj-$(CONFIG_NETLABEL)		+= netlabel/
 obj-$(CONFIG_IUCV)		+= iucv/
 obj-$(CONFIG_RFKILL)		+= rfkill/
 obj-$(CONFIG_NET_9P)		+= 9p/
+obj-$(CONFIG_NET_HOOKS)		+= hooks.o
 
 ifeq ($(CONFIG_NET),y)
 obj-$(CONFIG_SYSCTL)		+= sysctl_net.o
net/hooks.c new file +55 -0

55 lines not on this page · raw message

net/ipv4/af_inet.c +1 -1
index 0d10950..c9a2149 100644
@@ -466,7 +466,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 
 	snum = ntohs(addr->sin_port);
 	err = -EACCES;
-	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+	if (ip_prot_sock(sock, uaddr, addr_len))
 		goto out;
 
 	/*      We keep a pair of addresses. rcv_saddr is the one
net/ipv6/af_inet6.c +1 -1
index f0aa977..dd78e71 100644
@@ -264,7 +264,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 		return -EINVAL;
 
 	snum = ntohs(addr->sin6_port);
-	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+	if (ip6_prot_sock(sock, uaddr, addr_len))
 		return -EACCES;
 
 	lock_sock(sk);
#1 lore raw
Quoted 4 lines · --- Olaf Dietsche

This patch adds a new permission managing file system. Furthermore, it adds two modules, which make use of this file system.

One module allows granting capabilities based on user-/groupid.

Hmm. The primary purpose of the capability mechanism, according to the POSIX P1003.1e/2c working group*, is to separate the privilege mechanism from the userid mechanism. You are now reintegrating them two mechanims, albiet differently than they were integrated before. You can already achieve this end using filesystem based capabilties and mode bits and/or ACLs, so why the change?

Quoted 3 lines

The
second module allows to grant access to lower numbered ports based on user-/groupid, too.

Woof. As reasonable as mode bits on ports seems, there's an awful lot of tradition associated with the privileged port model. I can see the value in it, I've actually implemented it in the past in the Unix world, but I have never seen anyone willing to take advantage of the scheme.

-----
* As I'm the only member of that working group who ever pipes up here, you'll have to take my word for it. (smiley)

Casey Schaufler
[email protected]

#2 lore raw
Quoted 7 lines · Casey Schaufler
Quoted 4 lines · --- Olaf Dietsche

This patch adds a new permission managing file system. Furthermore, it adds two modules, which make use of this file system.

One module allows granting capabilities based on user-/groupid.

Quoted 7 lines

Hmm. The primary purpose of the capability mechanism, according to the POSIX P1003.1e/2c working group*, is to separate the privilege mechanism from the userid mechanism. You are now reintegrating them two mechanims, albiet differently than they were integrated before. You can already achieve this end using filesystem based capabilties and mode bits and/or ACLs, so why the change?

This idea is from 2002, when there were neither filesystem based capabilties nor ACLs. But since even I never used it, see it as an interesting excercise.

Quoted 9 lines
Quoted 3 lines

The
second module allows to grant access to lower numbered ports based on user-/groupid, too.

Woof. As reasonable as mode bits on ports seems, there's an awful lot of tradition associated with the privileged port model. I can see the value in it, I've actually implemented it in the past in the Unix world, but I have never seen anyone willing to take advantage of the scheme.

Well, I'm not in the tradition business :-) but it's fun to do these things and even useful in this case.

Regards, Olaf

#3 lore raw
In reply to Olaf Dietsche
Quoted 2 lines · On Mon, 12 May 2008 22:59:32 +0200 Olaf Dietsche wrote:

This patch adds a new permission managing file system. Furthermore, it adds two modules, which make use of this file system.

(attachment fragments copied as needed for comments:)

fs/accessfs/Kconfig:

+config ACCESSFS_USER_PORTS
+ tristate "User permission based IP ports"
+ depends on ACCESS_FS
+ select NET_HOOKS
+ default n
+ help

+	  If you say Y here, you will be able to control access to IP ports
+	  based on user-/groupid. For this to work, you must say Y
+	  to CONFIG_NET_HOOKS.

+
+ If you're unsure, say N.

Just spell out userid instead of using "user-". The hyphen is only saving one character, so just make it clearer by spelling it out. (Several instances of this, including in the Documentation.)

This config option should probably also depend on INET since it selects NET_HOOKS and NET_HOOKS depends on INET (and since select won't follow any dependency chain).

+config ACCESSFS_IGNORE_NET_BIND_SERVICE
+ bool "Ignore CAP_NET_BIND_SERVICE capability"
+ depends on ACCESSFS_USER_PORTS
+ default n
+ help
+ This option lets you decide, wether a user with

whether

Oh. That line ends with a space. Please check all Kconfig and source file lines to make sure that they do not end with whitespace.

+ CAP_NET_BIND_SERVICE capability is able to override
+ your userport configuration.
+
+ If you build this as a module, you can specify this
+ option at module load time (ignore_net_bind_service).
+
+ If you're unsure, say n.

Have the networking people commented on the NET_HOOKS and their function methods?

inode.c:

+static inline void accessfs_readdir_aux(struct file *filp,
+ struct accessfs_direntry *dir,
+ int start, void *dirent,
+ filldir_t filldir)

is rather large to be inlined. Why do that?

+int accessfs_register(struct accessfs_direntry *dir, const char *name,
+ struct access_attr *attr)
+{
+ int err;
+ if (dir == 0)
+ return -EINVAL;

Don't check for 0, check for NULL (when it's a pointer being tested). So use either

	if (dir == NULL)
or
	if (!dir)

(several of these seen)

+static int __init init_accessfs_fs(void)
+{
+
+ /* create mount point for accessfs */
+ mountdir = proc_mkdir("access",&proc_root);

space after comma.

+ return register_filesystem(&accessfs_fs_type);
+}
+
+static void __exit exit_accessfs_fs(void)
+{
+ unregister_filesystem(&accessfs_fs_type);
+ remove_proc_entry("access",&proc_root);

ditto.

+}

ip.c:

+ bind_to_port = kmalloc(max_prot_sock * sizeof(*bind_to_port),
+ GFP_KERNEL);
+ if (bind_to_port == 0)
+ return -ENOMEM;

Test pointer for NULL or use !bind_to_port.

+static void __exit exit_ip(void)
+{
+ struct accessfs_direntry *dir = accessfs_make_dirpath("net/ip/bind");
+ int i;
+ net_hooks_unregister(&ip_net_ops);
+ for (i = 1; i < max_prot_sock; ++i) {
+ char buf[sizeof("65536")];

			buf[sizeof("65536") + 1]; ???

+ sprintf(buf, "%d", i);
+ accessfs_unregister(dir, buf);
+ }

Documentation/filesystems/accessfs.txt:

Change "user-/" to "userid/".

---
~Randy