diff mbox

[v7,8/9] ARM: vdso initialization, mapping, and synchronization

Message ID 20140702144050.GD24879@arm.com
State Superseded
Headers show

Commit Message

Will Deacon July 2, 2014, 2:40 p.m. UTC
Hi Andy,

On Tue, Jul 01, 2014 at 03:17:23PM +0100, Andy Lutomirski wrote:
> On Tue, Jul 1, 2014 at 7:15 AM, Will Deacon <will.deacon@arm.com> wrote:
> > On Tue, Jul 01, 2014 at 03:11:04PM +0100, Nathan Lynch wrote:
> >> I believe Andy is suggesting separate VMAs (with different VM flags) for
> >> the VDSO's data and code.  So, breakpoints in code would work, but
> >> attempts to modify the data page via ptrace() would fail outright
> >> instead of silently COWing.
> >
> > Ah, yes. That makes a lot of sense for the data page -- we should do
> > something similar on arm64 too, since the CoW will break everything for the
> > task being debugged. We could also drop the EXEC flags too.
> 
> If you do this, I have a slight preference for the new vma being
> called "[vvar]" to match x86.  It'll make the CRIU people happy if and
> when they port it to ARM.

I quickly hacked something (see below) and now I see the following in
/proc/$$/maps:

7fa1574000-7fa1575000 r-xp 00000000 00:00 0                              [vdso]
7fa1575000-7fa1576000 r--p 00000000 00:00 0                              [vvar]

Is that what you're after?

Will

--->8

Comments

Andy Lutomirski July 2, 2014, 3:54 p.m. UTC | #1
On Wed, Jul 2, 2014 at 7:40 AM, Will Deacon <will.deacon@arm.com> wrote:
> Hi Andy,
>
> On Tue, Jul 01, 2014 at 03:17:23PM +0100, Andy Lutomirski wrote:
>> On Tue, Jul 1, 2014 at 7:15 AM, Will Deacon <will.deacon@arm.com> wrote:
>> > On Tue, Jul 01, 2014 at 03:11:04PM +0100, Nathan Lynch wrote:
>> >> I believe Andy is suggesting separate VMAs (with different VM flags) for
>> >> the VDSO's data and code.  So, breakpoints in code would work, but
>> >> attempts to modify the data page via ptrace() would fail outright
>> >> instead of silently COWing.
>> >
>> > Ah, yes. That makes a lot of sense for the data page -- we should do
>> > something similar on arm64 too, since the CoW will break everything for the
>> > task being debugged. We could also drop the EXEC flags too.
>>
>> If you do this, I have a slight preference for the new vma being
>> called "[vvar]" to match x86.  It'll make the CRIU people happy if and
>> when they port it to ARM.
>
> I quickly hacked something (see below) and now I see the following in
> /proc/$$/maps:
>
> 7fa1574000-7fa1575000 r-xp 00000000 00:00 0                              [vdso]
> 7fa1575000-7fa1576000 r--p 00000000 00:00 0                              [vvar]
>
> Is that what you're after?

Yes, with caveats.

Caveat 1: (minor) if you use _install_special_mapping, then you'll fix
an mremap bug and most of arch_vma_name can go away.

Caveat 2: (major) I'm kind of surprised that this, or the current
code, works reliably.  You're doing something that I tried briefly for
x86_64:

        _end = .;
        PROVIDE(end = .);

        . = ALIGN(PAGE_SIZE);
        PROVIDE(_vdso_data = .);

This sounds great, except that you're assuming that vdso_end -
vdso_start == ALIGN(_end, PAGE_SIZE) - (vdso base address).

If you *fully* strip the vdso (eu-strip --strip-sections), then this
is true: eu-strip --strip-sections outputs just the PT_LOAD piece of
the vdso.  But any binutils-generated incompletely stripped ELF image
contains a section table and possible non-allocatable sections at the
end.  If these exceed the amount of unused space in the last PT_LOAD
page, then they'll spill into the next page, and _vdso_data in the
vdso will no longer match the address at which vdso.c loads it.  Boom!

I bet you're getting away with this because the whole arm64 vdso seems
to be written in assembly, so it seems extremely unlikely to exceed
one page minus a few hundred bytes.  But if you start adding
complexity, you might get unlucky.

