@@ -700,7 +700,7 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info,
static int proc_pid_permission(struct inode *inode, int mask)
{
struct proc_fs_info *fs_info = proc_sb(inode->i_sb);
- struct pid_namespace *pid = fs_info->pid_ns;
+ int hide_pid = proc_fs_hide_pid(fs_info);
struct task_struct *task;
bool has_perms;
@@ -711,7 +711,7 @@ static int proc_pid_permission(struct inode *inode, int mask)
put_task_struct(task);
if (!has_perms) {
- if (pid->hide_pid == HIDEPID_INVISIBLE) {
+ if (hide_pid == HIDEPID_INVISIBLE) {
/*
* Let's make getdents(), stat(), and open()
* consistent with each other. If a process
@@ -105,12 +105,16 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
{
struct super_block *sb = root->d_sb;
struct proc_fs_info *fs_info = proc_sb(sb);
- struct pid_namespace *pid = fs_info->pid_ns;
+ int hide_pid = proc_fs_hide_pid(fs_info);
+ kgid_t pid_gid = proc_fs_pid_gid(fs_info);
- if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID))
- seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));
- if (pid->hide_pid != HIDEPID_OFF)
- seq_printf(seq, ",hidepid=%u", pid->hide_pid);
+ if (proc_fs_newinstance(fs_info))
+ seq_printf(seq, ",newinstance");
+
+ if (!gid_eq(pid_gid, GLOBAL_ROOT_GID))
+ seq_printf(seq, ",gid=%u", from_kgid_munged(current_user_ns(),pid_gid));
+ if (hide_pid != HIDEPID_OFF)
+ seq_printf(seq, ",hidepid=%u", hide_pid);
return 0;
}
@@ -28,15 +28,57 @@
#include "internal.h"
enum {
- Opt_gid, Opt_hidepid, Opt_err,
+ Opt_gid, Opt_hidepid, Opt_newinstance, Opt_err,
};
static const match_table_t tokens = {
{Opt_hidepid, "hidepid=%u"},
{Opt_gid, "gid=%u"},
+ {Opt_newinstance, "newinstance"},
{Opt_err, NULL},
};
+/* We only parse 'newinstance' option here */
+int proc_parse_early_options(char *options, struct proc_fs_info *fs_info)
+{
+ char *p, *opts, *orig;
+ substring_t args[MAX_OPT_ARGS];
+
+ if (!options)
+ return 0;
+
+ opts = kstrdup(options, GFP_KERNEL);
+ if (!opts)
+ return -ENOMEM;
+
+ orig = opts;
+
+ while ((p = strsep(&opts, ",")) != NULL) {
+ int token;
+
+ if (!*p)
+ continue;
+
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_newinstance:
+ proc_fs_set_newinstance(fs_info, true);
+ pr_info("proc: mounting a new procfs instance ");
+ break;
+ case Opt_gid:
+ case Opt_hidepid:
+ break;
+ default:
+ pr_err("proc: unrecognized mount option \"%s\" "
+ "or missing value\n", p);
+ return -EINVAL;
+ }
+ }
+
+ kfree(orig);
+ return 0;
+}
+
int proc_parse_options(char *options, struct proc_fs_info *fs_info)
{
char *p;
@@ -75,6 +117,8 @@ int proc_parse_options(char *options, struct proc_fs_info *fs_info)
}
proc_fs_set_hide_pid(fs_info, option);
break;
+ case Opt_newinstance:
+ break;
default:
pr_err("proc: unrecognized mount option \"%s\" "
"or missing value\n", p);
@@ -87,18 +131,34 @@ int proc_parse_options(char *options, struct proc_fs_info *fs_info)
int proc_remount(struct super_block *sb, int *flags, char *data)
{
+ int error;
struct proc_fs_info *fs_info = proc_sb(sb);
sync_filesystem(sb);
+
+ /*
+ * If this is a new instance, then parse again the proc mount
+ * options.
+ */
+ if (proc_fs_newinstance(fs_info)) {
+ error = proc_parse_early_options(data, fs_info);
+ if (error < 0)
+ return error;
+ }
+
return !proc_parse_options(data, fs_info);
}
-static int proc_test_super(struct super_block *s, void *data)
+static int proc_test_super(struct super_block *sb, void *data)
{
struct proc_fs_info *p = data;
- struct proc_fs_info *fs_info = proc_sb(s);
+ struct proc_fs_info *fs_info = proc_sb(sb);
+
+ if (!proc_fs_newinstance(p) && !proc_fs_newinstance(fs_info) &&
+ p->pid_ns == fs_info->pid_ns)
+ return 1;
- return p->pid_ns == fs_info->pid_ns;
+ return 0;
}
static int proc_set_super(struct super_block *sb, void *data)
@@ -110,7 +170,7 @@ static int proc_set_super(struct super_block *sb, void *data)
static struct dentry *proc_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
- int error;
+ int error = 0;
struct super_block *sb;
struct pid_namespace *ns;
struct proc_fs_info *fs_info;
@@ -126,10 +186,18 @@ static struct dentry *proc_mount(struct file_system_type *fs_type,
if (!fs_info)
return ERR_PTR(-ENOMEM);
+ /* Set it as early as possible */
+ proc_fs_set_newinstance(fs_info, false);
+
if (flags & SB_KERNMOUNT) {
ns = data;
data = NULL;
} else {
+ /* Parse early mount options if not a kernel mount */
+ error = proc_parse_early_options(data, fs_info);
+ if (error < 0)
+ goto error_fs_info;
+
ns = task_active_pid_ns(current);
}
@@ -39,8 +39,6 @@ struct pid_namespace {
struct user_namespace *user_ns;
struct ucounts *ucounts;
struct work_struct proc_work;
- kgid_t pid_gid;
- int hide_pid;
int reboot; /* group exit code if this pidns was rebooted */
struct ns_common ns;
} __randomize_layout;
@@ -16,6 +16,9 @@ struct proc_fs_info {
struct pid_namespace *pid_ns;
struct dentry *proc_self; /* For /proc/self/ */
struct dentry *proc_thread_self; /* For /proc/thread-self/ */
+ bool newinstance; /* Flag for new separated instances */
+ kgid_t pid_gid;
+ int hide_pid;
};
#ifdef CONFIG_PROC_FS
@@ -27,22 +30,32 @@ static inline struct proc_fs_info *proc_sb(struct super_block *sb)
static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid)
{
- fs_info->pid_ns->hide_pid = hide_pid;
+ fs_info->hide_pid = hide_pid;
}
static inline void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid)
{
- fs_info->pid_ns->pid_gid = gid;
+ fs_info->pid_gid = gid;
+}
+
+static inline void proc_fs_set_newinstance(struct proc_fs_info *fs_info, bool value)
+{
+ fs_info->newinstance = value;
}
static inline int proc_fs_hide_pid(struct proc_fs_info *fs_info)
{
- return fs_info->pid_ns->hide_pid;
+ return fs_info->hide_pid;
}
static inline kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info)
{
- return fs_info->pid_ns->pid_gid;
+ return fs_info->pid_gid;
+}
+
+static inline bool proc_fs_newinstance(struct proc_fs_info *fs_info)
+{
+ return fs_info->newinstance;
}
extern void proc_root_init(void);
@@ -89,6 +102,10 @@ static inline void proc_fs_set_pid_gid(struct proc_info_fs *fs_info, kgid_t gid)
{
}
+static inline void proc_fs_set_newinstance(struct proc_fs_info *fs_info, bool value)
+{
+}
+
static inline int proc_fs_hide_pid(struct proc_fs_info *fs_info)
{
return 0;
@@ -99,6 +116,11 @@ extern kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info)
return GLOBAL_ROOT_GID;
}
+static inline bool proc_fs_newinstance(struct proc_fs_info *fs_info)
+{
+ return false;
+}
+
extern inline struct proc_fs_info *proc_sb(struct super_block *sb) { return NULL;}
static inline struct proc_dir_entry *proc_symlink(const char *name,
struct proc_dir_entry *parent,const char *dest) { return NULL;}