diff options
| author | Ingo Molnar <mingo@kernel.org> | 2015-01-28 09:30:32 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2015-01-28 09:30:32 -0500 |
| commit | 41ca5d4e9be11ea6ae040b51d9628a189fd82896 (patch) | |
| tree | f9c35cc37b9622f6cccd91b94548f44b9a534029 /arch/x86/kernel/tls.c | |
| parent | 0fcedc8631ec28ca25d3c0b116e8fa0c19dd5f6d (diff) | |
| parent | 3669ef9fa7d35f573ec9c0e0341b29251c2734a7 (diff) | |
Merge commit 3669ef9fa7d3 ("x86, tls: Interpret an all-zero struct user_desc as 'no segment'") into x86/asm
Pick up the latestest asm fixes before advancing it any further.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/kernel/tls.c')
| -rw-r--r-- | arch/x86/kernel/tls.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 4e942f31b1a7..7fc5e843f247 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c | |||
| @@ -29,7 +29,28 @@ static int get_free_idx(void) | |||
| 29 | 29 | ||
| 30 | static bool tls_desc_okay(const struct user_desc *info) | 30 | static bool tls_desc_okay(const struct user_desc *info) |
| 31 | { | 31 | { |
| 32 | if (LDT_empty(info)) | 32 | /* |
| 33 | * For historical reasons (i.e. no one ever documented how any | ||
| 34 | * of the segmentation APIs work), user programs can and do | ||
| 35 | * assume that a struct user_desc that's all zeros except for | ||
| 36 | * entry_number means "no segment at all". This never actually | ||
| 37 | * worked. In fact, up to Linux 3.19, a struct user_desc like | ||
| 38 | * this would create a 16-bit read-write segment with base and | ||
| 39 | * limit both equal to zero. | ||
| 40 | * | ||
| 41 | * That was close enough to "no segment at all" until we | ||
| 42 | * hardened this function to disallow 16-bit TLS segments. Fix | ||
| 43 | * it up by interpreting these zeroed segments the way that they | ||
| 44 | * were almost certainly intended to be interpreted. | ||
| 45 | * | ||
| 46 | * The correct way to ask for "no segment at all" is to specify | ||
| 47 | * a user_desc that satisfies LDT_empty. To keep everything | ||
| 48 | * working, we accept both. | ||
| 49 | * | ||
| 50 | * Note that there's a similar kludge in modify_ldt -- look at | ||
| 51 | * the distinction between modes 1 and 0x11. | ||
| 52 | */ | ||
| 53 | if (LDT_empty(info) || LDT_zero(info)) | ||
| 33 | return true; | 54 | return true; |
| 34 | 55 | ||
| 35 | /* | 56 | /* |
| @@ -71,7 +92,7 @@ static void set_tls_desc(struct task_struct *p, int idx, | |||
| 71 | cpu = get_cpu(); | 92 | cpu = get_cpu(); |
| 72 | 93 | ||
| 73 | while (n-- > 0) { | 94 | while (n-- > 0) { |
| 74 | if (LDT_empty(info)) | 95 | if (LDT_empty(info) || LDT_zero(info)) |
| 75 | desc->a = desc->b = 0; | 96 | desc->a = desc->b = 0; |
| 76 | else | 97 | else |
| 77 | fill_ldt(desc, info); | 98 | fill_ldt(desc, info); |