The x86_32 solution in v3.15 was to simply reverse the order: stick
the data page before the vdso instead of after it.  This seems to work
fine.

The x86 (all variants) solution in v3.16-rc1 was to fully strip the
vdso.  This broke gdb (and Go, but you won't have that particular
problem on ARM).  In v3.16-rc3, we're using a hack that moves the
section table into an actual allocated section -- this works, and if
the kernel builds then it's guaranteed to work, but I'm now fighting
with weird output from various binutils versions, and at least one
version of binutils can't build 3.16-rc3 for x86_64.

Anyway, all solutions are messy, but the arm64 one has the particular
disadvantage of failing silently.  I think I just got lucky on x86_64
in that I happened to trigger the failure myself before I ever sent
out the patches.

--Andy
Nathan Lynch July 2, 2014, 4:18 p.m. UTC | #2
On 07/02/2014 10:54 AM, Andy Lutomirski wrote:
> Caveat 2: (major) I'm kind of surprised that this, or the current
> code, works reliably.  You're doing something that I tried briefly for
> x86_64:
> 
>         _end = .;
>         PROVIDE(end = .);
> 
>         . = ALIGN(PAGE_SIZE);
>         PROVIDE(_vdso_data = .);
> 
> This sounds great, except that you're assuming that vdso_end -
> vdso_start == ALIGN(_end, PAGE_SIZE) - (vdso base address).
> 
> If you *fully* strip the vdso (eu-strip --strip-sections), then this
> is true: eu-strip --strip-sections outputs just the PT_LOAD piece of
> the vdso.  But any binutils-generated incompletely stripped ELF image
> contains a section table and possible non-allocatable sections at the
> end.  If these exceed the amount of unused space in the last PT_LOAD
> page, then they'll spill into the next page, and _vdso_data in the
> vdso will no longer match the address at which vdso.c loads it.  Boom!
> 
> I bet you're getting away with this because the whole arm64 vdso seems
> to be written in assembly, so it seems extremely unlikely to exceed
> one page minus a few hundred bytes.  But if you start adding
> complexity, you might get unlucky.

This is why I switched (in v5) the proposed 32-bit ARM VDSO to place the
data page before the code -- adding -frecord-gcc-switches to the
compiler flags was enough to break it.

I meant to call Will's attention to it at the time for arm64's sake, but
I guess it slipped my mind... sorry.
Will Deacon July 2, 2014, 4:27 p.m. UTC | #3
On Wed, Jul 02, 2014 at 05:18:59PM +0100, Nathan Lynch wrote:
> On 07/02/2014 10:54 AM, Andy Lutomirski wrote:
> > Caveat 2: (major) I'm kind of surprised that this, or the current
> > code, works reliably.  You're doing something that I tried briefly for
> > x86_64:
> > 
> >         _end = .;
> >         PROVIDE(end = .);
> > 
> >         . = ALIGN(PAGE_SIZE);
> >         PROVIDE(_vdso_data = .);
> > 
> > This sounds great, except that you're assuming that vdso_end -
> > vdso_start == ALIGN(_end, PAGE_SIZE) - (vdso base address).
> > 
> > If you *fully* strip the vdso (eu-strip --strip-sections), then this
> > is true: eu-strip --strip-sections outputs just the PT_LOAD piece of
> > the vdso.  But any binutils-generated incompletely stripped ELF image
> > contains a section table and possible non-allocatable sections at the
> > end.  If these exceed the amount of unused space in the last PT_LOAD
> > page, then they'll spill into the next page, and _vdso_data in the
> > vdso will no longer match the address at which vdso.c loads it.  Boom!
> > 
> > I bet you're getting away with this because the whole arm64 vdso seems
> > to be written in assembly, so it seems extremely unlikely to exceed
> > one page minus a few hundred bytes.  But if you start adding
> > complexity, you might get unlucky.
> 
> This is why I switched (in v5) the proposed 32-bit ARM VDSO to place the
> data page before the code -- adding -frecord-gcc-switches to the
> compiler flags was enough to break it.
> 
> I meant to call Will's attention to it at the time for arm64's sake, but
> I guess it slipped my mind... sorry.

