diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 15 | ||||
-rw-r--r-- | fs/proc/base.c | 93 | ||||
-rw-r--r-- | fs/proc/inode.c | 4 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 4 | ||||
-rw-r--r-- | fs/proc/root.c | 2 |
5 files changed, 102 insertions, 16 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index f9bd395b3473..dc4c5a7b9ece 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <linux/pid_namespace.h> | 81 | #include <linux/pid_namespace.h> |
82 | #include <linux/ptrace.h> | 82 | #include <linux/ptrace.h> |
83 | #include <linux/tracehook.h> | 83 | #include <linux/tracehook.h> |
84 | #include <linux/user_namespace.h> | ||
84 | 85 | ||
85 | #include <asm/pgtable.h> | 86 | #include <asm/pgtable.h> |
86 | #include <asm/processor.h> | 87 | #include <asm/processor.h> |
@@ -161,6 +162,7 @@ static inline const char *get_task_state(struct task_struct *tsk) | |||
161 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | 162 | static inline void task_state(struct seq_file *m, struct pid_namespace *ns, |
162 | struct pid *pid, struct task_struct *p) | 163 | struct pid *pid, struct task_struct *p) |
163 | { | 164 | { |
165 | struct user_namespace *user_ns = current_user_ns(); | ||
164 | struct group_info *group_info; | 166 | struct group_info *group_info; |
165 | int g; | 167 | int g; |
166 | struct fdtable *fdt = NULL; | 168 | struct fdtable *fdt = NULL; |
@@ -189,8 +191,14 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
189 | task_tgid_nr_ns(p, ns), | 191 | task_tgid_nr_ns(p, ns), |
190 | pid_nr_ns(pid, ns), | 192 | pid_nr_ns(pid, ns), |
191 | ppid, tpid, | 193 | ppid, tpid, |
192 | cred->uid, cred->euid, cred->suid, cred->fsuid, | 194 | from_kuid_munged(user_ns, cred->uid), |
193 | cred->gid, cred->egid, cred->sgid, cred->fsgid); | 195 | from_kuid_munged(user_ns, cred->euid), |
196 | from_kuid_munged(user_ns, cred->suid), | ||
197 | from_kuid_munged(user_ns, cred->fsuid), | ||
198 | from_kgid_munged(user_ns, cred->gid), | ||
199 | from_kgid_munged(user_ns, cred->egid), | ||
200 | from_kgid_munged(user_ns, cred->sgid), | ||
201 | from_kgid_munged(user_ns, cred->fsgid)); | ||
194 | 202 | ||
195 | task_lock(p); | 203 | task_lock(p); |
196 | if (p->files) | 204 | if (p->files) |
@@ -205,7 +213,8 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns, | |||
205 | task_unlock(p); | 213 | task_unlock(p); |
206 | 214 | ||
207 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) | 215 | for (g = 0; g < min(group_info->ngroups, NGROUPS_SMALL); g++) |
208 | seq_printf(m, "%d ", GROUP_AT(group_info, g)); | 216 | seq_printf(m, "%d ", |
217 | from_kgid_munged(user_ns, GROUP_AT(group_info, g))); | ||
209 | put_cred(cred); | 218 | put_cred(cred); |
210 | 219 | ||
211 | seq_putc(m, '\n'); | 220 | seq_putc(m, '\n'); |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 57b8159f26f3..d2d3108a611c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <linux/oom.h> | 81 | #include <linux/oom.h> |
82 | #include <linux/elf.h> | 82 | #include <linux/elf.h> |
83 | #include <linux/pid_namespace.h> | 83 | #include <linux/pid_namespace.h> |
84 | #include <linux/user_namespace.h> | ||
84 | #include <linux/fs_struct.h> | 85 | #include <linux/fs_struct.h> |
85 | #include <linux/slab.h> | 86 | #include <linux/slab.h> |
86 | #include <linux/flex_array.h> | 87 | #include <linux/flex_array.h> |
@@ -1561,8 +1562,8 @@ int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
1561 | generic_fillattr(inode, stat); | 1562 | generic_fillattr(inode, stat); |
1562 | 1563 | ||
1563 | rcu_read_lock(); | 1564 | rcu_read_lock(); |
1564 | stat->uid = 0; | 1565 | stat->uid = GLOBAL_ROOT_UID; |
1565 | stat->gid = 0; | 1566 | stat->gid = GLOBAL_ROOT_GID; |
1566 | task = pid_task(proc_pid(inode), PIDTYPE_PID); | 1567 | task = pid_task(proc_pid(inode), PIDTYPE_PID); |
1567 | if (task) { | 1568 | if (task) { |
1568 | if (!has_pid_permissions(pid, task, 2)) { | 1569 | if (!has_pid_permissions(pid, task, 2)) { |
@@ -1622,8 +1623,8 @@ int pid_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1622 | inode->i_gid = cred->egid; | 1623 | inode->i_gid = cred->egid; |
1623 | rcu_read_unlock(); | 1624 | rcu_read_unlock(); |
1624 | } else { | 1625 | } else { |
1625 | inode->i_uid = 0; | 1626 | inode->i_uid = GLOBAL_ROOT_UID; |
1626 | inode->i_gid = 0; | 1627 | inode->i_gid = GLOBAL_ROOT_GID; |
1627 | } | 1628 | } |
1628 | inode->i_mode &= ~(S_ISUID | S_ISGID); | 1629 | inode->i_mode &= ~(S_ISUID | S_ISGID); |
1629 | security_task_to_inode(task, inode); | 1630 | security_task_to_inode(task, inode); |
@@ -1815,8 +1816,8 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1815 | inode->i_gid = cred->egid; | 1816 | inode->i_gid = cred->egid; |
1816 | rcu_read_unlock(); | 1817 | rcu_read_unlock(); |
1817 | } else { | 1818 | } else { |
1818 | inode->i_uid = 0; | 1819 | inode->i_uid = GLOBAL_ROOT_UID; |
1819 | inode->i_gid = 0; | 1820 | inode->i_gid = GLOBAL_ROOT_GID; |
1820 | } | 1821 | } |
1821 | 1822 | ||
1822 | i_mode = S_IFLNK; | 1823 | i_mode = S_IFLNK; |
@@ -2045,8 +2046,8 @@ static int map_files_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
2045 | inode->i_gid = cred->egid; | 2046 | inode->i_gid = cred->egid; |
2046 | rcu_read_unlock(); | 2047 | rcu_read_unlock(); |
2047 | } else { | 2048 | } else { |
2048 | inode->i_uid = 0; | 2049 | inode->i_uid = GLOBAL_ROOT_UID; |
2049 | inode->i_gid = 0; | 2050 | inode->i_gid = GLOBAL_ROOT_GID; |
2050 | } | 2051 | } |
2051 | security_task_to_inode(task, inode); | 2052 | security_task_to_inode(task, inode); |
2052 | status = 1; | 2053 | status = 1; |
@@ -2924,6 +2925,74 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer) | |||
2924 | } | 2925 | } |
2925 | #endif /* CONFIG_TASK_IO_ACCOUNTING */ | 2926 | #endif /* CONFIG_TASK_IO_ACCOUNTING */ |
2926 | 2927 | ||
2928 | #ifdef CONFIG_USER_NS | ||
2929 | static int proc_id_map_open(struct inode *inode, struct file *file, | ||
2930 | struct seq_operations *seq_ops) | ||
2931 | { | ||
2932 | struct user_namespace *ns = NULL; | ||
2933 | struct task_struct *task; | ||
2934 | struct seq_file *seq; | ||
2935 | int ret = -EINVAL; | ||
2936 | |||
2937 | task = get_proc_task(inode); | ||
2938 | if (task) { | ||
2939 | rcu_read_lock(); | ||
2940 | ns = get_user_ns(task_cred_xxx(task, user_ns)); | ||
2941 | rcu_read_unlock(); | ||
2942 | put_task_struct(task); | ||
2943 | } | ||
2944 | if (!ns) | ||
2945 | goto err; | ||
2946 | |||
2947 | ret = seq_open(file, seq_ops); | ||
2948 | if (ret) | ||
2949 | goto err_put_ns; | ||
2950 | |||
2951 | seq = file->private_data; | ||
2952 | seq->private = ns; | ||
2953 | |||
2954 | return 0; | ||
2955 | err_put_ns: | ||
2956 | put_user_ns(ns); | ||
2957 | err: | ||
2958 | return ret; | ||
2959 | } | ||
2960 | |||
2961 | static int proc_id_map_release(struct inode *inode, struct file *file) | ||
2962 | { | ||
2963 | struct seq_file *seq = file->private_data; | ||
2964 | struct user_namespace *ns = seq->private; | ||
2965 | put_user_ns(ns); | ||
2966 | return seq_release(inode, file); | ||
2967 | } | ||
2968 | |||
2969 | static int proc_uid_map_open(struct inode *inode, struct file *file) | ||
2970 | { | ||
2971 | return proc_id_map_open(inode, file, &proc_uid_seq_operations); | ||
2972 | } | ||
2973 | |||
2974 | static int proc_gid_map_open(struct inode *inode, struct file *file) | ||
2975 | { | ||
2976 | return proc_id_map_open(inode, file, &proc_gid_seq_operations); | ||
2977 | } | ||
2978 | |||
2979 | static const struct file_operations proc_uid_map_operations = { | ||
2980 | .open = proc_uid_map_open, | ||
2981 | .write = proc_uid_map_write, | ||
2982 | .read = seq_read, | ||
2983 | .llseek = seq_lseek, | ||
2984 | .release = proc_id_map_release, | ||
2985 | }; | ||
2986 | |||
2987 | static const struct file_operations proc_gid_map_operations = { | ||
2988 | .open = proc_gid_map_open, | ||
2989 | .write = proc_gid_map_write, | ||
2990 | .read = seq_read, | ||
2991 | .llseek = seq_lseek, | ||
2992 | .release = proc_id_map_release, | ||
2993 | }; | ||
2994 | #endif /* CONFIG_USER_NS */ | ||
2995 | |||
2927 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, | 2996 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, |
2928 | struct pid *pid, struct task_struct *task) | 2997 | struct pid *pid, struct task_struct *task) |
2929 | { | 2998 | { |
@@ -3026,6 +3095,10 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
3026 | #ifdef CONFIG_HARDWALL | 3095 | #ifdef CONFIG_HARDWALL |
3027 | INF("hardwall", S_IRUGO, proc_pid_hardwall), | 3096 | INF("hardwall", S_IRUGO, proc_pid_hardwall), |
3028 | #endif | 3097 | #endif |
3098 | #ifdef CONFIG_USER_NS | ||
3099 | REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), | ||
3100 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), | ||
3101 | #endif | ||
3029 | }; | 3102 | }; |
3030 | 3103 | ||
3031 | static int proc_tgid_base_readdir(struct file * filp, | 3104 | static int proc_tgid_base_readdir(struct file * filp, |
@@ -3381,6 +3454,10 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3381 | #ifdef CONFIG_HARDWALL | 3454 | #ifdef CONFIG_HARDWALL |
3382 | INF("hardwall", S_IRUGO, proc_pid_hardwall), | 3455 | INF("hardwall", S_IRUGO, proc_pid_hardwall), |
3383 | #endif | 3456 | #endif |
3457 | #ifdef CONFIG_USER_NS | ||
3458 | REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), | ||
3459 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), | ||
3460 | #endif | ||
3384 | }; | 3461 | }; |
3385 | 3462 | ||
3386 | static int proc_tid_base_readdir(struct file * filp, | 3463 | static int proc_tid_base_readdir(struct file * filp, |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 205c92280838..554ecc54799f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -108,8 +108,8 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root) | |||
108 | struct super_block *sb = root->d_sb; | 108 | struct super_block *sb = root->d_sb; |
109 | struct pid_namespace *pid = sb->s_fs_info; | 109 | struct pid_namespace *pid = sb->s_fs_info; |
110 | 110 | ||
111 | if (pid->pid_gid) | 111 | if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID)) |
112 | seq_printf(seq, ",gid=%lu", (unsigned long)pid->pid_gid); | 112 | seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid)); |
113 | if (pid->hide_pid != 0) | 113 | if (pid->hide_pid != 0) |
114 | seq_printf(seq, ",hidepid=%u", pid->hide_pid); | 114 | seq_printf(seq, ",hidepid=%u", pid->hide_pid); |
115 | 115 | ||
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 21d836f40292..3476bca8f7af 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -371,9 +371,9 @@ void register_sysctl_root(struct ctl_table_root *root) | |||
371 | 371 | ||
372 | static int test_perm(int mode, int op) | 372 | static int test_perm(int mode, int op) |
373 | { | 373 | { |
374 | if (!current_euid()) | 374 | if (uid_eq(current_euid(), GLOBAL_ROOT_UID)) |
375 | mode >>= 6; | 375 | mode >>= 6; |
376 | else if (in_egroup_p(0)) | 376 | else if (in_egroup_p(GLOBAL_ROOT_GID)) |
377 | mode >>= 3; | 377 | mode >>= 3; |
378 | if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0) | 378 | if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0) |
379 | return 0; | 379 | return 0; |
diff --git a/fs/proc/root.c b/fs/proc/root.c index eed44bfc85db..7c30fce037c0 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -67,7 +67,7 @@ static int proc_parse_options(char *options, struct pid_namespace *pid) | |||
67 | case Opt_gid: | 67 | case Opt_gid: |
68 | if (match_int(&args[0], &option)) | 68 | if (match_int(&args[0], &option)) |
69 | return 0; | 69 | return 0; |
70 | pid->pid_gid = option; | 70 | pid->pid_gid = make_kgid(current_user_ns(), option); |
71 | break; | 71 | break; |
72 | case Opt_hidepid: | 72 | case Opt_hidepid: |
73 | if (match_int(&args[0], &option)) | 73 | if (match_int(&args[0], &option)) |