Hi,
This patch adjusts capability relocations against two classes of symbols: - Symbols which point into sections which may be accessed via the PCC. - Symbols without size information.
For the latter, we emit a warning and adjust the capability relocation and fragment such that the resulting capability has bounds permitting access to the entire section. This matches the behaviour of LLD.
For the former, we adjust them as described in the following explanation.
The Morello ABI accesses global data using ADR and ADRP, and has no special indirection to jump to other functions. Given this, the PCC must maintain its bounds and base so that during execution loading global data and jumping to other functions can be done without worrying about the current PCC permissions and bounds.
To implement this, all capabilities that could be loaded into the PCC (via BLR or similar) must have a bounds and base according to the PCC. This must span all global data and text sections (i.e. .got, .text, .got.plt and the like). There is already code finding the range that the PCC should span, this patch records the information in a variable that we can query later.
There are two places where we create a relocation requesting a capability to be initialised at runtime. When handling relocations which request a capability from the GOT, and when handling a CAPINIT relocation. This patch adjusts both.
We can't tell from inspection which symbols would be loaded into the PCC, but we know that those symbols must point into a section which is executable. Hence we do this operation for all symbols which point into an executable section.
Most RELATIVE relocations don't use the addend. Rather the VA and size we want are put in the relative fragment and the addend is zero. This is because the *base* of the capability usually matches the VA we want that capability initialised to. In these possibly-code symbols we want the base of the capability bounds to be the base of the PCC, and the VA to be something very different. Hence we make use of the addend in the RELA relocations to encode this offset.
Note on implementation:
c64_fixup_frag takes the base and size of a capability we want to request from the runtime and checks that these are exactly representable in a capability. This patch changes many of the capabilities we request from the runtime to have the same bounds (those of the PCC). We leave the check to look at the bounds requested by the symbol rather than to check the PCC bounds multiple times. That means that if a symbol that points into an executable section has incorrect bounds then this will trigger a linker error even though it will cause no security problem when this executes. This is a trade-off between getting extra checks that the compiler is handling object bounds sizes and erroring on non-problematic code.
We have a compatibility hack that if a symbol is defined in the linker script to be directly after a given section but is *named* something like __.*_start or __start_.* then we treat it as if it is defined at the very start of the next section. The new behaviour introduced in this patch needs to take account of the above compatibility hack.
Hence we define a helper function to perform the relevent adjustment. It would be nice to also use the helper function so that it can be used in elfNN_c64_resize_sections, but that function will already need updating to account for the fact that zero-sized symbols found in the input will span entire sections. Hence we leave this function for then, since the manner in which we would use this helper function may change.
This patch also updates the entire testsuite according to these changes. In some places the original test no longer checks what it wanted, since the base of all symbols pointing into executable sections are now the same. There we add extra symbols and things to check so we ensure that this behaviour of PCC bounds is seen and that the original behaviour is still seen on non-executable sections.
This commit also includes a few tidy-ups:
We adjust the base and limit that are checked in c64_fixup_frag. Originally this would calculate the base as value + addend. As discussed above the way we treat capabilities in Morello is such that the value determines the base and the addend determines the initial value pointing from that base. Hence the check that these capabilities had correct bounds was not correct.
We add an extra assertion in final_link_relocate for robustness purposes. There is an existing bug in the assembler where GOT relocations against local symbols can be turned into relocations against the relevant section symbol plus an addend. This is problematic for multiple reasons, one being that the linker implementation does not have any way to associate different GOT entries with the same symbol but multiple offsets. In fact the linker ignores any offset. Here we simply add an assertion that this never happens. It turns a silent pre-existing error into a noisy one.
Regression tested on aarch64-none-elf, OK for users/ARM/morello-binutils-gdb-master?
Thanks, Alex
2022-01-21 Alex Coplan alex.coplan@arm.com Matthew Malcomson matthew.malcomson@arm.com
bfd/ChangeLog:
* elfnn-aarch64.c (pcc_low): New. (pcc_high): New. (elfNN_c64_resize_sections): Update new global variables pcc_{low,high} instead of local variables to track PCC span. (enum c64_section_perm_type): New. (c64_symbol_section_adjustment): New. (c64_fixup_frag): Rework to calculate size appropriately for symbols that need adjustment. (c64_symbol_adjust): New. Use it ... (elfNN_aarch64_final_link_relocate): ... here.
ld/ChangeLog:
* testsuite/ld-aarch64/aarch64-elf.exp: Add new tests. * testsuite/ld-aarch64/emit-relocs-morello-6.d: New test. * testsuite/ld-aarch64/emit-relocs-morello-6.s: Assembly. * testsuite/ld-aarch64/emit-relocs-morello-6b.d: New test. * testsuite/ld-aarch64/emit-relocs-morello-7.d: New test. * testsuite/ld-aarch64/emit-relocs-morello-7.ld: Linker script thereof. * testsuite/ld-aarch64/emit-relocs-morello-7.s: Assembly. * testsuite/ld-aarch64/morello-capinit.d: New test. * testsuite/ld-aarch64/morello-capinit.ld: Linker script. * testsuite/ld-aarch64/morello-capinit.s: Assembly. * testsuite/ld-aarch64/morello-sizeless-global-syms.d: New test. * testsuite/ld-aarch64/morello-sizeless-global-syms.s: Assembly. * testsuite/ld-aarch64/morello-sizeless-got-syms.d: New test. * testsuite/ld-aarch64/morello-sizeless-got-syms.s: Assembly. * testsuite/ld-aarch64/morello-sizeless-local-syms.d: New test. * testsuite/ld-aarch64/morello-sizeless-local-syms.s: Assembly.
OK for users/ARM/morello-binutils-gdb-master (Since I was on CC I got the patch 😉) ________________________________ From: Alex Coplan Alex.Coplan@arm.com Sent: 21 January 2022 14:22 To: gnu-morello@op-lists.linaro.org gnu-morello@op-lists.linaro.org Cc: Matthew Malcomson Matthew.Malcomson@arm.com; Kyrylo Tkachov Kyrylo.Tkachov@arm.com Subject: [PATCH] ld: Adjust bounds, base, and size for various symbols
Hi,
This patch adjusts capability relocations against two classes of symbols: - Symbols which point into sections which may be accessed via the PCC. - Symbols without size information.
For the latter, we emit a warning and adjust the capability relocation and fragment such that the resulting capability has bounds permitting access to the entire section. This matches the behaviour of LLD.
For the former, we adjust them as described in the following explanation.
The Morello ABI accesses global data using ADR and ADRP, and has no special indirection to jump to other functions. Given this, the PCC must maintain its bounds and base so that during execution loading global data and jumping to other functions can be done without worrying about the current PCC permissions and bounds.
To implement this, all capabilities that could be loaded into the PCC (via BLR or similar) must have a bounds and base according to the PCC. This must span all global data and text sections (i.e. .got, .text, .got.plt and the like). There is already code finding the range that the PCC should span, this patch records the information in a variable that we can query later.
There are two places where we create a relocation requesting a capability to be initialised at runtime. When handling relocations which request a capability from the GOT, and when handling a CAPINIT relocation. This patch adjusts both.
We can't tell from inspection which symbols would be loaded into the PCC, but we know that those symbols must point into a section which is executable. Hence we do this operation for all symbols which point into an executable section.
Most RELATIVE relocations don't use the addend. Rather the VA and size we want are put in the relative fragment and the addend is zero. This is because the *base* of the capability usually matches the VA we want that capability initialised to. In these possibly-code symbols we want the base of the capability bounds to be the base of the PCC, and the VA to be something very different. Hence we make use of the addend in the RELA relocations to encode this offset.
Note on implementation:
c64_fixup_frag takes the base and size of a capability we want to request from the runtime and checks that these are exactly representable in a capability. This patch changes many of the capabilities we request from the runtime to have the same bounds (those of the PCC). We leave the check to look at the bounds requested by the symbol rather than to check the PCC bounds multiple times. That means that if a symbol that points into an executable section has incorrect bounds then this will trigger a linker error even though it will cause no security problem when this executes. This is a trade-off between getting extra checks that the compiler is handling object bounds sizes and erroring on non-problematic code.
We have a compatibility hack that if a symbol is defined in the linker script to be directly after a given section but is *named* something like __.*_start or __start_.* then we treat it as if it is defined at the very start of the next section. The new behaviour introduced in this patch needs to take account of the above compatibility hack.
Hence we define a helper function to perform the relevent adjustment. It would be nice to also use the helper function so that it can be used in elfNN_c64_resize_sections, but that function will already need updating to account for the fact that zero-sized symbols found in the input will span entire sections. Hence we leave this function for then, since the manner in which we would use this helper function may change.
This patch also updates the entire testsuite according to these changes. In some places the original test no longer checks what it wanted, since the base of all symbols pointing into executable sections are now the same. There we add extra symbols and things to check so we ensure that this behaviour of PCC bounds is seen and that the original behaviour is still seen on non-executable sections.
This commit also includes a few tidy-ups:
We adjust the base and limit that are checked in c64_fixup_frag. Originally this would calculate the base as value + addend. As discussed above the way we treat capabilities in Morello is such that the value determines the base and the addend determines the initial value pointing from that base. Hence the check that these capabilities had correct bounds was not correct.
We add an extra assertion in final_link_relocate for robustness purposes. There is an existing bug in the assembler where GOT relocations against local symbols can be turned into relocations against the relevant section symbol plus an addend. This is problematic for multiple reasons, one being that the linker implementation does not have any way to associate different GOT entries with the same symbol but multiple offsets. In fact the linker ignores any offset. Here we simply add an assertion that this never happens. It turns a silent pre-existing error into a noisy one.
Regression tested on aarch64-none-elf, OK for users/ARM/morello-binutils-gdb-master?
Thanks, Alex
2022-01-21 Alex Coplan alex.coplan@arm.com Matthew Malcomson matthew.malcomson@arm.com
bfd/ChangeLog:
* elfnn-aarch64.c (pcc_low): New. (pcc_high): New. (elfNN_c64_resize_sections): Update new global variables pcc_{low,high} instead of local variables to track PCC span. (enum c64_section_perm_type): New. (c64_symbol_section_adjustment): New. (c64_fixup_frag): Rework to calculate size appropriately for symbols that need adjustment. (c64_symbol_adjust): New. Use it ... (elfNN_aarch64_final_link_relocate): ... here.
ld/ChangeLog:
* testsuite/ld-aarch64/aarch64-elf.exp: Add new tests. * testsuite/ld-aarch64/emit-relocs-morello-6.d: New test. * testsuite/ld-aarch64/emit-relocs-morello-6.s: Assembly. * testsuite/ld-aarch64/emit-relocs-morello-6b.d: New test. * testsuite/ld-aarch64/emit-relocs-morello-7.d: New test. * testsuite/ld-aarch64/emit-relocs-morello-7.ld: Linker script thereof. * testsuite/ld-aarch64/emit-relocs-morello-7.s: Assembly. * testsuite/ld-aarch64/morello-capinit.d: New test. * testsuite/ld-aarch64/morello-capinit.ld: Linker script. * testsuite/ld-aarch64/morello-capinit.s: Assembly. * testsuite/ld-aarch64/morello-sizeless-global-syms.d: New test. * testsuite/ld-aarch64/morello-sizeless-global-syms.s: Assembly. * testsuite/ld-aarch64/morello-sizeless-got-syms.d: New test. * testsuite/ld-aarch64/morello-sizeless-got-syms.s: Assembly. * testsuite/ld-aarch64/morello-sizeless-local-syms.d: New test. * testsuite/ld-aarch64/morello-sizeless-local-syms.s: Assembly.
On 21 Jan 2022, at 14:22, Alex Coplan via Gnu-morello gnu-morello@op-lists.linaro.org wrote:
Hi,
This patch adjusts capability relocations against two classes of symbols:
- Symbols which point into sections which may be accessed via the PCC.
- Symbols without size information.
For the latter, we emit a warning and adjust the capability relocation and fragment such that the resulting capability has bounds permitting access to the entire section. This matches the behaviour of LLD.
This does not match the behaviour of LLD. LLD will only change the size of zero-sized symbols if they have a name that looks like a section start symbol (see isSectionStartSymbol in lld/ELF/Arch/Cheri.h). All other symbols will be left as 0 size, with only some of the warning, again based on the name (section end symbols are expected to be 0 size, and section start symbols can be 0 size if the section is empty), whether it’s absolute and whether it’s undef weak. Changing the size of every symbol violates memory safety, because then:
int x[0];
and
struct { } y;
will give you a capability for the entire data section. That is bad.
I don’t see a patch attached so I cannot verify if you’ve actually implemented the LLD behaviour or what you incorrectly describe the LLD behaviour as here.
Jess
For the former, we adjust them as described in the following explanation.
The Morello ABI accesses global data using ADR and ADRP, and has no special indirection to jump to other functions. Given this, the PCC must maintain its bounds and base so that during execution loading global data and jumping to other functions can be done without worrying about the current PCC permissions and bounds.
To implement this, all capabilities that could be loaded into the PCC (via BLR or similar) must have a bounds and base according to the PCC. This must span all global data and text sections (i.e. .got, .text, .got.plt and the like). There is already code finding the range that the PCC should span, this patch records the information in a variable that we can query later.
There are two places where we create a relocation requesting a capability to be initialised at runtime. When handling relocations which request a capability from the GOT, and when handling a CAPINIT relocation. This patch adjusts both.
We can't tell from inspection which symbols would be loaded into the PCC, but we know that those symbols must point into a section which is executable. Hence we do this operation for all symbols which point into an executable section.
Most RELATIVE relocations don't use the addend. Rather the VA and size we want are put in the relative fragment and the addend is zero. This is because the *base* of the capability usually matches the VA we want that capability initialised to. In these possibly-code symbols we want the base of the capability bounds to be the base of the PCC, and the VA to be something very different. Hence we make use of the addend in the RELA relocations to encode this offset.
Note on implementation:
c64_fixup_frag takes the base and size of a capability we want to request from the runtime and checks that these are exactly representable in a capability. This patch changes many of the capabilities we request from the runtime to have the same bounds (those of the PCC). We leave the check to look at the bounds requested by the symbol rather than to check the PCC bounds multiple times. That means that if a symbol that points into an executable section has incorrect bounds then this will trigger a linker error even though it will cause no security problem when this executes. This is a trade-off between getting extra checks that the compiler is handling object bounds sizes and erroring on non-problematic code.
We have a compatibility hack that if a symbol is defined in the linker script to be directly after a given section but is *named* something like __.*_start or __start_.* then we treat it as if it is defined at the very start of the next section. The new behaviour introduced in this patch needs to take account of the above compatibility hack.
Hence we define a helper function to perform the relevent adjustment. It would be nice to also use the helper function so that it can be used in elfNN_c64_resize_sections, but that function will already need updating to account for the fact that zero-sized symbols found in the input will span entire sections. Hence we leave this function for then, since the manner in which we would use this helper function may change.
This patch also updates the entire testsuite according to these changes. In some places the original test no longer checks what it wanted, since the base of all symbols pointing into executable sections are now the same. There we add extra symbols and things to check so we ensure that this behaviour of PCC bounds is seen and that the original behaviour is still seen on non-executable sections.
This commit also includes a few tidy-ups:
We adjust the base and limit that are checked in c64_fixup_frag. Originally this would calculate the base as value + addend. As discussed above the way we treat capabilities in Morello is such that the value determines the base and the addend determines the initial value pointing from that base. Hence the check that these capabilities had correct bounds was not correct.
We add an extra assertion in final_link_relocate for robustness purposes. There is an existing bug in the assembler where GOT relocations against local symbols can be turned into relocations against the relevant section symbol plus an addend. This is problematic for multiple reasons, one being that the linker implementation does not have any way to associate different GOT entries with the same symbol but multiple offsets. In fact the linker ignores any offset. Here we simply add an assertion that this never happens. It turns a silent pre-existing error into a noisy one.
Regression tested on aarch64-none-elf, OK for users/ARM/morello-binutils-gdb-master?
Thanks, Alex
2022-01-21 Alex Coplan alex.coplan@arm.com Matthew Malcomson matthew.malcomson@arm.com
bfd/ChangeLog:
- elfnn-aarch64.c (pcc_low): New.
(pcc_high): New. (elfNN_c64_resize_sections): Update new global variables pcc_{low,high} instead of local variables to track PCC span. (enum c64_section_perm_type): New. (c64_symbol_section_adjustment): New. (c64_fixup_frag): Rework to calculate size appropriately for symbols that need adjustment. (c64_symbol_adjust): New. Use it ... (elfNN_aarch64_final_link_relocate): ... here.
ld/ChangeLog:
- testsuite/ld-aarch64/aarch64-elf.exp: Add new tests.
- testsuite/ld-aarch64/emit-relocs-morello-6.d: New test.
- testsuite/ld-aarch64/emit-relocs-morello-6.s: Assembly.
- testsuite/ld-aarch64/emit-relocs-morello-6b.d: New test.
- testsuite/ld-aarch64/emit-relocs-morello-7.d: New test.
- testsuite/ld-aarch64/emit-relocs-morello-7.ld: Linker script thereof.
- testsuite/ld-aarch64/emit-relocs-morello-7.s: Assembly.
- testsuite/ld-aarch64/morello-capinit.d: New test.
- testsuite/ld-aarch64/morello-capinit.ld: Linker script.
- testsuite/ld-aarch64/morello-capinit.s: Assembly.
- testsuite/ld-aarch64/morello-sizeless-global-syms.d: New test.
- testsuite/ld-aarch64/morello-sizeless-global-syms.s: Assembly.
- testsuite/ld-aarch64/morello-sizeless-got-syms.d: New test.
- testsuite/ld-aarch64/morello-sizeless-got-syms.s: Assembly.
- testsuite/ld-aarch64/morello-sizeless-local-syms.d: New test.
- testsuite/ld-aarch64/morello-sizeless-local-syms.s: Assembly.
-- Gnu-morello mailing list -- gnu-morello@op-lists.linaro.org To unsubscribe send an email to gnu-morello-leave@op-lists.linaro.org
gnu-morello@op-lists.linaro.org