Hmm, so I could definitely look at doing the same thing, but I don't know if
we actually need to for arm64. As Andy points out, we're written entirely in
assembly and we objcopy -S to create the vdso.so. I've dumped the headers
below and everything appears to be PT_LOAD.

Will

--->8

arch/arm64/kernel/vdso/vdso.so:     file format elf64-littleaarch64
arch/arm64/kernel/vdso/vdso.so
architecture: aarch64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x00000000000002d0

Program Header:
    LOAD off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**4
         filesz 0x00000000000006e8 memsz 0x00000000000006e8 flags r-x
 DYNAMIC off    0x00000000000005d8 vaddr 0x00000000000005d8 paddr 0x00000000000005d8 align 2**3
         filesz 0x00000000000000f0 memsz 0x00000000000000f0 flags r--
    NOTE off    0x00000000000002b8 vaddr 0x00000000000002b8 paddr 0x00000000000002b8 align 2**2
         filesz 0x0000000000000018 memsz 0x0000000000000018 flags r--
EH_FRAME off    0x00000000000004f0 vaddr 0x00000000000004f0 paddr 0x00000000000004f0 align 2**2
         filesz 0x0000000000000034 memsz 0x0000000000000034 flags r--

Dynamic Section:
  SONAME               linux-vdso.so.1
  HASH                 0x0000000000000120
  STRTAB               0x00000000000001f8
  SYMTAB               0x0000000000000150
  STRSZ                0x0000000000000077
  SYMENT               0x0000000000000018
  VERDEF               0x0000000000000280
  VERDEFNUM            0x0000000000000002
  VERSYM               0x0000000000000270

Version definitions:
1 0x01 0x0deebfa1 linux-vdso.so.1
2 0x00 0x075fcb89 LINUX_2.6.39
private flags = 0:

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .hash         00000030  0000000000000120  0000000000000120  00000120  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .dynsym       000000a8  0000000000000150  0000000000000150  00000150  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .dynstr       00000077  00000000000001f8  00000000000001f8  000001f8  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .gnu.version  0000000e  0000000000000270  0000000000000270  00000270  2**1
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .gnu.version_d 00000038  0000000000000280  0000000000000280  00000280  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .note         00000018  00000000000002b8  00000000000002b8  000002b8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA, LINK_ONCE_SAME_CONTENTS
  6 .text         00000220  00000000000002d0  00000000000002d0  000002d0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  7 .eh_frame_hdr 00000034  00000000000004f0  00000000000004f0  000004f0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  8 .eh_frame     000000b0  0000000000000528  0000000000000528  00000528  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  9 .dynamic      000000f0  00000000000005d8  00000000000005d8  000005d8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 10 .got          00000008  00000000000006c8  00000000000006c8  000006c8  2**3
                  CONTENTS, ALLOC, LOAD, DATA
 11 .got.plt      00000018  00000000000006d0  00000000000006d0  000006d0  2**3
                  CONTENTS, ALLOC, LOAD, DATA
SYMBOL TABLE:
no symbols
Andy Lutomirski July 2, 2014, 4:47 p.m. UTC | #4
On Wed, Jul 2, 2014 at 9:27 AM, Will Deacon <will.deacon@arm.com> wrote:
> On Wed, Jul 02, 2014 at 05:18:59PM +0100, Nathan Lynch wrote:
>> On 07/02/2014 10:54 AM, Andy Lutomirski wrote:
>> > Caveat 2: (major) I'm kind of surprised that this, or the current
>> > code, works reliably.  You're doing something that I tried briefly for
>> > x86_64:
>> >
>> >         _end = .;
>> >         PROVIDE(end = .);
>> >
>> >         . = ALIGN(PAGE_SIZE);
>> >         PROVIDE(_vdso_data = .);
>> >
>> > This sounds great, except that you're assuming that vdso_end -
>> > vdso_start == ALIGN(_end, PAGE_SIZE) - (vdso base address).
>> >
>> > If you *fully* strip the vdso (eu-strip --strip-sections), then this
>> > is true: eu-strip --strip-sections outputs just the PT_LOAD piece of
>> > the vdso.  But any binutils-generated incompletely stripped ELF image
>> > contains a section table and possible non-allocatable sections at the
>> > end.  If these exceed the amount of unused space in the last PT_LOAD
>> > page, then they'll spill into the next page, and _vdso_data in the
>> > vdso will no longer match the address at which vdso.c loads it.  Boom!
>> >
>> > I bet you're getting away with this because the whole arm64 vdso seems
>> > to be written in assembly, so it seems extremely unlikely to exceed
>> > one page minus a few hundred bytes.  But if you start adding
>> > complexity, you might get unlucky.
>>
>> This is why I switched (in v5) the proposed 32-bit ARM VDSO to place the
>> data page before the code -- adding -frecord-gcc-switches to the
>> compiler flags was enough to break it.
>>
>> I meant to call Will's attention to it at the time for arm64's sake, but
>> I guess it slipped my mind... sorry.
>
> Hmm, so I could definitely look at doing the same thing, but I don't know if
> we actually need to for arm64. As Andy points out, we're written entirely in
> assembly and we objcopy -S to create the vdso.so. I've dumped the headers
> below and everything appears to be PT_LOAD.

