Skip to contentSkip to conversation

x86: kill handle_signal()->set_fs()

PATCH In review Oleg Nesterov 2 participants 5 messages Jul 10, 2011 – Jul 15, 2011 x86

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86: kill handle_signal()->set_fs()

handle_signal()->set_fs() has a nice comment which explains what set_fs() is, but it doesn't explain why it is needed and why it depends on CONFIG_X86_64.

Afaics, the history of this confusion is:

1. I guess today nobody can explain why it was needed in arch/i386/kernel/signal.c, perhaps it was always wrong. This predates 2.4.0 kernel.

2. then it was copy-and-past'ed to the new x86_64 arch.

3. then it was removed from i386 (but not from x86_64) by b93b6ca3 "i386: remove unnecessary code".

4. then it was reintroduced under CONFIG_X86_64 when x86 unified i386 and x86_64, because the patch above didn't touch x86_64.

Remove it. ->addr_limit should be correct. Even if it was possible that it is wrong, it is too late to fix it after setup_rt_frame().

---

 arch/x86/kernel/signal.c |    9 ---------
 1 file changed, 9 deletions(-)
arch/x86/kernel/signal.c renamed from arch/x86/kernel/signal.c~1_kill_set_fs +0 -9
@@ -717,15 +717,6 @@ handle_signal(unsigned long sig, siginfo
 	if (ret)
 		return ret;
 
-#ifdef CONFIG_X86_64
-	/*
-	 * This has nothing to do with segment registers,
-	 * despite the name.  This magic affects uaccess.h
-	 * macros' behavior.  Reset it to the normal setting.
-	 */
-	set_fs(USER_DS);
-#endif
-
 	/*
 	 * Clear the direction flag as per the ABI for function entry.
 	 */
#1 lore raw
Quoted 15 lines · Oleg Nesterov

handle_signal()->set_fs() has a nice comment which explains what set_fs() is, but it doesn't explain why it is needed and why it depends on CONFIG_X86_64.

Afaics, the history of this confusion is:

1. I guess today nobody can explain why it was needed in arch/i386/kernel/signal.c, perhaps it was always wrong. This predates 2.4.0 kernel.

2. then it was copy-and-past'ed to the new x86_64 arch.

3. then it was removed from i386 (but not from x86_64) by b93b6ca3 "i386: remove unnecessary code".

Quoted 7 lines

4. then it was reintroduced under CONFIG_X86_64 when x86 unified i386 and x86_64, because the patch above didn't touch x86_64.

Remove it. ->addr_limit should be correct. Even if it was possible that it is wrong, it is too late to fix it after setup_rt_frame().

The main reason I could think of why this would be necessary is if we take an event while we have fs == KERNEL_DS inside the kernel which is then promoted to a signal. Are you absolutely sure that can't happen?

In particular, there should be a setting upstream of this, as you're correctly pointing out that it's too late. If not, we might actually have a problem.

-hpa

#2 lore raw
Quoted 21 lines · H. Peter Anvin
Quoted 19 lines · Oleg Nesterov

handle_signal()->set_fs() has a nice comment which explains what set_fs() is, but it doesn't explain why it is needed and why it depends on CONFIG_X86_64.

Afaics, the history of this confusion is:

1. I guess today nobody can explain why it was needed in arch/i386/kernel/signal.c, perhaps it was always wrong. This predates 2.4.0 kernel.

2. then it was copy-and-past'ed to the new x86_64 arch.

3. then it was removed from i386 (but not from x86_64) by b93b6ca3 "i386: remove unnecessary code".

4. then it was reintroduced under CONFIG_X86_64 when x86 unified i386 and x86_64, because the patch above didn't touch x86_64.

Quoted 6 lines
Quoted 3 lines

Remove it. ->addr_limit should be correct. Even if it was possible that it is wrong, it is too late to fix it after setup_rt_frame().

The main reason I could think of why this would be necessary is if we take an event while we have fs == KERNEL_DS inside the kernel

this is possible if we are the kernel thread, or set_fs(KERNEL_DS) was called.

Quoted 2 lines

which is
then promoted to a signal.

How? We are going to return to the user-space. Obviously this is not possible with the kernel thread. So I think this can only happen if we already have a bug with unbalanced set_fs().

Are you absolutely sure that can't happen?

Quoted 3 lines

In particular, there should be a setting upstream of this, as you're correctly pointing out that it's too late. If not, we might actually have a problem.

Hmm... Now I recall, this was already discussed 5 years ago. Thanks to google, see http://lkml.org/lkml/2007/7/17/321

In particular, Linus sayd:

Heh. I think it's entirely historical.

Please realize that the whole reason that function is called "set_fs()" is that it literally used to set the %fs segment register, not "->addr_limit".

So I think the "set_fs(USER_DS)" is there _only_ to match the other

regs->xds = __USER_DS;
regs->xes = __USER_DS;
regs->xss = __USER_DS;
regs->xcs = __USER_CS;

things, and never mattered. And now it matters even less, and has been copied to all other architectures where it is just totally insane.

Oleg.

#3 lore raw

So, Peter, do you agree we can remove this set_fs() ?

Of course, this doesn't matter from the perfomance pov. But it is very confusing, especially with CONFIG_X86_64.

Quoted 68 lines · Oleg Nesterov
Quoted 21 lines · H. Peter Anvin
Quoted 19 lines · Oleg Nesterov

handle_signal()->set_fs() has a nice comment which explains what set_fs() is, but it doesn't explain why it is needed and why it depends on CONFIG_X86_64.

Afaics, the history of this confusion is:

1. I guess today nobody can explain why it was needed in arch/i386/kernel/signal.c, perhaps it was always wrong. This predates 2.4.0 kernel.

2. then it was copy-and-past'ed to the new x86_64 arch.

3. then it was removed from i386 (but not from x86_64) by b93b6ca3 "i386: remove unnecessary code".

4. then it was reintroduced under CONFIG_X86_64 when x86 unified i386 and x86_64, because the patch above didn't touch x86_64.

Quoted 6 lines
Quoted 3 lines

Remove it. ->addr_limit should be correct. Even if it was possible that it is wrong, it is too late to fix it after setup_rt_frame().

The main reason I could think of why this would be necessary is if we take an event while we have fs == KERNEL_DS inside the kernel

this is possible if we are the kernel thread, or set_fs(KERNEL_DS) was called.

Quoted 2 lines

which is
then promoted to a signal.

How? We are going to return to the user-space. Obviously this is not possible with the kernel thread. So I think this can only happen if we already have a bug with unbalanced set_fs().

Are you absolutely sure that can't happen?

Quoted 3 lines

In particular, there should be a setting upstream of this, as you're correctly pointing out that it's too late. If not, we might actually have a problem.

Hmm... Now I recall, this was already discussed 5 years ago. Thanks to google, see http://lkml.org/lkml/2007/7/17/321

In particular, Linus sayd:

Heh. I think it's entirely historical.

Please realize that the whole reason that function is called "set_fs()" is that it literally used to set the %fs segment register, not "->addr_limit".

So I think the "set_fs(USER_DS)" is there _only_ to match the other

regs->xds = __USER_DS;
regs->xes = __USER_DS;
regs->xss = __USER_DS;
regs->xcs = __USER_CS;

things, and never mattered. And now it matters even less, and has been copied to all other architectures where it is just totally insane.

Oleg.

#4 lore raw

[tip:x86/signal] x86: Kill handle_signal()->set_fs()

In reply to Oleg Nesterov
Commit-ID:  73d382deccac186d103496bf10388bc2432a8384
Gitweb:     http://git.kernel.org/tip/73d382deccac186d103496bf10388bc2432a8384
Author:     Oleg Nesterov <[email protected]>
AuthorDate: Sun, 10 Jul 2011 18:44:24 +0200
Committer:  H. Peter Anvin <[email protected]>
CommitDate: Thu, 14 Jul 2011 21:46:20 -0700

x86: Kill handle_signal()->set_fs()

handle_signal()->set_fs() has a nice comment which explains what set_fs() is, but it doesn't explain why it is needed and why it depends on CONFIG_X86_64.

Afaics, the history of this confusion is:

1. I guess today nobody can explain why it was needed in arch/i386/kernel/signal.c, perhaps it was always wrong. This predates 2.4.0 kernel.

2. then it was copy-and-past'ed to the new x86_64 arch.

3. then it was removed from i386 (but not from x86_64) by b93b6ca3 "i386: remove unnecessary code".

4. then it was reintroduced under CONFIG_X86_64 when x86 unified i386 and x86_64, because the patch above didn't touch x86_64.

Remove it. ->addr_limit should be correct. Even if it was possible that it is wrong, it is too late to fix it after setup_rt_frame().

Linus commented in:
http://lkml.kernel.org/r/[email protected]

... about the equivalent bit from i386:

Heh. I think it's entirely historical.

Please realize that the whole reason that function is called "set_fs()" is that it literally used to set the %fs segment register, not "->addr_limit".

So I think the "set_fs(USER_DS)" is there _only_ to match the other

        regs->xds = __USER_DS;
        regs->xes = __USER_DS;
        regs->xss = __USER_DS;
        regs->xcs = __USER_CS;

things, and never mattered. And now it matters even less, and has been copied to all other architectures where it is just totally insane.

---
 arch/x86/kernel/signal.c |    9 ---------
 1 files changed, 0 insertions(+), 9 deletions(-)
arch/x86/kernel/signal.c +0 -9
index 8c55f97..54ddaeb2 100644
@@ -720,15 +720,6 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
 	if (ret)
 		return ret;
 
-#ifdef CONFIG_X86_64
-	/*
-	 * This has nothing to do with segment registers,
-	 * despite the name.  This magic affects uaccess.h
-	 * macros' behavior.  Reset it to the normal setting.
-	 */
-	set_fs(USER_DS);
-#endif
-
 	/*
 	 * Clear the direction flag as per the ABI for function entry.
 	 */