diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 93 |
1 files changed, 85 insertions, 8 deletions
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, |