Your dump doesn't show the location of the section and section string
tables themselves.  Try:

eu-readelf -l -h -S whatever.so

--Andy
Will Deacon July 2, 2014, 5:24 p.m. UTC | #5
On Wed, Jul 02, 2014 at 05:47:08PM +0100, Andy Lutomirski wrote:
> On Wed, Jul 2, 2014 at 9:27 AM, Will Deacon <will.deacon@arm.com> wrote:
> > On Wed, Jul 02, 2014 at 05:18:59PM +0100, Nathan Lynch wrote:
> >> On 07/02/2014 10:54 AM, Andy Lutomirski wrote:
> >> > Caveat 2: (major) I'm kind of surprised that this, or the current
> >> > code, works reliably.  You're doing something that I tried briefly for
> >> > x86_64:
> >> >
> >> >         _end = .;
> >> >         PROVIDE(end = .);
> >> >
> >> >         . = ALIGN(PAGE_SIZE);
> >> >         PROVIDE(_vdso_data = .);
> >> >
> >> > This sounds great, except that you're assuming that vdso_end -
> >> > vdso_start == ALIGN(_end, PAGE_SIZE) - (vdso base address).
> >> >
> >> > If you *fully* strip the vdso (eu-strip --strip-sections), then this
> >> > is true: eu-strip --strip-sections outputs just the PT_LOAD piece of
> >> > the vdso.  But any binutils-generated incompletely stripped ELF image
> >> > contains a section table and possible non-allocatable sections at the
> >> > end.  If these exceed the amount of unused space in the last PT_LOAD
> >> > page, then they'll spill into the next page, and _vdso_data in the
> >> > vdso will no longer match the address at which vdso.c loads it.  Boom!
> >> >
> >> > I bet you're getting away with this because the whole arm64 vdso seems
> >> > to be written in assembly, so it seems extremely unlikely to exceed
> >> > one page minus a few hundred bytes.  But if you start adding
> >> > complexity, you might get unlucky.
> >>
> >> This is why I switched (in v5) the proposed 32-bit ARM VDSO to place the
> >> data page before the code -- adding -frecord-gcc-switches to the
> >> compiler flags was enough to break it.
> >>
> >> I meant to call Will's attention to it at the time for arm64's sake, but
> >> I guess it slipped my mind... sorry.
> >
> > Hmm, so I could definitely look at doing the same thing, but I don't know if
> > we actually need to for arm64. As Andy points out, we're written entirely in
> > assembly and we objcopy -S to create the vdso.so. I've dumped the headers
> > below and everything appears to be PT_LOAD.
> 
> Your dump doesn't show the location of the section and section string
> tables themselves.  Try:
> 
> eu-readelf -l -h -S whatever.so

Thanks. See below.

Will

