diff options
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r-- | fs/proc/base.c | 70 |
1 files changed, 50 insertions, 20 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 60316b52d659..9298324325ed 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -75,6 +75,7 @@ | |||
75 | #include <linux/ptrace.h> | 75 | #include <linux/ptrace.h> |
76 | #include <linux/tracehook.h> | 76 | #include <linux/tracehook.h> |
77 | #include <linux/printk.h> | 77 | #include <linux/printk.h> |
78 | #include <linux/cache.h> | ||
78 | #include <linux/cgroup.h> | 79 | #include <linux/cgroup.h> |
79 | #include <linux/cpuset.h> | 80 | #include <linux/cpuset.h> |
80 | #include <linux/audit.h> | 81 | #include <linux/audit.h> |
@@ -100,6 +101,8 @@ | |||
100 | #include "internal.h" | 101 | #include "internal.h" |
101 | #include "fd.h" | 102 | #include "fd.h" |
102 | 103 | ||
104 | #include "../../lib/kstrtox.h" | ||
105 | |||
103 | /* NOTE: | 106 | /* NOTE: |
104 | * Implementing inode permission operations in /proc is almost | 107 | * Implementing inode permission operations in /proc is almost |
105 | * certainly an error. Permission checks need to happen during | 108 | * certainly an error. Permission checks need to happen during |
@@ -110,8 +113,8 @@ | |||
110 | * in /proc for a task before it execs a suid executable. | 113 | * in /proc for a task before it execs a suid executable. |
111 | */ | 114 | */ |
112 | 115 | ||
113 | static u8 nlink_tid; | 116 | static u8 nlink_tid __ro_after_init; |
114 | static u8 nlink_tgid; | 117 | static u8 nlink_tgid __ro_after_init; |
115 | 118 | ||
116 | struct pid_entry { | 119 | struct pid_entry { |
117 | const char *name; | 120 | const char *name; |
@@ -1370,7 +1373,7 @@ static ssize_t proc_fail_nth_write(struct file *file, const char __user *buf, | |||
1370 | task = get_proc_task(file_inode(file)); | 1373 | task = get_proc_task(file_inode(file)); |
1371 | if (!task) | 1374 | if (!task) |
1372 | return -ESRCH; | 1375 | return -ESRCH; |
1373 | WRITE_ONCE(task->fail_nth, n); | 1376 | task->fail_nth = n; |
1374 | put_task_struct(task); | 1377 | put_task_struct(task); |
1375 | 1378 | ||
1376 | return count; | 1379 | return count; |
@@ -1386,8 +1389,7 @@ static ssize_t proc_fail_nth_read(struct file *file, char __user *buf, | |||
1386 | task = get_proc_task(file_inode(file)); | 1389 | task = get_proc_task(file_inode(file)); |
1387 | if (!task) | 1390 | if (!task) |
1388 | return -ESRCH; | 1391 | return -ESRCH; |
1389 | len = snprintf(numbuf, sizeof(numbuf), "%u\n", | 1392 | len = snprintf(numbuf, sizeof(numbuf), "%u\n", task->fail_nth); |
1390 | READ_ONCE(task->fail_nth)); | ||
1391 | len = simple_read_from_buffer(buf, count, ppos, numbuf, len); | 1393 | len = simple_read_from_buffer(buf, count, ppos, numbuf, len); |
1392 | put_task_struct(task); | 1394 | put_task_struct(task); |
1393 | 1395 | ||
@@ -1907,8 +1909,33 @@ end_instantiate: | |||
1907 | static int dname_to_vma_addr(struct dentry *dentry, | 1909 | static int dname_to_vma_addr(struct dentry *dentry, |
1908 | unsigned long *start, unsigned long *end) | 1910 | unsigned long *start, unsigned long *end) |
1909 | { | 1911 | { |
1910 | if (sscanf(dentry->d_name.name, "%lx-%lx", start, end) != 2) | 1912 | const char *str = dentry->d_name.name; |
1913 | unsigned long long sval, eval; | ||
1914 | unsigned int len; | ||
1915 | |||
1916 | len = _parse_integer(str, 16, &sval); | ||
1917 | if (len & KSTRTOX_OVERFLOW) | ||
1918 | return -EINVAL; | ||
1919 | if (sval != (unsigned long)sval) | ||
1911 | return -EINVAL; | 1920 | return -EINVAL; |
1921 | str += len; | ||
1922 | |||
1923 | if (*str != '-') | ||
1924 | return -EINVAL; | ||
1925 | str++; | ||
1926 | |||
1927 | len = _parse_integer(str, 16, &eval); | ||
1928 | if (len & KSTRTOX_OVERFLOW) | ||
1929 | return -EINVAL; | ||
1930 | if (eval != (unsigned long)eval) | ||
1931 | return -EINVAL; | ||
1932 | str += len; | ||
1933 | |||
1934 | if (*str != '\0') | ||
1935 | return -EINVAL; | ||
1936 | |||
1937 | *start = sval; | ||
1938 | *end = eval; | ||
1912 | 1939 | ||
1913 | return 0; | 1940 | return 0; |
1914 | } | 1941 | } |
@@ -2000,9 +2027,9 @@ out: | |||
2000 | } | 2027 | } |
2001 | 2028 | ||
2002 | struct map_files_info { | 2029 | struct map_files_info { |
2030 | unsigned long start; | ||
2031 | unsigned long end; | ||
2003 | fmode_t mode; | 2032 | fmode_t mode; |
2004 | unsigned int len; | ||
2005 | unsigned char name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */ | ||
2006 | }; | 2033 | }; |
2007 | 2034 | ||
2008 | /* | 2035 | /* |
@@ -2172,10 +2199,9 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx) | |||
2172 | if (++pos <= ctx->pos) | 2199 | if (++pos <= ctx->pos) |
2173 | continue; | 2200 | continue; |
2174 | 2201 | ||
2202 | info.start = vma->vm_start; | ||
2203 | info.end = vma->vm_end; | ||
2175 | info.mode = vma->vm_file->f_mode; | 2204 | info.mode = vma->vm_file->f_mode; |
2176 | info.len = snprintf(info.name, | ||
2177 | sizeof(info.name), "%lx-%lx", | ||
2178 | vma->vm_start, vma->vm_end); | ||
2179 | if (flex_array_put(fa, i++, &info, GFP_KERNEL)) | 2205 | if (flex_array_put(fa, i++, &info, GFP_KERNEL)) |
2180 | BUG(); | 2206 | BUG(); |
2181 | } | 2207 | } |
@@ -2183,9 +2209,13 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx) | |||
2183 | up_read(&mm->mmap_sem); | 2209 | up_read(&mm->mmap_sem); |
2184 | 2210 | ||
2185 | for (i = 0; i < nr_files; i++) { | 2211 | for (i = 0; i < nr_files; i++) { |
2212 | char buf[4 * sizeof(long) + 2]; /* max: %lx-%lx\0 */ | ||
2213 | unsigned int len; | ||
2214 | |||
2186 | p = flex_array_get(fa, i); | 2215 | p = flex_array_get(fa, i); |
2216 | len = snprintf(buf, sizeof(buf), "%lx-%lx", p->start, p->end); | ||
2187 | if (!proc_fill_cache(file, ctx, | 2217 | if (!proc_fill_cache(file, ctx, |
2188 | p->name, p->len, | 2218 | buf, len, |
2189 | proc_map_files_instantiate, | 2219 | proc_map_files_instantiate, |
2190 | task, | 2220 | task, |
2191 | (void *)(unsigned long)p->mode)) | 2221 | (void *)(unsigned long)p->mode)) |
@@ -3018,11 +3048,11 @@ static const struct inode_operations proc_tgid_base_inode_operations = { | |||
3018 | static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) | 3048 | static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) |
3019 | { | 3049 | { |
3020 | struct dentry *dentry, *leader, *dir; | 3050 | struct dentry *dentry, *leader, *dir; |
3021 | char buf[PROC_NUMBUF]; | 3051 | char buf[10 + 1]; |
3022 | struct qstr name; | 3052 | struct qstr name; |
3023 | 3053 | ||
3024 | name.name = buf; | 3054 | name.name = buf; |
3025 | name.len = snprintf(buf, sizeof(buf), "%d", pid); | 3055 | name.len = snprintf(buf, sizeof(buf), "%u", pid); |
3026 | /* no ->d_hash() rejects on procfs */ | 3056 | /* no ->d_hash() rejects on procfs */ |
3027 | dentry = d_hash_and_lookup(mnt->mnt_root, &name); | 3057 | dentry = d_hash_and_lookup(mnt->mnt_root, &name); |
3028 | if (dentry) { | 3058 | if (dentry) { |
@@ -3034,7 +3064,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) | |||
3034 | return; | 3064 | return; |
3035 | 3065 | ||
3036 | name.name = buf; | 3066 | name.name = buf; |
3037 | name.len = snprintf(buf, sizeof(buf), "%d", tgid); | 3067 | name.len = snprintf(buf, sizeof(buf), "%u", tgid); |
3038 | leader = d_hash_and_lookup(mnt->mnt_root, &name); | 3068 | leader = d_hash_and_lookup(mnt->mnt_root, &name); |
3039 | if (!leader) | 3069 | if (!leader) |
3040 | goto out; | 3070 | goto out; |
@@ -3046,7 +3076,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) | |||
3046 | goto out_put_leader; | 3076 | goto out_put_leader; |
3047 | 3077 | ||
3048 | name.name = buf; | 3078 | name.name = buf; |
3049 | name.len = snprintf(buf, sizeof(buf), "%d", pid); | 3079 | name.len = snprintf(buf, sizeof(buf), "%u", pid); |
3050 | dentry = d_hash_and_lookup(dir, &name); | 3080 | dentry = d_hash_and_lookup(dir, &name); |
3051 | if (dentry) { | 3081 | if (dentry) { |
3052 | d_invalidate(dentry); | 3082 | d_invalidate(dentry); |
@@ -3225,14 +3255,14 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx) | |||
3225 | for (iter = next_tgid(ns, iter); | 3255 | for (iter = next_tgid(ns, iter); |
3226 | iter.task; | 3256 | iter.task; |
3227 | iter.tgid += 1, iter = next_tgid(ns, iter)) { | 3257 | iter.tgid += 1, iter = next_tgid(ns, iter)) { |
3228 | char name[PROC_NUMBUF]; | 3258 | char name[10 + 1]; |
3229 | int len; | 3259 | int len; |
3230 | 3260 | ||
3231 | cond_resched(); | 3261 | cond_resched(); |
3232 | if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE)) | 3262 | if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE)) |
3233 | continue; | 3263 | continue; |
3234 | 3264 | ||
3235 | len = snprintf(name, sizeof(name), "%d", iter.tgid); | 3265 | len = snprintf(name, sizeof(name), "%u", iter.tgid); |
3236 | ctx->pos = iter.tgid + TGID_OFFSET; | 3266 | ctx->pos = iter.tgid + TGID_OFFSET; |
3237 | if (!proc_fill_cache(file, ctx, name, len, | 3267 | if (!proc_fill_cache(file, ctx, name, len, |
3238 | proc_pid_instantiate, iter.task, NULL)) { | 3268 | proc_pid_instantiate, iter.task, NULL)) { |
@@ -3560,10 +3590,10 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx) | |||
3560 | for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns); | 3590 | for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns); |
3561 | task; | 3591 | task; |
3562 | task = next_tid(task), ctx->pos++) { | 3592 | task = next_tid(task), ctx->pos++) { |
3563 | char name[PROC_NUMBUF]; | 3593 | char name[10 + 1]; |
3564 | int len; | 3594 | int len; |
3565 | tid = task_pid_nr_ns(task, ns); | 3595 | tid = task_pid_nr_ns(task, ns); |
3566 | len = snprintf(name, sizeof(name), "%d", tid); | 3596 | len = snprintf(name, sizeof(name), "%u", tid); |
3567 | if (!proc_fill_cache(file, ctx, name, len, | 3597 | if (!proc_fill_cache(file, ctx, name, len, |
3568 | proc_task_instantiate, task, NULL)) { | 3598 | proc_task_instantiate, task, NULL)) { |
3569 | /* returning this tgid failed, save it as the first | 3599 | /* returning this tgid failed, save it as the first |