aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-07-19 18:11:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-07-19 18:11:09 -0400
commitd471ce53b1fab60110e4e9f647a345cea31752de (patch)
tree73acb87c823b63d026f9ba4617b5e112835d6abf
parent1b050180454dc226780f765a33575d4cd8d6e552 (diff)
parent9e82d450531c79b18ab18c9b9645cdd9db31ee98 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML fixes from Richard Weinberger: "Special thanks goes to Toralf Föster for continuously testing UML and reporting issues!" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml: um: remove dead code um: siginfo cleanup uml: Fix which_tmpdir failure when /dev/shm is a symlink, and in other edge cases um: Fix wait_stub_done() error handling um: Mark stub pages mapping with VM_PFNMAP um: Fix return value of strnlen_user()
-rw-r--r--arch/um/include/shared/frame_kern.h8
-rw-r--r--arch/um/kernel/signal.c4
-rw-r--r--arch/um/kernel/skas/mmu.c2
-rw-r--r--arch/um/kernel/skas/uaccess.c2
-rw-r--r--arch/um/os-Linux/mem.c230
-rw-r--r--arch/um/os-Linux/signal.c8
-rw-r--r--arch/um/os-Linux/skas/process.c19
-rw-r--r--arch/x86/um/signal.c1
8 files changed, 213 insertions, 61 deletions
diff --git a/arch/um/include/shared/frame_kern.h b/arch/um/include/shared/frame_kern.h
index e584e40ee832..f2ca5702a4e2 100644
--- a/arch/um/include/shared/frame_kern.h
+++ b/arch/um/include/shared/frame_kern.h
@@ -6,13 +6,13 @@
6#ifndef __FRAME_KERN_H_ 6#ifndef __FRAME_KERN_H_
7#define __FRAME_KERN_H_ 7#define __FRAME_KERN_H_
8 8
9extern int setup_signal_stack_sc(unsigned long stack_top, int sig, 9extern int setup_signal_stack_sc(unsigned long stack_top, int sig,
10 struct k_sigaction *ka, 10 struct k_sigaction *ka,
11 struct pt_regs *regs, 11 struct pt_regs *regs,
12 sigset_t *mask); 12 sigset_t *mask);
13extern int setup_signal_stack_si(unsigned long stack_top, int sig, 13extern int setup_signal_stack_si(unsigned long stack_top, int sig,
14 struct k_sigaction *ka, 14 struct k_sigaction *ka,
15 struct pt_regs *regs, siginfo_t *info, 15 struct pt_regs *regs, struct siginfo *info,
16 sigset_t *mask); 16 sigset_t *mask);
17 17
18#endif 18#endif
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 3e831b3fd07b..f57e02e7910f 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -19,7 +19,7 @@ EXPORT_SYMBOL(unblock_signals);
19 * OK, we're invoking a handler 19 * OK, we're invoking a handler
20 */ 20 */
21static void handle_signal(struct pt_regs *regs, unsigned long signr, 21static void handle_signal(struct pt_regs *regs, unsigned long signr,
22 struct k_sigaction *ka, siginfo_t *info) 22 struct k_sigaction *ka, struct siginfo *info)
23{ 23{
24 sigset_t *oldset = sigmask_to_save(); 24 sigset_t *oldset = sigmask_to_save();
25 int singlestep = 0; 25 int singlestep = 0;
@@ -71,7 +71,7 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr,
71static int kern_do_signal(struct pt_regs *regs) 71static int kern_do_signal(struct pt_regs *regs)
72{ 72{
73 struct k_sigaction ka_copy; 73 struct k_sigaction ka_copy;
74 siginfo_t info; 74 struct siginfo info;
75 int sig, handled_sig = 0; 75 int sig, handled_sig = 0;
76 76
77 while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) { 77 while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index ff03067a3b14..007d5503f49b 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -123,7 +123,7 @@ void uml_setup_stubs(struct mm_struct *mm)
123 /* dup_mmap already holds mmap_sem */ 123 /* dup_mmap already holds mmap_sem */
124 err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START, 124 err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
125 VM_READ | VM_MAYREAD | VM_EXEC | 125 VM_READ | VM_MAYREAD | VM_EXEC |
126 VM_MAYEXEC | VM_DONTCOPY, 126 VM_MAYEXEC | VM_DONTCOPY | VM_PFNMAP,
127 mm->context.stub_pages); 127 mm->context.stub_pages);
128 if (err) { 128 if (err) {
129 printk(KERN_ERR "install_special_mapping returned %d\n", err); 129 printk(KERN_ERR "install_special_mapping returned %d\n", err);
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index 1d3e0c17340b..4ffb644d6c07 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -254,6 +254,6 @@ int strnlen_user(const void __user *str, int len)
254 n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count); 254 n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
255 if (n == 0) 255 if (n == 0)
256 return count + 1; 256 return count + 1;
257 return -EFAULT; 257 return 0;
258} 258}
259EXPORT_SYMBOL(strnlen_user); 259EXPORT_SYMBOL(strnlen_user);
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
index ba4398056fe9..3c4af77e51a2 100644
--- a/arch/um/os-Linux/mem.c
+++ b/arch/um/os-Linux/mem.c
@@ -53,6 +53,25 @@ static void __init find_tempdir(void)
53} 53}
54 54
55/* 55/*
56 * Remove bytes from the front of the buffer and refill it so that if there's a
57 * partial string that we care about, it will be completed, and we can recognize
58 * it.
59 */
60static int pop(int fd, char *buf, size_t size, size_t npop)
61{
62 ssize_t n;
63 size_t len = strlen(&buf[npop]);
64
65 memmove(buf, &buf[npop], len + 1);
66 n = read(fd, &buf[len], size - len - 1);
67 if (n < 0)
68 return -errno;
69
70 buf[len + n] = '\0';
71 return 1;
72}
73
74/*
56 * This will return 1, with the first character in buf being the 75 * This will return 1, with the first character in buf being the
57 * character following the next instance of c in the file. This will 76 * character following the next instance of c in the file. This will
58 * read the file as needed. If there's an error, -errno is returned; 77 * read the file as needed. If there's an error, -errno is returned;
@@ -61,7 +80,6 @@ static void __init find_tempdir(void)
61static int next(int fd, char *buf, size_t size, char c) 80static int next(int fd, char *buf, size_t size, char c)
62{ 81{
63 ssize_t n; 82 ssize_t n;
64 size_t len;
65 char *ptr; 83 char *ptr;
66 84
67 while ((ptr = strchr(buf, c)) == NULL) { 85 while ((ptr = strchr(buf, c)) == NULL) {
@@ -74,20 +92,129 @@ static int next(int fd, char *buf, size_t size, char c)
74 buf[n] = '\0'; 92 buf[n] = '\0';
75 } 93 }
76 94
77 ptr++; 95 return pop(fd, buf, size, ptr - buf + 1);
78 len = strlen(ptr); 96}
79 memmove(buf, ptr, len + 1); 97
98/*
99 * Decode an octal-escaped and space-terminated path of the form used by
100 * /proc/mounts. May be used to decode a path in-place. "out" must be at least
101 * as large as the input. The output is always null-terminated. "len" gets the
102 * length of the output, excluding the trailing null. Returns 0 if a full path
103 * was successfully decoded, otherwise an error.
104 */
105static int decode_path(const char *in, char *out, size_t *len)
106{
107 char *first = out;
108 int c;
109 int i;
110 int ret = -EINVAL;
111 while (1) {
112 switch (*in) {
113 case '\0':
114 goto out;
115
116 case ' ':
117 ret = 0;
118 goto out;
119
120 case '\\':
121 in++;
122 c = 0;
123 for (i = 0; i < 3; i++) {
124 if (*in < '0' || *in > '7')
125 goto out;
126 c = (c << 3) | (*in++ - '0');
127 }
128 *(unsigned char *)out++ = (unsigned char) c;
129 break;
130
131 default:
132 *out++ = *in++;
133 break;
134 }
135 }
136
137out:
138 *out = '\0';
139 *len = out - first;
140 return ret;
141}
142
143/*
144 * Computes the length of s when encoded with three-digit octal escape sequences
145 * for the characters in chars.
146 */
147static size_t octal_encoded_length(const char *s, const char *chars)
148{
149 size_t len = strlen(s);
150 while ((s = strpbrk(s, chars)) != NULL) {
151 len += 3;
152 s++;
153 }
154
155 return len;
156}
157
158enum {
159 OUTCOME_NOTHING_MOUNTED,
160 OUTCOME_TMPFS_MOUNT,
161 OUTCOME_NON_TMPFS_MOUNT,
162};
163
164/* Read a line of /proc/mounts data looking for a tmpfs mount at "path". */
165static int read_mount(int fd, char *buf, size_t bufsize, const char *path,
166 int *outcome)
167{
168 int found;
169 int match;
170 char *space;
171 size_t len;
172
173 enum {
174 MATCH_NONE,
175 MATCH_EXACT,
176 MATCH_PARENT,
177 };
178
179 found = next(fd, buf, bufsize, ' ');
180 if (found != 1)
181 return found;
80 182
81 /* 183 /*
82 * Refill the buffer so that if there's a partial string that we care 184 * If there's no following space in the buffer, then this path is
83 * about, it will be completed, and we can recognize it. 185 * truncated, so it can't be the one we're looking for.
84 */ 186 */
85 n = read(fd, &buf[len], size - len - 1); 187 space = strchr(buf, ' ');
86 if (n < 0) 188 if (space) {
87 return -errno; 189 match = MATCH_NONE;
190 if (!decode_path(buf, buf, &len)) {
191 if (!strcmp(buf, path))
192 match = MATCH_EXACT;
193 else if (!strncmp(buf, path, len)
194 && (path[len] == '/' || !strcmp(buf, "/")))
195 match = MATCH_PARENT;
196 }
197
198 found = pop(fd, buf, bufsize, space - buf + 1);
199 if (found != 1)
200 return found;
201
202 switch (match) {
203 case MATCH_EXACT:
204 if (!strncmp(buf, "tmpfs", strlen("tmpfs")))
205 *outcome = OUTCOME_TMPFS_MOUNT;
206 else
207 *outcome = OUTCOME_NON_TMPFS_MOUNT;
208 break;
88 209
89 buf[len + n] = '\0'; 210 case MATCH_PARENT:
90 return 1; 211 /* This mount obscures any previous ones. */
212 *outcome = OUTCOME_NOTHING_MOUNTED;
213 break;
214 }
215 }
216
217 return next(fd, buf, bufsize, '\n');
91} 218}
92 219
93/* which_tmpdir is called only during early boot */ 220/* which_tmpdir is called only during early boot */
@@ -106,8 +233,12 @@ static int checked_tmpdir = 0;
106 */ 233 */
107static void which_tmpdir(void) 234static void which_tmpdir(void)
108{ 235{
109 int fd, found; 236 int fd;
110 char buf[128] = { '\0' }; 237 int found;
238 int outcome;
239 char *path;
240 char *buf;
241 size_t bufsize;
111 242
112 if (checked_tmpdir) 243 if (checked_tmpdir)
113 return; 244 return;
@@ -116,49 +247,66 @@ static void which_tmpdir(void)
116 247
117 printf("Checking for tmpfs mount on /dev/shm..."); 248 printf("Checking for tmpfs mount on /dev/shm...");
118 249
250 path = realpath("/dev/shm", NULL);
251 if (!path) {
252 printf("failed to check real path, errno = %d\n", errno);
253 return;
254 }
255 printf("%s...", path);
256
257 /*
258 * The buffer needs to be able to fit the full octal-escaped path, a
259 * space, and a trailing null in order to successfully decode it.
260 */
261 bufsize = octal_encoded_length(path, " \t\n\\") + 2;
262
263 if (bufsize < 128)
264 bufsize = 128;
265
266 buf = malloc(bufsize);
267 if (!buf) {
268 printf("malloc failed, errno = %d\n", errno);
269 goto out;
270 }
271 buf[0] = '\0';
272
119 fd = open("/proc/mounts", O_RDONLY); 273 fd = open("/proc/mounts", O_RDONLY);
120 if (fd < 0) { 274 if (fd < 0) {
121 printf("failed to open /proc/mounts, errno = %d\n", errno); 275 printf("failed to open /proc/mounts, errno = %d\n", errno);
122 return; 276 goto out1;
123 } 277 }
124 278
279 outcome = OUTCOME_NOTHING_MOUNTED;
125 while (1) { 280 while (1) {
126 found = next(fd, buf, ARRAY_SIZE(buf), ' '); 281 found = read_mount(fd, buf, bufsize, path, &outcome);
127 if (found != 1)
128 break;
129
130 if (!strncmp(buf, "/dev/shm", strlen("/dev/shm")))
131 goto found;
132
133 found = next(fd, buf, ARRAY_SIZE(buf), '\n');
134 if (found != 1) 282 if (found != 1)
135 break; 283 break;
136 } 284 }
137 285
138err: 286 if (found < 0) {
139 if (found == 0)
140 printf("nothing mounted on /dev/shm\n");
141 else if (found < 0)
142 printf("read returned errno %d\n", -found); 287 printf("read returned errno %d\n", -found);
288 } else {
289 switch (outcome) {
290 case OUTCOME_TMPFS_MOUNT:
291 printf("OK\n");
292 default_tmpdir = "/dev/shm";
293 break;
143 294
144out: 295 case OUTCOME_NON_TMPFS_MOUNT:
145 close(fd); 296 printf("not tmpfs\n");
146 297 break;
147 return;
148
149found:
150 found = next(fd, buf, ARRAY_SIZE(buf), ' ');
151 if (found != 1)
152 goto err;
153 298
154 if (strncmp(buf, "tmpfs", strlen("tmpfs"))) { 299 default:
155 printf("not tmpfs\n"); 300 printf("nothing mounted on /dev/shm\n");
156 goto out; 301 break;
302 }
157 } 303 }
158 304
159 printf("OK\n"); 305 close(fd);
160 default_tmpdir = "/dev/shm"; 306out1:
161 goto out; 307 free(buf);
308out:
309 free(path);
162} 310}
163 311
164static int __init make_tempfile(const char *template, char **out_tempname, 312static int __init make_tempfile(const char *template, char **out_tempname,
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 9d9f1b4bf826..905924b773d3 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -25,7 +25,7 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
25 [SIGIO] = sigio_handler, 25 [SIGIO] = sigio_handler,
26 [SIGVTALRM] = timer_handler }; 26 [SIGVTALRM] = timer_handler };
27 27
28static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc) 28static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
29{ 29{
30 struct uml_pt_regs r; 30 struct uml_pt_regs r;
31 int save_errno = errno; 31 int save_errno = errno;
@@ -61,7 +61,7 @@ static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc)
61static int signals_enabled; 61static int signals_enabled;
62static unsigned int signals_pending; 62static unsigned int signals_pending;
63 63
64void sig_handler(int sig, siginfo_t *si, mcontext_t *mc) 64void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
65{ 65{
66 int enabled; 66 int enabled;
67 67
@@ -120,7 +120,7 @@ void set_sigstack(void *sig_stack, int size)
120 panic("enabling signal stack failed, errno = %d\n", errno); 120 panic("enabling signal stack failed, errno = %d\n", errno);
121} 121}
122 122
123static void (*handlers[_NSIG])(int sig, siginfo_t *si, mcontext_t *mc) = { 123static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
124 [SIGSEGV] = sig_handler, 124 [SIGSEGV] = sig_handler,
125 [SIGBUS] = sig_handler, 125 [SIGBUS] = sig_handler,
126 [SIGILL] = sig_handler, 126 [SIGILL] = sig_handler,
@@ -162,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *si, void *p)
162 while ((sig = ffs(pending)) != 0){ 162 while ((sig = ffs(pending)) != 0){
163 sig--; 163 sig--;
164 pending &= ~(1 << sig); 164 pending &= ~(1 << sig);
165 (*handlers[sig])(sig, si, mc); 165 (*handlers[sig])(sig, (struct siginfo *)si, mc);
166 } 166 }
167 167
168 /* 168 /*
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 4625949bf1e4..d531879a4617 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -54,7 +54,7 @@ static int ptrace_dump_regs(int pid)
54 54
55void wait_stub_done(int pid) 55void wait_stub_done(int pid)
56{ 56{
57 int n, status, err; 57 int n, status, err, bad_stop = 0;
58 58
59 while (1) { 59 while (1) {
60 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL)); 60 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED | __WALL));
@@ -74,6 +74,8 @@ void wait_stub_done(int pid)
74 74
75 if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0) 75 if (((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
76 return; 76 return;
77 else
78 bad_stop = 1;
77 79
78bad_wait: 80bad_wait:
79 err = ptrace_dump_regs(pid); 81 err = ptrace_dump_regs(pid);
@@ -83,7 +85,10 @@ bad_wait:
83 printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, " 85 printk(UM_KERN_ERR "wait_stub_done : failed to wait for SIGTRAP, "
84 "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno, 86 "pid = %d, n = %d, errno = %d, status = 0x%x\n", pid, n, errno,
85 status); 87 status);
86 fatal_sigsegv(); 88 if (bad_stop)
89 kill(pid, SIGKILL);
90 else
91 fatal_sigsegv();
87} 92}
88 93
89extern unsigned long current_stub_stack(void); 94extern unsigned long current_stub_stack(void);
@@ -409,7 +414,7 @@ void userspace(struct uml_pt_regs *regs)
409 if (WIFSTOPPED(status)) { 414 if (WIFSTOPPED(status)) {
410 int sig = WSTOPSIG(status); 415 int sig = WSTOPSIG(status);
411 416
412 ptrace(PTRACE_GETSIGINFO, pid, 0, &si); 417 ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si);
413 418
414 switch (sig) { 419 switch (sig) {
415 case SIGSEGV: 420 case SIGSEGV:
@@ -417,7 +422,7 @@ void userspace(struct uml_pt_regs *regs)
417 !ptrace_faultinfo) { 422 !ptrace_faultinfo) {
418 get_skas_faultinfo(pid, 423 get_skas_faultinfo(pid,
419 &regs->faultinfo); 424 &regs->faultinfo);
420 (*sig_info[SIGSEGV])(SIGSEGV, &si, 425 (*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si,
421 regs); 426 regs);
422 } 427 }
423 else handle_segv(pid, regs); 428 else handle_segv(pid, regs);
@@ -426,14 +431,14 @@ void userspace(struct uml_pt_regs *regs)
426 handle_trap(pid, regs, local_using_sysemu); 431 handle_trap(pid, regs, local_using_sysemu);
427 break; 432 break;
428 case SIGTRAP: 433 case SIGTRAP:
429 relay_signal(SIGTRAP, &si, regs); 434 relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
430 break; 435 break;
431 case SIGVTALRM: 436 case SIGVTALRM:
432 now = os_nsecs(); 437 now = os_nsecs();
433 if (now < nsecs) 438 if (now < nsecs)
434 break; 439 break;
435 block_signals(); 440 block_signals();
436 (*sig_info[sig])(sig, &si, regs); 441 (*sig_info[sig])(sig, (struct siginfo *)&si, regs);
437 unblock_signals(); 442 unblock_signals();
438 nsecs = timer.it_value.tv_sec * 443 nsecs = timer.it_value.tv_sec *
439 UM_NSEC_PER_SEC + 444 UM_NSEC_PER_SEC +
@@ -447,7 +452,7 @@ void userspace(struct uml_pt_regs *regs)
447 case SIGFPE: 452 case SIGFPE:
448 case SIGWINCH: 453 case SIGWINCH:
449 block_signals(); 454 block_signals();
450 (*sig_info[sig])(sig, &si, regs); 455 (*sig_info[sig])(sig, (struct siginfo *)&si, regs);
451 unblock_signals(); 456 unblock_signals();
452 break; 457 break;
453 default: 458 default:
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c
index ae7319db18ee..5e04a1c899fa 100644
--- a/arch/x86/um/signal.c
+++ b/arch/x86/um/signal.c
@@ -508,7 +508,6 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
508{ 508{
509 struct rt_sigframe __user *frame; 509 struct rt_sigframe __user *frame;
510 int err = 0; 510 int err = 0;
511 struct task_struct *me = current;
512 511
513 frame = (struct rt_sigframe __user *) 512 frame = (struct rt_sigframe __user *)
514 round_down(stack_top - sizeof(struct rt_sigframe), 16); 513 round_down(stack_top - sizeof(struct rt_sigframe), 16);