--->8

ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           AArch64
  Version:                           0x1
  Entry point address:               0x2d0
  Start of program headers:          64 (bytes into file)
  Start of section headers:          1888 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         4
  Size of section headers:           64 (bytes)
  Number of section headers:         14
  Section header string table index: 13

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .hash             HASH             0000000000000120  00000120
       0000000000000030  0000000000000004   A       2     0     8
  [ 2] .dynsym           DYNSYM           0000000000000150  00000150
       00000000000000a8  0000000000000018   A       3     2     8
  [ 3] .dynstr           STRTAB           00000000000001f8  000001f8
       0000000000000077  0000000000000000   A       0     0     1
  [ 4] .gnu.version      VERSYM           0000000000000270  00000270
       000000000000000e  0000000000000002   A       2     0     2
  [ 5] .gnu.version_d    VERDEF           0000000000000280  00000280
       0000000000000038  0000000000000000   A       3     2     8
  [ 6] .note             NOTE             00000000000002b8  000002b8
       0000000000000018  0000000000000000   A       0     0     4
  [ 7] .text             PROGBITS         00000000000002d0  000002d0
       0000000000000220  0000000000000000  AX       0     0     16
  [ 8] .eh_frame_hdr     PROGBITS         00000000000004f0  000004f0
       0000000000000034  0000000000000000   A       0     0     4
  [ 9] .eh_frame         PROGBITS         0000000000000528  00000528
       00000000000000b0  0000000000000000   A       0     0     8
  [10] .dynamic          DYNAMIC          00000000000005d8  000005d8
       00000000000000f0  0000000000000010  WA       3     0     8
  [11] .got              PROGBITS         00000000000006c8  000006c8
       0000000000000008  0000000000000008  WA       0     0     8
  [12] .got.plt          PROGBITS         00000000000006d0  000006d0
       0000000000000018  0000000000000008  WA       0     0     8
  [13] .shstrtab         STRTAB           0000000000000000  000006e8
       0000000000000078  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000006e8 0x00000000000006e8  R E    10
  DYNAMIC        0x00000000000005d8 0x00000000000005d8 0x00000000000005d8
                 0x00000000000000f0 0x00000000000000f0  R      8
  NOTE           0x00000000000002b8 0x00000000000002b8 0x00000000000002b8
                 0x0000000000000018 0x0000000000000018  R      4
  GNU_EH_FRAME   0x00000000000004f0 0x00000000000004f0 0x00000000000004f0
                 0x0000000000000034 0x0000000000000034  R      4

 Section to Segment mapping:
  Segment Sections...
   00     .hash .dynsym .dynstr .gnu.version .gnu.version_d .note .text .eh_frame_hdr .eh_frame .dynamic .got .got.plt 
   01     .dynamic 
   02     .note 
   03     .eh_frame_hdr
Andy Lutomirski July 2, 2014, 6:34 p.m. UTC | #6
On Wed, Jul 2, 2014 at 10:24 AM, Will Deacon <will.deacon@arm.com> wrote:
> On Wed, Jul 02, 2014 at 05:47:08PM +0100, Andy Lutomirski wrote:
>> On Wed, Jul 2, 2014 at 9:27 AM, Will Deacon <will.deacon@arm.com> wrote:
>> > On Wed, Jul 02, 2014 at 05:18:59PM +0100, Nathan Lynch wrote:
>> >> On 07/02/2014 10:54 AM, Andy Lutomirski wrote:
>> >
>> > Hmm, so I could definitely look at doing the same thing, but I don't know if
>> > we actually need to for arm64. As Andy points out, we're written entirely in
>> > assembly and we objcopy -S to create the vdso.so. I've dumped the headers
>> > below and everything appears to be PT_LOAD.
>>
>> Your dump doesn't show the location of the section and section string
>> tables themselves.  Try:
>>
>> eu-readelf -l -h -S whatever.so
>
> Thanks. See below.
>
> Will
>
> --->8
>
> ELF Header:
>   Start of section headers:          1888 (bytes into file)
>   Size of section headers:           64 (bytes)
>   Number of section headers:         14

That's 896 bytes for the section table, starting at offset 1888.

>   Section header string table index: 13


>
> Section Headers:
>   [13] .shstrtab         STRTAB           0000000000000000  000006e8
>        0000000000000078  0000000000000000           0     0     1

120 bytes of section headers strings, starting at offset 1768 (and not
allocatable -- no 'A' here).

