Done already :)
Btw. it's not a question of laudability. It's a question of
correctness.
Writing a piece of code, which has a thinko in the first place, is not
correct, but we are all humans and miss a detail from time to time.
What you did is far more than incorrect:
You discovered the bug, you did not point it out upfront and you hid
an alleged fix in a bunch of changes, which happen to be around the
same area. And at the very end you ignore my objections against your
buggy fix by handwaving about your init_memory_mapping() cleanups.
To fix the try_preserve_large_page() problem a range check is not
necessary at all. A range check, if done right, might optimize it.
For the proposed cleanup of init_memory_mapping() I tend to agree,
that a range check might be useful.
I can see the requirement for a range check for the kind of cleanup
you want to do and it's fine with me to modify static_protections() in
a way which allows us to do range checks and share that code.
It just needs to be correct, while your so called fix is not even
close to correct.
To verify the incorrectness, lets apply the first two patches:
[PATCH] [1/5] CPA: Split static_protections into required_static_prot and advised_static_prot
[PATCH] [2/5] Support range checking for required/advisory protections
we get:
static inline int
within_range(unsigned long addr_start, unsigned long addr_end,
unsigned long start, unsigned long end)
{
return addr_end >= start && addr_start < end;
}
advised_static_prot(pgprot_t prot, unsigned long start, unsigned long end)
{
if (within_range(start, end, (unsigned long)__start_rodata,
(unsigned long)__end_rodata)
pgprot_val(forbidden) |= _PAGE_RW;
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
return prot;
}
Called with:
prot = advised_static_prot(prot | _PAGE_RW,
(unsigned long)__start_rodata - PAGE_SIZE,
(unsigned long)__end_rodata + PAGE_SIZE - 1);
ends up with the check for:
(__end_rodata + PAGE_SIZE - 1) >= __start_rodata &&
(__start_rodata - PAGE_SIZE) < __end_rodata
Which evaluates to true. So we write protect one page before the RO
section and one page after the RO section.
How does this fix the incorrectness exactly ?
The next patch
[PATCH] [3/5] CPA: Make advised protection check truly advisory
morphes advised_static_prot() into:
advised_static_prot(pgprot_t prot, unsigned long start, unsigned long end)
{
if (within_range((unsigned long)__start_rodata,
(unsigned long)__end_rodata,
start, end))
pgprot_val(forbidden) |= _PAGE_RW;
prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden));
return prot;
}
Called with:
prot = advised_static_prot(prot | _PAGE_RW,
(unsigned long)__start_rodata - PAGE_SIZE,
(unsigned long)__end_rodata + PAGE_SIZE - 1);
This results in:
__end_rodata >= (__start_rodata - PAGE_SIZE) &&
__start_rodata < (__end_rodata + PAGE_SIZE - 1)
which evaluates to true as well. So we still write protect one page
before the RO section and one page after the RO section. Probably not
what we want either, right ?
From the changelog:
"Only force RO in the advisory protection checks when all pages in the
range are RO. Previously it would trigger when any page in the range
was ro.
I believe this will make try_preserve_large_page much safer to use."
I had a reason to ask, whether you believe it or you are sure about
it. The changelog is so ludicrously detached from the code change,
that one needs to ask, whether you added it to the right patch.
The only change of this commit is:
(end_range >= start_test_range) && (start_range < end_test_range)
becomes
(end_test_range >= start_range) && (start_test_range < end_range)
which is the same as:
(end_range > start_test_range) && (start_range <= end_test_range)
So you just moved the "or equal" check to the other side, which does
not really change the behaviour of your code significantly, except for
one off corner cases.
Also the correctness of the order of arguments to within_range(), which is
btw. a horrible misleading function name, should have been clear in
the first place, when introducing it and converting the exisiting code
to use it.
Are you still convinced, that it would be a good idea to apply your
patches as a foundation for a fix, which takes 5 lines of code to be
correct ?
Thanks,
tglx
--