Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Fri, 3 Jun 2011 22:38:41 +0400
From: Vasiliy Kulikov <segoon@...nwall.com>
To: owl-dev@...ts.openwall.com
Cc: Eugene Teo <eugeneteo@...il.com>
Subject: add mount options to sysfs (was: segoon's status report - #1 of 15)

Solar, Eugene,

I've added mount option printing in /proc/mounts and tested different
remount situations.

Solar, I'm waiting for your response re: mode usefullness.  Then I'll
try to post the patch to LKML one more time.

Thanks,

-- 
Vasiliy Kulikov

diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index ea9120a..ce12dfe 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -325,8 +325,10 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type)
 	atomic_set(&sd->s_active, 0);
 
 	sd->s_name = name;
-	sd->s_mode = mode;
+	sd->s_mode = mode & ~sysfs_perms.umask;
 	sd->s_flags = type;
+	sd->s_uid = sysfs_perms.uid;
+	sd->s_gid = sysfs_perms.gid;
 
 	return sd;
 
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index 0a12eb8..2764d07 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -17,6 +17,7 @@
 #include <linux/backing-dev.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
+#include <linux/mount.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
@@ -217,8 +218,9 @@ static int sysfs_count_nlink(struct sysfs_dirent *sd)
 static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode)
 {
 	struct sysfs_inode_attrs *iattrs = sd->s_iattr;
+	struct sysfs_super_info *sb_info = sysfs_info(inode->i_sb);
 
-	inode->i_mode = sd->s_mode;
+	inode->i_mode = sd->s_mode & (sb_info->mode | ~0777);
 	if (iattrs) {
 		/* sysfs_dirent has non-default attributes
 		 * get them from persistent copy in sysfs_dirent
@@ -256,6 +258,8 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode)
 	inode->i_op = &sysfs_inode_operations;
 
 	set_default_inode_attr(inode, sd->s_mode);
+	inode->i_uid = sd->s_uid;
+	inode->i_gid = sd->s_gid;
 	sysfs_refresh_inode(sd, inode);
 
 	/* initialize inode according to type */
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 2668957..8ef7eb9 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -18,10 +18,16 @@
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/magic.h>
+#include <linux/parser.h>
 #include <linux/slab.h>
+#include <linux/seq_file.h>
 
 #include "sysfs.h"
 
+struct sysfs_perms sysfs_perms;
+
+static int sysfs_remount_fs(struct super_block * sb, int *flags, char *data);
+static int sysfs_show_options(struct seq_file *seq, struct vfsmount *vfs);
 
 static struct vfsmount *sysfs_mnt;
 struct kmem_cache *sysfs_dir_cachep;
@@ -30,6 +36,8 @@ static const struct super_operations sysfs_ops = {
 	.statfs		= simple_statfs,
 	.drop_inode	= generic_delete_inode,
 	.evict_inode	= sysfs_evict_inode,
+	.remount_fs	= sysfs_remount_fs,
+	.show_options	= sysfs_show_options,
 };
 
 struct sysfs_dirent sysfs_root = {
@@ -40,10 +48,77 @@ struct sysfs_dirent sysfs_root = {
 	.s_ino		= 1,
 };
 
+enum {
+	Opt_uid, Opt_gid, Opt_umask, Opt_mode, Opt_err
+};
+
+static const match_table_t sysfs_tokens = {
+	{Opt_uid, "uid=%u"},
+	{Opt_gid, "gid=%u"},
+	{Opt_umask, "umask=%o"},
+	{Opt_mode, "mode=%o"},
+	{Opt_err, NULL},
+};
+
+static int parse_options(char *options, struct sysfs_super_info *sb_info)
+{
+	char *p;
+	int option;
+	substring_t args[MAX_OPT_ARGS];
+
+	while ((p = strsep(&options, ",")) != NULL) {
+		int token;
+		if (!*p)
+			continue;
+
+		token = match_token(p, sysfs_tokens, args);
+
+		switch (token) {
+		case Opt_uid:
+		case Opt_gid:
+		case Opt_umask:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EPERM;
+		default:
+			break;
+		}
+
+		switch (token) {
+		case Opt_uid:
+			if (match_int(&args[0], &option))
+				return -EINVAL;
+			sysfs_perms.uid = option;
+			break;
+		case Opt_gid:
+			if (match_int(&args[0], &option))
+				return -EINVAL;
+			sysfs_perms.gid = option;
+			break;
+		case Opt_mode:
+			if (match_octal(&args[0], &option))
+				return -EINVAL;
+			sb_info->mode = option;
+			break;
+		case Opt_umask:
+			if (match_octal(&args[0], &option))
+				return -EINVAL;
+			sysfs_perms.umask = option;
+			break;
+		default:
+			pr_err("SYSFS: Unrecognized mount option \"%s\" "
+			       "or missing value\n", p);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
 static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 {
 	struct inode *inode;
 	struct dentry *root;
+	int err;
 
 	sb->s_blocksize = PAGE_CACHE_SIZE;
 	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -51,6 +126,10 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 	sb->s_op = &sysfs_ops;
 	sb->s_time_gran = 1;
 
+	err = parse_options(data, sysfs_info(sb));
+	if (err)
+		return err;
+
 	/* get root inode, initialize and unlock it */
 	mutex_lock(&sysfs_mutex);
 	inode = sysfs_get_inode(sb, &sysfs_root);
@@ -109,6 +188,7 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 
 	for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
 		info->ns[type] = kobj_ns_current(type);
+	info->mode = 0777;
 
 	sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info);
 	if (IS_ERR(sb) || sb->s_fs_info != info)
@@ -128,6 +208,28 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
 	return dget(sb->s_root);
 }
 
+static int sysfs_remount_fs(struct super_block * sb, int *flags, char *data)
+{
+	return parse_options(data, sysfs_info(sb));
+}
+
+static int sysfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+	struct super_block *sb = vfs->mnt_sb;
+	struct sysfs_super_info *info = sysfs_info(sb);
+
+	if (sysfs_perms.uid != 0)
+		seq_printf(seq, ",uid=%lu", (unsigned long)sysfs_perms.uid);
+	if (sysfs_perms.gid != 0)
+		seq_printf(seq, ",gid=%lu", (unsigned long)sysfs_perms.gid);
+	if (info->mode != 0777)
+		seq_printf(seq, ",mode=%o", info->mode);
+	if (sysfs_perms.umask != 0)
+		seq_printf(seq, ",umask=%o", sysfs_perms.umask);
+
+	return 0;
+}
+
 static void sysfs_kill_sb(struct super_block *sb)
 {
 	struct sysfs_super_info *info = sysfs_info(sb);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 3d28af3..d474f1e 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -69,6 +69,8 @@ struct sysfs_dirent {
 
 	unsigned int		s_flags;
 	unsigned short		s_mode;
+	uid_t			s_uid;
+	gid_t			s_gid;
 	ino_t			s_ino;
 	struct sysfs_inode_attrs *s_iattr;
 };
@@ -130,6 +132,13 @@ struct sysfs_addrm_cxt {
  * mount.c
  */
 
+struct sysfs_perms {
+	unsigned int umask;
+	gid_t gid;
+	uid_t uid;
+};
+extern struct sysfs_perms sysfs_perms;
+
 /*
  * Each sb is associated with a set of namespace tags (i.e.
  * the network namespace of the task which mounted this sysfs
@@ -137,6 +146,7 @@ struct sysfs_addrm_cxt {
  */
 struct sysfs_super_info {
 	const void *ns[KOBJ_NS_TYPES];
+	unsigned int mode;
 };
 #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
 extern struct sysfs_dirent sysfs_root;

Powered by blists - more mailing lists

Your e-mail address:

Powered by Openwall GNU/*/Linux - Powered by OpenVZ