>
> Program Headers:
>   Type           Offset             VirtAddr           PhysAddr
>                  FileSiz            MemSiz              Flags  Align
>   LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
>                  0x00000000000006e8 0x00000000000006e8  R E    10

The loadable segment is 1768 bytes long, starting at the beginning of
the file (and therefore the beginning of the mapping).

So you have a total of 1016 bytes of non-allocatable stuff at the end
that I've accounted for.  I assume that the whole file is 2784 bytes.

If you added text or data to bring PT_LOAD to between 3081 and 4095
bytes, then the section headers and/or section string table would
cross a page boundary.

--Andy
Will Deacon July 2, 2014, 6:54 p.m. UTC | #7
Cheers for this, Andy.

On Wed, Jul 02, 2014 at 07:34:22PM +0100, Andy Lutomirski wrote:
> On Wed, Jul 2, 2014 at 10:24 AM, Will Deacon <will.deacon@arm.com> wrote:
> > ELF Header:
> >   Start of section headers:          1888 (bytes into file)
> >   Size of section headers:           64 (bytes)
> >   Number of section headers:         14
> 
> That's 896 bytes for the section table, starting at offset 1888.
> 
> >   Section header string table index: 13
> 
> 
> >
> > Section Headers:
> >   [13] .shstrtab         STRTAB           0000000000000000  000006e8
> >        0000000000000078  0000000000000000           0     0     1
> 
> 120 bytes of section headers strings, starting at offset 1768 (and not
> allocatable -- no 'A' here).
> 
> >
> > Program Headers:
> >   Type           Offset             VirtAddr           PhysAddr
> >                  FileSiz            MemSiz              Flags  Align
> >   LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
> >                  0x00000000000006e8 0x00000000000006e8  R E    10
> 
> The loadable segment is 1768 bytes long, starting at the beginning of
> the file (and therefore the beginning of the mapping).
> 
> So you have a total of 1016 bytes of non-allocatable stuff at the end
> that I've accounted for.  I assume that the whole file is 2784 bytes.

Correct.

> If you added text or data to bring PT_LOAD to between 3081 and 4095
> bytes, then the section headers and/or section string table would
> cross a page boundary.

Ok, so that explains why things are working at the moment and it sounds like
we have some wiggle room too. I'll look at moving the datapage anyway, since
having these artificial limits is error-prone and fragile, but I don't think
it's something we need to panic about immediately.

Also, if you get to the bottom of your binutils issues with the section
allocation, that might work for us since we don't really have any legacy
binutils supporting arm64.

Will
Andy Lutomirski July 22, 2014, 12:14 a.m. UTC | #8
On Wed, Jul 2, 2014 at 11:54 AM, Will Deacon <will.deacon@arm.com> wrote:
> Cheers for this, Andy.
>
> On Wed, Jul 02, 2014 at 07:34:22PM +0100, Andy Lutomirski wrote:
>> On Wed, Jul 2, 2014 at 10:24 AM, Will Deacon <will.deacon@arm.com> wrote:
>> > ELF Header:
>> >   Start of section headers:          1888 (bytes into file)
>> >   Size of section headers:           64 (bytes)
>> >   Number of section headers:         14
>>
>> That's 896 bytes for the section table, starting at offset 1888.
>>
>> >   Section header string table index: 13
>>
>>
>> >
>> > Section Headers:
>> >   [13] .shstrtab         STRTAB           0000000000000000  000006e8
>> >        0000000000000078  0000000000000000           0     0     1
>>
>> 120 bytes of section headers strings, starting at offset 1768 (and not
>> allocatable -- no 'A' here).
>>
>> >
>> > Program Headers:
>> >   Type           Offset             VirtAddr           PhysAddr
>> >                  FileSiz            MemSiz              Flags  Align
>> >   LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
>> >                  0x00000000000006e8 0x00000000000006e8  R E    10
>>
>> The loadable segment is 1768 bytes long, starting at the beginning of
>> the file (and therefore the beginning of the mapping).
>>
>> So you have a total of 1016 bytes of non-allocatable stuff at the end
>> that I've accounted for.  I assume that the whole file is 2784 bytes.
>
> Correct.
>
>> If you added text or data to bring PT_LOAD to between 3081 and 4095
>> bytes, then the section headers and/or section string table would
>> cross a page boundary.
>
> Ok, so that explains why things are working at the moment and it sounds like
> we have some wiggle room too. I'll look at moving the datapage anyway, since
> having these artificial limits is error-prone and fragile, but I don't think
> it's something we need to panic about immediately.
>
> Also, if you get to the bottom of your binutils issues with the section
> allocation, that might work for us since we don't really have any legacy
> binutils supporting arm64.

