diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 119 |
1 files changed, 88 insertions, 31 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 8e4addaa5424..f3d02ca461ec 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -226,7 +226,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task) | |||
226 | { | 226 | { |
227 | struct mm_struct *mm; | 227 | struct mm_struct *mm; |
228 | 228 | ||
229 | if (mutex_lock_killable(&task->cred_guard_mutex)) | 229 | if (mutex_lock_killable(&task->signal->cred_guard_mutex)) |
230 | return NULL; | 230 | return NULL; |
231 | 231 | ||
232 | mm = get_task_mm(task); | 232 | mm = get_task_mm(task); |
@@ -235,7 +235,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task) | |||
235 | mmput(mm); | 235 | mmput(mm); |
236 | mm = NULL; | 236 | mm = NULL; |
237 | } | 237 | } |
238 | mutex_unlock(&task->cred_guard_mutex); | 238 | mutex_unlock(&task->signal->cred_guard_mutex); |
239 | 239 | ||
240 | return mm; | 240 | return mm; |
241 | } | 241 | } |
@@ -771,6 +771,8 @@ static const struct file_operations proc_single_file_operations = { | |||
771 | static int mem_open(struct inode* inode, struct file* file) | 771 | static int mem_open(struct inode* inode, struct file* file) |
772 | { | 772 | { |
773 | file->private_data = (void*)((long)current->self_exec_id); | 773 | file->private_data = (void*)((long)current->self_exec_id); |
774 | /* OK to pass negative loff_t, we can catch out-of-range */ | ||
775 | file->f_mode |= FMODE_UNSIGNED_OFFSET; | ||
774 | return 0; | 776 | return 0; |
775 | } | 777 | } |
776 | 778 | ||
@@ -1023,28 +1025,47 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1023 | memset(buffer, 0, sizeof(buffer)); | 1025 | memset(buffer, 0, sizeof(buffer)); |
1024 | if (count > sizeof(buffer) - 1) | 1026 | if (count > sizeof(buffer) - 1) |
1025 | count = sizeof(buffer) - 1; | 1027 | count = sizeof(buffer) - 1; |
1026 | if (copy_from_user(buffer, buf, count)) | 1028 | if (copy_from_user(buffer, buf, count)) { |
1027 | return -EFAULT; | 1029 | err = -EFAULT; |
1030 | goto out; | ||
1031 | } | ||
1028 | 1032 | ||
1029 | err = strict_strtol(strstrip(buffer), 0, &oom_adjust); | 1033 | err = strict_strtol(strstrip(buffer), 0, &oom_adjust); |
1030 | if (err) | 1034 | if (err) |
1031 | return -EINVAL; | 1035 | goto out; |
1032 | if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && | 1036 | if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) && |
1033 | oom_adjust != OOM_DISABLE) | 1037 | oom_adjust != OOM_DISABLE) { |
1034 | return -EINVAL; | 1038 | err = -EINVAL; |
1039 | goto out; | ||
1040 | } | ||
1035 | 1041 | ||
1036 | task = get_proc_task(file->f_path.dentry->d_inode); | 1042 | task = get_proc_task(file->f_path.dentry->d_inode); |
1037 | if (!task) | 1043 | if (!task) { |
1038 | return -ESRCH; | 1044 | err = -ESRCH; |
1045 | goto out; | ||
1046 | } | ||
1047 | |||
1048 | task_lock(task); | ||
1049 | if (!task->mm) { | ||
1050 | err = -EINVAL; | ||
1051 | goto err_task_lock; | ||
1052 | } | ||
1053 | |||
1039 | if (!lock_task_sighand(task, &flags)) { | 1054 | if (!lock_task_sighand(task, &flags)) { |
1040 | put_task_struct(task); | 1055 | err = -ESRCH; |
1041 | return -ESRCH; | 1056 | goto err_task_lock; |
1042 | } | 1057 | } |
1043 | 1058 | ||
1044 | if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { | 1059 | if (oom_adjust < task->signal->oom_adj && !capable(CAP_SYS_RESOURCE)) { |
1045 | unlock_task_sighand(task, &flags); | 1060 | err = -EACCES; |
1046 | put_task_struct(task); | 1061 | goto err_sighand; |
1047 | return -EACCES; | 1062 | } |
1063 | |||
1064 | if (oom_adjust != task->signal->oom_adj) { | ||
1065 | if (oom_adjust == OOM_DISABLE) | ||
1066 | atomic_inc(&task->mm->oom_disable_count); | ||
1067 | if (task->signal->oom_adj == OOM_DISABLE) | ||
1068 | atomic_dec(&task->mm->oom_disable_count); | ||
1048 | } | 1069 | } |
1049 | 1070 | ||
1050 | /* | 1071 | /* |
@@ -1065,10 +1086,13 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, | |||
1065 | else | 1086 | else |
1066 | task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) / | 1087 | task->signal->oom_score_adj = (oom_adjust * OOM_SCORE_ADJ_MAX) / |
1067 | -OOM_DISABLE; | 1088 | -OOM_DISABLE; |
1089 | err_sighand: | ||
1068 | unlock_task_sighand(task, &flags); | 1090 | unlock_task_sighand(task, &flags); |
1091 | err_task_lock: | ||
1092 | task_unlock(task); | ||
1069 | put_task_struct(task); | 1093 | put_task_struct(task); |
1070 | 1094 | out: | |
1071 | return count; | 1095 | return err < 0 ? err : count; |
1072 | } | 1096 | } |
1073 | 1097 | ||
1074 | static const struct file_operations proc_oom_adjust_operations = { | 1098 | static const struct file_operations proc_oom_adjust_operations = { |
@@ -1109,30 +1133,49 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf, | |||
1109 | memset(buffer, 0, sizeof(buffer)); | 1133 | memset(buffer, 0, sizeof(buffer)); |
1110 | if (count > sizeof(buffer) - 1) | 1134 | if (count > sizeof(buffer) - 1) |
1111 | count = sizeof(buffer) - 1; | 1135 | count = sizeof(buffer) - 1; |
1112 | if (copy_from_user(buffer, buf, count)) | 1136 | if (copy_from_user(buffer, buf, count)) { |
1113 | return -EFAULT; | 1137 | err = -EFAULT; |
1138 | goto out; | ||
1139 | } | ||
1114 | 1140 | ||
1115 | err = strict_strtol(strstrip(buffer), 0, &oom_score_adj); | 1141 | err = strict_strtol(strstrip(buffer), 0, &oom_score_adj); |
1116 | if (err) | 1142 | if (err) |
1117 | return -EINVAL; | 1143 | goto out; |
1118 | if (oom_score_adj < OOM_SCORE_ADJ_MIN || | 1144 | if (oom_score_adj < OOM_SCORE_ADJ_MIN || |
1119 | oom_score_adj > OOM_SCORE_ADJ_MAX) | 1145 | oom_score_adj > OOM_SCORE_ADJ_MAX) { |
1120 | return -EINVAL; | 1146 | err = -EINVAL; |
1147 | goto out; | ||
1148 | } | ||
1121 | 1149 | ||
1122 | task = get_proc_task(file->f_path.dentry->d_inode); | 1150 | task = get_proc_task(file->f_path.dentry->d_inode); |
1123 | if (!task) | 1151 | if (!task) { |
1124 | return -ESRCH; | 1152 | err = -ESRCH; |
1153 | goto out; | ||
1154 | } | ||
1155 | |||
1156 | task_lock(task); | ||
1157 | if (!task->mm) { | ||
1158 | err = -EINVAL; | ||
1159 | goto err_task_lock; | ||
1160 | } | ||
1161 | |||
1125 | if (!lock_task_sighand(task, &flags)) { | 1162 | if (!lock_task_sighand(task, &flags)) { |
1126 | put_task_struct(task); | 1163 | err = -ESRCH; |
1127 | return -ESRCH; | 1164 | goto err_task_lock; |
1128 | } | 1165 | } |
1166 | |||
1129 | if (oom_score_adj < task->signal->oom_score_adj && | 1167 | if (oom_score_adj < task->signal->oom_score_adj && |
1130 | !capable(CAP_SYS_RESOURCE)) { | 1168 | !capable(CAP_SYS_RESOURCE)) { |
1131 | unlock_task_sighand(task, &flags); | 1169 | err = -EACCES; |
1132 | put_task_struct(task); | 1170 | goto err_sighand; |
1133 | return -EACCES; | ||
1134 | } | 1171 | } |
1135 | 1172 | ||
1173 | if (oom_score_adj != task->signal->oom_score_adj) { | ||
1174 | if (oom_score_adj == OOM_SCORE_ADJ_MIN) | ||
1175 | atomic_inc(&task->mm->oom_disable_count); | ||
1176 | if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MIN) | ||
1177 | atomic_dec(&task->mm->oom_disable_count); | ||
1178 | } | ||
1136 | task->signal->oom_score_adj = oom_score_adj; | 1179 | task->signal->oom_score_adj = oom_score_adj; |
1137 | /* | 1180 | /* |
1138 | * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is | 1181 | * Scale /proc/pid/oom_adj appropriately ensuring that OOM_DISABLE is |
@@ -1143,14 +1186,19 @@ static ssize_t oom_score_adj_write(struct file *file, const char __user *buf, | |||
1143 | else | 1186 | else |
1144 | task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) / | 1187 | task->signal->oom_adj = (oom_score_adj * OOM_ADJUST_MAX) / |
1145 | OOM_SCORE_ADJ_MAX; | 1188 | OOM_SCORE_ADJ_MAX; |
1189 | err_sighand: | ||
1146 | unlock_task_sighand(task, &flags); | 1190 | unlock_task_sighand(task, &flags); |
1191 | err_task_lock: | ||
1192 | task_unlock(task); | ||
1147 | put_task_struct(task); | 1193 | put_task_struct(task); |
1148 | return count; | 1194 | out: |
1195 | return err < 0 ? err : count; | ||
1149 | } | 1196 | } |
1150 | 1197 | ||
1151 | static const struct file_operations proc_oom_score_adj_operations = { | 1198 | static const struct file_operations proc_oom_score_adj_operations = { |
1152 | .read = oom_score_adj_read, | 1199 | .read = oom_score_adj_read, |
1153 | .write = oom_score_adj_write, | 1200 | .write = oom_score_adj_write, |
1201 | .llseek = default_llseek, | ||
1154 | }; | 1202 | }; |
1155 | 1203 | ||
1156 | #ifdef CONFIG_AUDITSYSCALL | 1204 | #ifdef CONFIG_AUDITSYSCALL |
@@ -1600,6 +1648,7 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st | |||
1600 | 1648 | ||
1601 | /* Common stuff */ | 1649 | /* Common stuff */ |
1602 | ei = PROC_I(inode); | 1650 | ei = PROC_I(inode); |
1651 | inode->i_ino = get_next_ino(); | ||
1603 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 1652 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
1604 | inode->i_op = &proc_def_inode_operations; | 1653 | inode->i_op = &proc_def_inode_operations; |
1605 | 1654 | ||
@@ -2039,11 +2088,13 @@ static ssize_t proc_fdinfo_read(struct file *file, char __user *buf, | |||
2039 | static const struct file_operations proc_fdinfo_file_operations = { | 2088 | static const struct file_operations proc_fdinfo_file_operations = { |
2040 | .open = nonseekable_open, | 2089 | .open = nonseekable_open, |
2041 | .read = proc_fdinfo_read, | 2090 | .read = proc_fdinfo_read, |
2091 | .llseek = no_llseek, | ||
2042 | }; | 2092 | }; |
2043 | 2093 | ||
2044 | static const struct file_operations proc_fd_operations = { | 2094 | static const struct file_operations proc_fd_operations = { |
2045 | .read = generic_read_dir, | 2095 | .read = generic_read_dir, |
2046 | .readdir = proc_readfd, | 2096 | .readdir = proc_readfd, |
2097 | .llseek = default_llseek, | ||
2047 | }; | 2098 | }; |
2048 | 2099 | ||
2049 | /* | 2100 | /* |
@@ -2112,6 +2163,7 @@ static int proc_readfdinfo(struct file *filp, void *dirent, filldir_t filldir) | |||
2112 | static const struct file_operations proc_fdinfo_operations = { | 2163 | static const struct file_operations proc_fdinfo_operations = { |
2113 | .read = generic_read_dir, | 2164 | .read = generic_read_dir, |
2114 | .readdir = proc_readfdinfo, | 2165 | .readdir = proc_readfdinfo, |
2166 | .llseek = default_llseek, | ||
2115 | }; | 2167 | }; |
2116 | 2168 | ||
2117 | /* | 2169 | /* |
@@ -2302,14 +2354,14 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, | |||
2302 | goto out_free; | 2354 | goto out_free; |
2303 | 2355 | ||
2304 | /* Guard against adverse ptrace interaction */ | 2356 | /* Guard against adverse ptrace interaction */ |
2305 | length = mutex_lock_interruptible(&task->cred_guard_mutex); | 2357 | length = mutex_lock_interruptible(&task->signal->cred_guard_mutex); |
2306 | if (length < 0) | 2358 | if (length < 0) |
2307 | goto out_free; | 2359 | goto out_free; |
2308 | 2360 | ||
2309 | length = security_setprocattr(task, | 2361 | length = security_setprocattr(task, |
2310 | (char*)file->f_path.dentry->d_name.name, | 2362 | (char*)file->f_path.dentry->d_name.name, |
2311 | (void*)page, count); | 2363 | (void*)page, count); |
2312 | mutex_unlock(&task->cred_guard_mutex); | 2364 | mutex_unlock(&task->signal->cred_guard_mutex); |
2313 | out_free: | 2365 | out_free: |
2314 | free_page((unsigned long) page); | 2366 | free_page((unsigned long) page); |
2315 | out: | 2367 | out: |
@@ -2343,6 +2395,7 @@ static int proc_attr_dir_readdir(struct file * filp, | |||
2343 | static const struct file_operations proc_attr_dir_operations = { | 2395 | static const struct file_operations proc_attr_dir_operations = { |
2344 | .read = generic_read_dir, | 2396 | .read = generic_read_dir, |
2345 | .readdir = proc_attr_dir_readdir, | 2397 | .readdir = proc_attr_dir_readdir, |
2398 | .llseek = default_llseek, | ||
2346 | }; | 2399 | }; |
2347 | 2400 | ||
2348 | static struct dentry *proc_attr_dir_lookup(struct inode *dir, | 2401 | static struct dentry *proc_attr_dir_lookup(struct inode *dir, |
@@ -2542,6 +2595,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir, | |||
2542 | 2595 | ||
2543 | /* Initialize the inode */ | 2596 | /* Initialize the inode */ |
2544 | ei = PROC_I(inode); | 2597 | ei = PROC_I(inode); |
2598 | inode->i_ino = get_next_ino(); | ||
2545 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 2599 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
2546 | 2600 | ||
2547 | /* | 2601 | /* |
@@ -2751,6 +2805,7 @@ static int proc_tgid_base_readdir(struct file * filp, | |||
2751 | static const struct file_operations proc_tgid_base_operations = { | 2805 | static const struct file_operations proc_tgid_base_operations = { |
2752 | .read = generic_read_dir, | 2806 | .read = generic_read_dir, |
2753 | .readdir = proc_tgid_base_readdir, | 2807 | .readdir = proc_tgid_base_readdir, |
2808 | .llseek = default_llseek, | ||
2754 | }; | 2809 | }; |
2755 | 2810 | ||
2756 | static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ | 2811 | static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ |
@@ -3088,6 +3143,7 @@ static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *den | |||
3088 | static const struct file_operations proc_tid_base_operations = { | 3143 | static const struct file_operations proc_tid_base_operations = { |
3089 | .read = generic_read_dir, | 3144 | .read = generic_read_dir, |
3090 | .readdir = proc_tid_base_readdir, | 3145 | .readdir = proc_tid_base_readdir, |
3146 | .llseek = default_llseek, | ||
3091 | }; | 3147 | }; |
3092 | 3148 | ||
3093 | static const struct inode_operations proc_tid_base_inode_operations = { | 3149 | static const struct inode_operations proc_tid_base_inode_operations = { |
@@ -3324,4 +3380,5 @@ static const struct inode_operations proc_task_inode_operations = { | |||
3324 | static const struct file_operations proc_task_operations = { | 3380 | static const struct file_operations proc_task_operations = { |
3325 | .read = generic_read_dir, | 3381 | .read = generic_read_dir, |
3326 | .readdir = proc_task_readdir, | 3382 | .readdir = proc_task_readdir, |
3383 | .llseek = default_llseek, | ||
3327 | }; | 3384 | }; |