Just in case anyone still cares about this thread, moving the vvar
area back before the vdso text is queued up for 3.17.  I gave up on
reliably keeping binutils happy with my ugly hack.

--Andy
Will Deacon July 22, 2014, 8:13 a.m. UTC | #9
On Tue, Jul 22, 2014 at 01:14:35AM +0100, Andy Lutomirski wrote:
> On Wed, Jul 2, 2014 at 11:54 AM, Will Deacon <will.deacon@arm.com> wrote:
> > Ok, so that explains why things are working at the moment and it sounds like
> > we have some wiggle room too. I'll look at moving the datapage anyway, since
> > having these artificial limits is error-prone and fragile, but I don't think
> > it's something we need to panic about immediately.
> >
> > Also, if you get to the bottom of your binutils issues with the section
> > allocation, that might work for us since we don't really have any legacy
> > binutils supporting arm64.
> 
> Just in case anyone still cares about this thread, moving the vvar
> area back before the vdso text is queued up for 3.17.  I gave up on
> reliably keeping binutils happy with my ugly hack.

The same change is also queued for arm64.

Thanks Andy,

Will
diff mbox

Patch

diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 50384fec56c4..84cafbc3eb54 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -138,11 +138,12 @@  int arch_setup_additional_pages(struct linux_binprm *bprm,
 				int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
-	unsigned long vdso_base, vdso_mapping_len;
+	unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
 	int ret;
 
+	vdso_text_len = vdso_pages << PAGE_SHIFT;
 	/* Be sure to map the data page */
-	vdso_mapping_len = (vdso_pages + 1) << PAGE_SHIFT;
+	vdso_mapping_len = vdso_text_len + PAGE_SIZE;
 
 	down_write(&mm->mmap_sem);
 	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
@@ -152,35 +153,52 @@  int arch_setup_additional_pages(struct linux_binprm *bprm,
 	}
 	mm->context.vdso = (void *)vdso_base;
 
-	ret = install_special_mapping(mm, vdso_base, vdso_mapping_len,
+	ret = install_special_mapping(mm, vdso_base, vdso_text_len,
 				      VM_READ|VM_EXEC|
 				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 				      vdso_pagelist);
-	if (ret) {
-		mm->context.vdso = NULL;
+	if (ret)
+		goto up_fail;
+
+	vdso_base += vdso_text_len;
+	ret = install_special_mapping(mm, vdso_base, PAGE_SIZE,
+				      VM_READ|VM_MAYREAD,
+				      vdso_pagelist + vdso_pages);
+	if (ret)
 		goto up_fail;
-	}
 
-up_fail:
 	up_write(&mm->mmap_sem);
+	return 0;
 
+up_fail:
+	mm->context.vdso = NULL;
+	up_write(&mm->mmap_sem);
 	return ret;
 }
 
 const char *arch_vma_name(struct vm_area_struct *vma)
 {
+	unsigned long vdso_text;
+
+	if (!vma->vm_mm)
+		return NULL;
+
+	vdso_text = (unsigned long)vma->vm_mm->context.vdso;
+
 	/*
 	 * We can re-use the vdso pointer in mm_context_t for identifying
 	 * the vectors page for compat applications. The vDSO will always
 	 * sit above TASK_UNMAPPED_BASE and so we don't need to worry about
 	 * it conflicting with the vectors base.
 	 */
-	if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) {
+	if (vma->vm_start == vdso_text) {
 #ifdef CONFIG_COMPAT
 		if (vma->vm_start == AARCH32_VECTORS_BASE)
 			return "[vectors]";
 #endif
 		return "[vdso]";
+	} else if (vma->vm_start == (vdso_text + (vdso_pages << PAGE_SHIFT))) {
+		return "[vvar]";
 	}
 
 	return NULL;