mbox series

[v10,00/12] arm64: untag user pointers passed to the kernel

Message ID cover.1550839937.git.andreyknvl@google.com (mailing list archive)
Headers show
Series arm64: untag user pointers passed to the kernel | expand

Message

Andrey Konovalov Feb. 22, 2019, 12:53 p.m. UTC
This patchset is meant to be merged together with "arm64 relaxed ABI" [1].

arm64 has a feature called Top Byte Ignore, which allows to embed pointer
tags into the top byte of each pointer. Userspace programs (such as
HWASan, a memory debugging tool [2]) might use this feature and pass
tagged user pointers to the kernel through syscalls or other interfaces.

Right now the kernel is already able to handle user faults with tagged
pointers, due to these patches:

1. 81cddd65 ("arm64: traps: fix userspace cache maintenance emulation on a
             tagged pointer")
2. 7dcd9dd8 ("arm64: hw_breakpoint: fix watchpoint matching for tagged
	      pointers")
3. 276e9327 ("arm64: entry: improve data abort handling of tagged
	      pointers")

This patchset extends tagged pointer support to syscall arguments.

For non-memory syscalls this is done by untaging user pointers when the
kernel performs pointer checking to find out whether the pointer comes
from userspace (most notably in access_ok). The untagging is done only
when the pointer is being checked, the tag is preserved as the pointer
makes its way through the kernel.

Since memory syscalls (mmap, mprotect, etc.) don't do memory accesses but
rather deal with memory ranges, untagged pointers are better suited to
describe memory ranges internally. Thus for memory syscalls we untag
pointers completely when they enter the kernel.

One of the alternative approaches to untagging that was considered is to
completely strip the pointer tag as the pointer enters the kernel with
some kind of a syscall wrapper, but that won't work with the countless
number of different ioctl calls. With this approach we would need a custom
wrapper for each ioctl variation, which doesn't seem practical.

The following testing approaches has been taken to find potential issues
with user pointer untagging:

1. Static testing (with sparse [3] and separately with a custom static
   analyzer based on Clang) to track casts of __user pointers to integer
   types to find places where untagging needs to be done.

2. Static testing with grep to find parts of the kernel that call
   find_vma() (and other similar functions) or directly compare against
   vm_start/vm_end fields of vma.

3. Static testing with grep to find parts of the kernel that compare
   user pointers with TASK_SIZE or other similar consts and macros.

4. Dynamic testing: adding BUG_ON(has_tag(addr)) to find_vma() and running
   a modified syzkaller version that passes tagged pointers to the kernel.

Based on the results of the testing the requried patches have been added
to the patchset.

This patchset has been merged into the Pixel 2 kernel tree and is now
being used to enable testing of Pixel 2 phones with HWASan.

This patchset is a prerequisite for ARM's memory tagging hardware feature
support [4].

Thanks!

[1] https://lkml.org/lkml/2018/12/10/402

[2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html

[3] https://github.com/lucvoo/sparse-dev/commit/5f960cb10f56ec2017c128ef9d16060e0145f292

[4] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a

Changes in v10:
- Added "mm, arm64: untag user pointers passed to memory syscalls" back.
- New patch "fs, arm64: untag user pointers in fs/userfaultfd.c".
- New patch "net, arm64: untag user pointers in tcp_zerocopy_receive".
- New patch "kernel, arm64: untag user pointers in prctl_set_mm*".
- New patch "tracing, arm64: untag user pointers in seq_print_user_ip".

Changes in v9:
- Rebased onto 4.20-rc6.
- Used u64 instead of __u64 in type casts in the untagged_addr macro for
  arm64.
- Added braces around (addr) in the untagged_addr macro for other arches.

Changes in v8:
- Rebased onto 65102238 (4.20-rc1).
- Added a note to the cover letter on why syscall wrappers/shims that untag
  user pointers won't work.
- Added a note to the cover letter that this patchset has been merged into
  the Pixel 2 kernel tree.
- Documentation fixes, in particular added a list of syscalls that don't
  support tagged user pointers.

Changes in v7:
- Rebased onto 17b57b18 (4.19-rc6).
- Dropped the "arm64: untag user address in __do_user_fault" patch, since
  the existing patches already handle user faults properly.
- Dropped the "usb, arm64: untag user addresses in devio" patch, since the
  passed pointer must come from a vma and therefore be untagged.
- Dropped the "arm64: annotate user pointers casts detected by sparse"
  patch (see the discussion to the replies of the v6 of this patchset).
- Added more context to the cover letter.
- Updated Documentation/arm64/tagged-pointers.txt.

Changes in v6:
- Added annotations for user pointer casts found by sparse.
- Rebased onto 050cdc6c (4.19-rc1+).

Changes in v5:
- Added 3 new patches that add untagging to places found with static
  analysis.
- Rebased onto 44c929e1 (4.18-rc8).

Changes in v4:
- Added a selftest for checking that passing tagged pointers to the
  kernel succeeds.
- Rebased onto 81e97f013 (4.18-rc1+).

Changes in v3:
- Rebased onto e5c51f30 (4.17-rc6+).
- Added linux-arch@ to the list of recipients.

Changes in v2:
- Rebased onto 2d618bdf (4.17-rc3+).
- Removed excessive untagging in gup.c.
- Removed untagging pointers returned from __uaccess_mask_ptr.

Changes in v1:
- Rebased onto 4.17-rc1.

Changes in RFC v2:
- Added "#ifndef untagged_addr..." fallback in linux/uaccess.h instead of
  defining it for each arch individually.
- Updated Documentation/arm64/tagged-pointers.txt.
- Dropped "mm, arm64: untag user addresses in memory syscalls".
- Rebased onto 3eb2ce82 (4.16-rc7).

Reviewed-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Signed-off-by: Andrey Konovalov <andreyknvl@google.com>

Andrey Konovalov (12):
  uaccess: add untagged_addr definition for other arches
  arm64: untag user pointers in access_ok and __uaccess_mask_ptr
  lib, arm64: untag user pointers in strn*_user
  mm, arm64: untag user pointers passed to memory syscalls
  mm, arm64: untag user pointers in mm/gup.c
  fs, arm64: untag user pointers in copy_mount_options
  fs, arm64: untag user pointers in fs/userfaultfd.c
  net, arm64: untag user pointers in tcp_zerocopy_receive
  kernel, arm64: untag user pointers in prctl_set_mm*
  tracing, arm64: untag user pointers in seq_print_user_ip
  arm64: update Documentation/arm64/tagged-pointers.txt
  selftests, arm64: add a selftest for passing tagged pointers to kernel

 Documentation/arm64/tagged-pointers.txt       | 25 +++++++++++--------
 arch/arm64/include/asm/uaccess.h              | 10 +++++---
 fs/namespace.c                                |  2 +-
 fs/userfaultfd.c                              |  5 ++++
 include/linux/memory.h                        |  4 +++
 ipc/shm.c                                     |  2 ++
 kernel/sys.c                                  | 14 +++++++++++
 kernel/trace/trace_output.c                   |  2 +-
 lib/strncpy_from_user.c                       |  2 ++
 lib/strnlen_user.c                            |  2 ++
 mm/gup.c                                      |  4 +++
 mm/madvise.c                                  |  2 ++
 mm/mempolicy.c                                |  5 ++++
 mm/migrate.c                                  |  1 +
 mm/mincore.c                                  |  2 ++
 mm/mlock.c                                    |  5 ++++
 mm/mmap.c                                     |  7 ++++++
 mm/mprotect.c                                 |  2 ++
 mm/mremap.c                                   |  2 ++
 mm/msync.c                                    |  2 ++
 net/ipv4/tcp.c                                |  2 ++
 tools/testing/selftests/arm64/.gitignore      |  1 +
 tools/testing/selftests/arm64/Makefile        | 11 ++++++++
 .../testing/selftests/arm64/run_tags_test.sh  | 12 +++++++++
 tools/testing/selftests/arm64/tags_test.c     | 19 ++++++++++++++
 25 files changed, 129 insertions(+), 16 deletions(-)
 create mode 100644 tools/testing/selftests/arm64/.gitignore
 create mode 100644 tools/testing/selftests/arm64/Makefile
 create mode 100755 tools/testing/selftests/arm64/run_tags_test.sh
 create mode 100644 tools/testing/selftests/arm64/tags_test.c

Comments

Szabolcs Nagy Feb. 22, 2019, 3:35 p.m. UTC | #1
On 22/02/2019 12:53, Andrey Konovalov wrote:
> This patchset is meant to be merged together with "arm64 relaxed ABI" [1].
> 
> arm64 has a feature called Top Byte Ignore, which allows to embed pointer
> tags into the top byte of each pointer. Userspace programs (such as
> HWASan, a memory debugging tool [2]) might use this feature and pass
> tagged user pointers to the kernel through syscalls or other interfaces.
> 
> Right now the kernel is already able to handle user faults with tagged
> pointers, due to these patches:
> 
> 1. 81cddd65 ("arm64: traps: fix userspace cache maintenance emulation on a
>              tagged pointer")
> 2. 7dcd9dd8 ("arm64: hw_breakpoint: fix watchpoint matching for tagged
> 	      pointers")
> 3. 276e9327 ("arm64: entry: improve data abort handling of tagged
> 	      pointers")
> 
> This patchset extends tagged pointer support to syscall arguments.
> 
> For non-memory syscalls this is done by untaging user pointers when the
> kernel performs pointer checking to find out whether the pointer comes
> from userspace (most notably in access_ok). The untagging is done only
> when the pointer is being checked, the tag is preserved as the pointer
> makes its way through the kernel.
> 
> Since memory syscalls (mmap, mprotect, etc.) don't do memory accesses but
> rather deal with memory ranges, untagged pointers are better suited to
> describe memory ranges internally. Thus for memory syscalls we untag
> pointers completely when they enter the kernel.

i think the same is true when user pointers are compared.

e.g. i suspect there may be issues with tagged robust mutex
list pointers because the kernel does

futex.c:3541:	while (entry != &head->list) {

where entry is a user pointer that may be tagged, and
&head->list is probably not tagged.

> One of the alternative approaches to untagging that was considered is to
> completely strip the pointer tag as the pointer enters the kernel with
> some kind of a syscall wrapper, but that won't work with the countless
> number of different ioctl calls. With this approach we would need a custom
> wrapper for each ioctl variation, which doesn't seem practical.
> 
> The following testing approaches has been taken to find potential issues
> with user pointer untagging:
> 
> 1. Static testing (with sparse [3] and separately with a custom static
>    analyzer based on Clang) to track casts of __user pointers to integer
>    types to find places where untagging needs to be done.
> 
> 2. Static testing with grep to find parts of the kernel that call
>    find_vma() (and other similar functions) or directly compare against
>    vm_start/vm_end fields of vma.
> 
> 3. Static testing with grep to find parts of the kernel that compare
>    user pointers with TASK_SIZE or other similar consts and macros.
> 
> 4. Dynamic testing: adding BUG_ON(has_tag(addr)) to find_vma() and running
>    a modified syzkaller version that passes tagged pointers to the kernel.
> 
> Based on the results of the testing the requried patches have been added
> to the patchset.
> 
> This patchset has been merged into the Pixel 2 kernel tree and is now
> being used to enable testing of Pixel 2 phones with HWASan.
> 
> This patchset is a prerequisite for ARM's memory tagging hardware feature
> support [4].
> 
> Thanks!
> 
> [1] https://lkml.org/lkml/2018/12/10/402
> 
> [2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
> 
> [3] https://github.com/lucvoo/sparse-dev/commit/5f960cb10f56ec2017c128ef9d16060e0145f292
> 
> [4] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a
> 
> Changes in v10:
> - Added "mm, arm64: untag user pointers passed to memory syscalls" back.
> - New patch "fs, arm64: untag user pointers in fs/userfaultfd.c".
> - New patch "net, arm64: untag user pointers in tcp_zerocopy_receive".
> - New patch "kernel, arm64: untag user pointers in prctl_set_mm*".
> - New patch "tracing, arm64: untag user pointers in seq_print_user_ip".
> 
> Changes in v9:
> - Rebased onto 4.20-rc6.
> - Used u64 instead of __u64 in type casts in the untagged_addr macro for
>   arm64.
> - Added braces around (addr) in the untagged_addr macro for other arches.
> 
> Changes in v8:
> - Rebased onto 65102238 (4.20-rc1).
> - Added a note to the cover letter on why syscall wrappers/shims that untag
>   user pointers won't work.
> - Added a note to the cover letter that this patchset has been merged into
>   the Pixel 2 kernel tree.
> - Documentation fixes, in particular added a list of syscalls that don't
>   support tagged user pointers.
> 
> Changes in v7:
> - Rebased onto 17b57b18 (4.19-rc6).
> - Dropped the "arm64: untag user address in __do_user_fault" patch, since
>   the existing patches already handle user faults properly.
> - Dropped the "usb, arm64: untag user addresses in devio" patch, since the
>   passed pointer must come from a vma and therefore be untagged.
> - Dropped the "arm64: annotate user pointers casts detected by sparse"
>   patch (see the discussion to the replies of the v6 of this patchset).
> - Added more context to the cover letter.
> - Updated Documentation/arm64/tagged-pointers.txt.
> 
> Changes in v6:
> - Added annotations for user pointer casts found by sparse.
> - Rebased onto 050cdc6c (4.19-rc1+).
> 
> Changes in v5:
> - Added 3 new patches that add untagging to places found with static
>   analysis.
> - Rebased onto 44c929e1 (4.18-rc8).
> 
> Changes in v4:
> - Added a selftest for checking that passing tagged pointers to the
>   kernel succeeds.
> - Rebased onto 81e97f013 (4.18-rc1+).
> 
> Changes in v3:
> - Rebased onto e5c51f30 (4.17-rc6+).
> - Added linux-arch@ to the list of recipients.
> 
> Changes in v2:
> - Rebased onto 2d618bdf (4.17-rc3+).
> - Removed excessive untagging in gup.c.
> - Removed untagging pointers returned from __uaccess_mask_ptr.
> 
> Changes in v1:
> - Rebased onto 4.17-rc1.
> 
> Changes in RFC v2:
> - Added "#ifndef untagged_addr..." fallback in linux/uaccess.h instead of
>   defining it for each arch individually.
> - Updated Documentation/arm64/tagged-pointers.txt.
> - Dropped "mm, arm64: untag user addresses in memory syscalls".
> - Rebased onto 3eb2ce82 (4.16-rc7).
> 
> Reviewed-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
> 
> Andrey Konovalov (12):
>   uaccess: add untagged_addr definition for other arches
>   arm64: untag user pointers in access_ok and __uaccess_mask_ptr
>   lib, arm64: untag user pointers in strn*_user
>   mm, arm64: untag user pointers passed to memory syscalls
>   mm, arm64: untag user pointers in mm/gup.c
>   fs, arm64: untag user pointers in copy_mount_options
>   fs, arm64: untag user pointers in fs/userfaultfd.c
>   net, arm64: untag user pointers in tcp_zerocopy_receive
>   kernel, arm64: untag user pointers in prctl_set_mm*
>   tracing, arm64: untag user pointers in seq_print_user_ip
>   arm64: update Documentation/arm64/tagged-pointers.txt
>   selftests, arm64: add a selftest for passing tagged pointers to kernel
> 
>  Documentation/arm64/tagged-pointers.txt       | 25 +++++++++++--------
>  arch/arm64/include/asm/uaccess.h              | 10 +++++---
>  fs/namespace.c                                |  2 +-
>  fs/userfaultfd.c                              |  5 ++++
>  include/linux/memory.h                        |  4 +++
>  ipc/shm.c                                     |  2 ++
>  kernel/sys.c                                  | 14 +++++++++++
>  kernel/trace/trace_output.c                   |  2 +-
>  lib/strncpy_from_user.c                       |  2 ++
>  lib/strnlen_user.c                            |  2 ++
>  mm/gup.c                                      |  4 +++
>  mm/madvise.c                                  |  2 ++
>  mm/mempolicy.c                                |  5 ++++
>  mm/migrate.c                                  |  1 +
>  mm/mincore.c                                  |  2 ++
>  mm/mlock.c                                    |  5 ++++
>  mm/mmap.c                                     |  7 ++++++
>  mm/mprotect.c                                 |  2 ++
>  mm/mremap.c                                   |  2 ++
>  mm/msync.c                                    |  2 ++
>  net/ipv4/tcp.c                                |  2 ++
>  tools/testing/selftests/arm64/.gitignore      |  1 +
>  tools/testing/selftests/arm64/Makefile        | 11 ++++++++
>  .../testing/selftests/arm64/run_tags_test.sh  | 12 +++++++++
>  tools/testing/selftests/arm64/tags_test.c     | 19 ++++++++++++++
>  25 files changed, 129 insertions(+), 16 deletions(-)
>  create mode 100644 tools/testing/selftests/arm64/.gitignore
>  create mode 100644 tools/testing/selftests/arm64/Makefile
>  create mode 100755 tools/testing/selftests/arm64/run_tags_test.sh
>  create mode 100644 tools/testing/selftests/arm64/tags_test.c
>
Andrey Konovalov Feb. 22, 2019, 3:40 p.m. UTC | #2
On Fri, Feb 22, 2019 at 4:35 PM Szabolcs Nagy <Szabolcs.Nagy@arm.com> wrote:
>
> On 22/02/2019 12:53, Andrey Konovalov wrote:
> > This patchset is meant to be merged together with "arm64 relaxed ABI" [1].
> >
> > arm64 has a feature called Top Byte Ignore, which allows to embed pointer
> > tags into the top byte of each pointer. Userspace programs (such as
> > HWASan, a memory debugging tool [2]) might use this feature and pass
> > tagged user pointers to the kernel through syscalls or other interfaces.
> >
> > Right now the kernel is already able to handle user faults with tagged
> > pointers, due to these patches:
> >
> > 1. 81cddd65 ("arm64: traps: fix userspace cache maintenance emulation on a
> >              tagged pointer")
> > 2. 7dcd9dd8 ("arm64: hw_breakpoint: fix watchpoint matching for tagged
> >             pointers")
> > 3. 276e9327 ("arm64: entry: improve data abort handling of tagged
> >             pointers")
> >
> > This patchset extends tagged pointer support to syscall arguments.
> >
> > For non-memory syscalls this is done by untaging user pointers when the
> > kernel performs pointer checking to find out whether the pointer comes
> > from userspace (most notably in access_ok). The untagging is done only
> > when the pointer is being checked, the tag is preserved as the pointer
> > makes its way through the kernel.
> >
> > Since memory syscalls (mmap, mprotect, etc.) don't do memory accesses but
> > rather deal with memory ranges, untagged pointers are better suited to
> > describe memory ranges internally. Thus for memory syscalls we untag
> > pointers completely when they enter the kernel.
>
> i think the same is true when user pointers are compared.
>
> e.g. i suspect there may be issues with tagged robust mutex
> list pointers because the kernel does
>
> futex.c:3541:   while (entry != &head->list) {
>
> where entry is a user pointer that may be tagged, and
> &head->list is probably not tagged.

You're right. I'll expand the cover letter in the next version to
describe this more accurately. The patchset however contains "mm,
arm64: untag user pointers in mm/gup.c" that should take care of futex
pointers.

Thanks!

>
> > One of the alternative approaches to untagging that was considered is to
> > completely strip the pointer tag as the pointer enters the kernel with
> > some kind of a syscall wrapper, but that won't work with the countless
> > number of different ioctl calls. With this approach we would need a custom
> > wrapper for each ioctl variation, which doesn't seem practical.
> >
> > The following testing approaches has been taken to find potential issues
> > with user pointer untagging:
> >
> > 1. Static testing (with sparse [3] and separately with a custom static
> >    analyzer based on Clang) to track casts of __user pointers to integer
> >    types to find places where untagging needs to be done.
> >
> > 2. Static testing with grep to find parts of the kernel that call
> >    find_vma() (and other similar functions) or directly compare against
> >    vm_start/vm_end fields of vma.
> >
> > 3. Static testing with grep to find parts of the kernel that compare
> >    user pointers with TASK_SIZE or other similar consts and macros.
> >
> > 4. Dynamic testing: adding BUG_ON(has_tag(addr)) to find_vma() and running
> >    a modified syzkaller version that passes tagged pointers to the kernel.
> >
> > Based on the results of the testing the requried patches have been added
> > to the patchset.
> >
> > This patchset has been merged into the Pixel 2 kernel tree and is now
> > being used to enable testing of Pixel 2 phones with HWASan.
> >
> > This patchset is a prerequisite for ARM's memory tagging hardware feature
> > support [4].
> >
> > Thanks!
> >
> > [1] https://lkml.org/lkml/2018/12/10/402
> >
> > [2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
> >
> > [3] https://github.com/lucvoo/sparse-dev/commit/5f960cb10f56ec2017c128ef9d16060e0145f292
> >
> > [4] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a
> >
> > Changes in v10:
> > - Added "mm, arm64: untag user pointers passed to memory syscalls" back.
> > - New patch "fs, arm64: untag user pointers in fs/userfaultfd.c".
> > - New patch "net, arm64: untag user pointers in tcp_zerocopy_receive".
> > - New patch "kernel, arm64: untag user pointers in prctl_set_mm*".
> > - New patch "tracing, arm64: untag user pointers in seq_print_user_ip".
> >
> > Changes in v9:
> > - Rebased onto 4.20-rc6.
> > - Used u64 instead of __u64 in type casts in the untagged_addr macro for
> >   arm64.
> > - Added braces around (addr) in the untagged_addr macro for other arches.
> >
> > Changes in v8:
> > - Rebased onto 65102238 (4.20-rc1).
> > - Added a note to the cover letter on why syscall wrappers/shims that untag
> >   user pointers won't work.
> > - Added a note to the cover letter that this patchset has been merged into
> >   the Pixel 2 kernel tree.
> > - Documentation fixes, in particular added a list of syscalls that don't
> >   support tagged user pointers.
> >
> > Changes in v7:
> > - Rebased onto 17b57b18 (4.19-rc6).
> > - Dropped the "arm64: untag user address in __do_user_fault" patch, since
> >   the existing patches already handle user faults properly.
> > - Dropped the "usb, arm64: untag user addresses in devio" patch, since the
> >   passed pointer must come from a vma and therefore be untagged.
> > - Dropped the "arm64: annotate user pointers casts detected by sparse"
> >   patch (see the discussion to the replies of the v6 of this patchset).
> > - Added more context to the cover letter.
> > - Updated Documentation/arm64/tagged-pointers.txt.
> >
> > Changes in v6:
> > - Added annotations for user pointer casts found by sparse.
> > - Rebased onto 050cdc6c (4.19-rc1+).
> >
> > Changes in v5:
> > - Added 3 new patches that add untagging to places found with static
> >   analysis.
> > - Rebased onto 44c929e1 (4.18-rc8).
> >
> > Changes in v4:
> > - Added a selftest for checking that passing tagged pointers to the
> >   kernel succeeds.
> > - Rebased onto 81e97f013 (4.18-rc1+).
> >
> > Changes in v3:
> > - Rebased onto e5c51f30 (4.17-rc6+).
> > - Added linux-arch@ to the list of recipients.
> >
> > Changes in v2:
> > - Rebased onto 2d618bdf (4.17-rc3+).
> > - Removed excessive untagging in gup.c.
> > - Removed untagging pointers returned from __uaccess_mask_ptr.
> >
> > Changes in v1:
> > - Rebased onto 4.17-rc1.
> >
> > Changes in RFC v2:
> > - Added "#ifndef untagged_addr..." fallback in linux/uaccess.h instead of
> >   defining it for each arch individually.
> > - Updated Documentation/arm64/tagged-pointers.txt.
> > - Dropped "mm, arm64: untag user addresses in memory syscalls".
> > - Rebased onto 3eb2ce82 (4.16-rc7).
> >
> > Reviewed-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
> > Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
> >
> > Andrey Konovalov (12):
> >   uaccess: add untagged_addr definition for other arches
> >   arm64: untag user pointers in access_ok and __uaccess_mask_ptr
> >   lib, arm64: untag user pointers in strn*_user
> >   mm, arm64: untag user pointers passed to memory syscalls
> >   mm, arm64: untag user pointers in mm/gup.c
> >   fs, arm64: untag user pointers in copy_mount_options
> >   fs, arm64: untag user pointers in fs/userfaultfd.c
> >   net, arm64: untag user pointers in tcp_zerocopy_receive
> >   kernel, arm64: untag user pointers in prctl_set_mm*
> >   tracing, arm64: untag user pointers in seq_print_user_ip
> >   arm64: update Documentation/arm64/tagged-pointers.txt
> >   selftests, arm64: add a selftest for passing tagged pointers to kernel
> >
> >  Documentation/arm64/tagged-pointers.txt       | 25 +++++++++++--------
> >  arch/arm64/include/asm/uaccess.h              | 10 +++++---
> >  fs/namespace.c                                |  2 +-
> >  fs/userfaultfd.c                              |  5 ++++
> >  include/linux/memory.h                        |  4 +++
> >  ipc/shm.c                                     |  2 ++
> >  kernel/sys.c                                  | 14 +++++++++++
> >  kernel/trace/trace_output.c                   |  2 +-
> >  lib/strncpy_from_user.c                       |  2 ++
> >  lib/strnlen_user.c                            |  2 ++
> >  mm/gup.c                                      |  4 +++
> >  mm/madvise.c                                  |  2 ++
> >  mm/mempolicy.c                                |  5 ++++
> >  mm/migrate.c                                  |  1 +
> >  mm/mincore.c                                  |  2 ++
> >  mm/mlock.c                                    |  5 ++++
> >  mm/mmap.c                                     |  7 ++++++
> >  mm/mprotect.c                                 |  2 ++
> >  mm/mremap.c                                   |  2 ++
> >  mm/msync.c                                    |  2 ++
> >  net/ipv4/tcp.c                                |  2 ++
> >  tools/testing/selftests/arm64/.gitignore      |  1 +
> >  tools/testing/selftests/arm64/Makefile        | 11 ++++++++
> >  .../testing/selftests/arm64/run_tags_test.sh  | 12 +++++++++
> >  tools/testing/selftests/arm64/tags_test.c     | 19 ++++++++++++++
> >  25 files changed, 129 insertions(+), 16 deletions(-)
> >  create mode 100644 tools/testing/selftests/arm64/.gitignore
> >  create mode 100644 tools/testing/selftests/arm64/Makefile
> >  create mode 100755 tools/testing/selftests/arm64/run_tags_test.sh
> >  create mode 100644 tools/testing/selftests/arm64/tags_test.c
> >
>
Szabolcs Nagy Feb. 22, 2019, 4:10 p.m. UTC | #3
On 22/02/2019 15:40, Andrey Konovalov wrote:
> On Fri, Feb 22, 2019 at 4:35 PM Szabolcs Nagy <Szabolcs.Nagy@arm.com> wrote:
>>
>> On 22/02/2019 12:53, Andrey Konovalov wrote:
>>> This patchset is meant to be merged together with "arm64 relaxed ABI" [1].
>>>
>>> arm64 has a feature called Top Byte Ignore, which allows to embed pointer
>>> tags into the top byte of each pointer. Userspace programs (such as
>>> HWASan, a memory debugging tool [2]) might use this feature and pass
>>> tagged user pointers to the kernel through syscalls or other interfaces.
>>>
>>> Right now the kernel is already able to handle user faults with tagged
>>> pointers, due to these patches:
>>>
>>> 1. 81cddd65 ("arm64: traps: fix userspace cache maintenance emulation on a
>>>              tagged pointer")
>>> 2. 7dcd9dd8 ("arm64: hw_breakpoint: fix watchpoint matching for tagged
>>>             pointers")
>>> 3. 276e9327 ("arm64: entry: improve data abort handling of tagged
>>>             pointers")
>>>
>>> This patchset extends tagged pointer support to syscall arguments.
>>>
>>> For non-memory syscalls this is done by untaging user pointers when the
>>> kernel performs pointer checking to find out whether the pointer comes
>>> from userspace (most notably in access_ok). The untagging is done only
>>> when the pointer is being checked, the tag is preserved as the pointer
>>> makes its way through the kernel.
>>>
>>> Since memory syscalls (mmap, mprotect, etc.) don't do memory accesses but
>>> rather deal with memory ranges, untagged pointers are better suited to
>>> describe memory ranges internally. Thus for memory syscalls we untag
>>> pointers completely when they enter the kernel.
>>
>> i think the same is true when user pointers are compared.
>>
>> e.g. i suspect there may be issues with tagged robust mutex
>> list pointers because the kernel does
>>
>> futex.c:3541:   while (entry != &head->list) {
>>
>> where entry is a user pointer that may be tagged, and
>> &head->list is probably not tagged.
> 
> You're right. I'll expand the cover letter in the next version to
> describe this more accurately. The patchset however contains "mm,
> arm64: untag user pointers in mm/gup.c" that should take care of futex
> pointers.

the robust mutex list pointer is not a futex pointer,
i'm not sure how the mm/gup.c patch helps.

>>
>>> One of the alternative approaches to untagging that was considered is to
>>> completely strip the pointer tag as the pointer enters the kernel with
>>> some kind of a syscall wrapper, but that won't work with the countless
>>> number of different ioctl calls. With this approach we would need a custom
>>> wrapper for each ioctl variation, which doesn't seem practical.
>>>
>>> The following testing approaches has been taken to find potential issues
>>> with user pointer untagging:
>>>
>>> 1. Static testing (with sparse [3] and separately with a custom static
>>>    analyzer based on Clang) to track casts of __user pointers to integer
>>>    types to find places where untagging needs to be done.
>>>
>>> 2. Static testing with grep to find parts of the kernel that call
>>>    find_vma() (and other similar functions) or directly compare against
>>>    vm_start/vm_end fields of vma.
>>>
>>> 3. Static testing with grep to find parts of the kernel that compare
>>>    user pointers with TASK_SIZE or other similar consts and macros.
>>>
>>> 4. Dynamic testing: adding BUG_ON(has_tag(addr)) to find_vma() and running
>>>    a modified syzkaller version that passes tagged pointers to the kernel.
>>>
>>> Based on the results of the testing the requried patches have been added
>>> to the patchset.
>>>
>>> This patchset has been merged into the Pixel 2 kernel tree and is now
>>> being used to enable testing of Pixel 2 phones with HWASan.
>>>
>>> This patchset is a prerequisite for ARM's memory tagging hardware feature
>>> support [4].
>>>
>>> Thanks!
>>>
>>> [1] https://lkml.org/lkml/2018/12/10/402
>>>
>>> [2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
>>>
>>> [3] https://github.com/lucvoo/sparse-dev/commit/5f960cb10f56ec2017c128ef9d16060e0145f292
>>>
>>> [4] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a
>>>
>>> Changes in v10:
>>> - Added "mm, arm64: untag user pointers passed to memory syscalls" back.
>>> - New patch "fs, arm64: untag user pointers in fs/userfaultfd.c".
>>> - New patch "net, arm64: untag user pointers in tcp_zerocopy_receive".
>>> - New patch "kernel, arm64: untag user pointers in prctl_set_mm*".
>>> - New patch "tracing, arm64: untag user pointers in seq_print_user_ip".
>>>
>>> Changes in v9:
>>> - Rebased onto 4.20-rc6.
>>> - Used u64 instead of __u64 in type casts in the untagged_addr macro for
>>>   arm64.
>>> - Added braces around (addr) in the untagged_addr macro for other arches.
>>>
>>> Changes in v8:
>>> - Rebased onto 65102238 (4.20-rc1).
>>> - Added a note to the cover letter on why syscall wrappers/shims that untag
>>>   user pointers won't work.
>>> - Added a note to the cover letter that this patchset has been merged into
>>>   the Pixel 2 kernel tree.
>>> - Documentation fixes, in particular added a list of syscalls that don't
>>>   support tagged user pointers.
>>>
>>> Changes in v7:
>>> - Rebased onto 17b57b18 (4.19-rc6).
>>> - Dropped the "arm64: untag user address in __do_user_fault" patch, since
>>>   the existing patches already handle user faults properly.
>>> - Dropped the "usb, arm64: untag user addresses in devio" patch, since the
>>>   passed pointer must come from a vma and therefore be untagged.
>>> - Dropped the "arm64: annotate user pointers casts detected by sparse"
>>>   patch (see the discussion to the replies of the v6 of this patchset).
>>> - Added more context to the cover letter.
>>> - Updated Documentation/arm64/tagged-pointers.txt.
>>>
>>> Changes in v6:
>>> - Added annotations for user pointer casts found by sparse.
>>> - Rebased onto 050cdc6c (4.19-rc1+).
>>>
>>> Changes in v5:
>>> - Added 3 new patches that add untagging to places found with static
>>>   analysis.
>>> - Rebased onto 44c929e1 (4.18-rc8).
>>>
>>> Changes in v4:
>>> - Added a selftest for checking that passing tagged pointers to the
>>>   kernel succeeds.
>>> - Rebased onto 81e97f013 (4.18-rc1+).
>>>
>>> Changes in v3:
>>> - Rebased onto e5c51f30 (4.17-rc6+).
>>> - Added linux-arch@ to the list of recipients.
>>>
>>> Changes in v2:
>>> - Rebased onto 2d618bdf (4.17-rc3+).
>>> - Removed excessive untagging in gup.c.
>>> - Removed untagging pointers returned from __uaccess_mask_ptr.
>>>
>>> Changes in v1:
>>> - Rebased onto 4.17-rc1.
>>>
>>> Changes in RFC v2:
>>> - Added "#ifndef untagged_addr..." fallback in linux/uaccess.h instead of
>>>   defining it for each arch individually.
>>> - Updated Documentation/arm64/tagged-pointers.txt.
>>> - Dropped "mm, arm64: untag user addresses in memory syscalls".
>>> - Rebased onto 3eb2ce82 (4.16-rc7).
>>>
>>> Reviewed-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
>>> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
>>>
>>> Andrey Konovalov (12):
>>>   uaccess: add untagged_addr definition for other arches
>>>   arm64: untag user pointers in access_ok and __uaccess_mask_ptr
>>>   lib, arm64: untag user pointers in strn*_user
>>>   mm, arm64: untag user pointers passed to memory syscalls
>>>   mm, arm64: untag user pointers in mm/gup.c
>>>   fs, arm64: untag user pointers in copy_mount_options
>>>   fs, arm64: untag user pointers in fs/userfaultfd.c
>>>   net, arm64: untag user pointers in tcp_zerocopy_receive
>>>   kernel, arm64: untag user pointers in prctl_set_mm*
>>>   tracing, arm64: untag user pointers in seq_print_user_ip
>>>   arm64: update Documentation/arm64/tagged-pointers.txt
>>>   selftests, arm64: add a selftest for passing tagged pointers to kernel
>>>
>>>  Documentation/arm64/tagged-pointers.txt       | 25 +++++++++++--------
>>>  arch/arm64/include/asm/uaccess.h              | 10 +++++---
>>>  fs/namespace.c                                |  2 +-
>>>  fs/userfaultfd.c                              |  5 ++++
>>>  include/linux/memory.h                        |  4 +++
>>>  ipc/shm.c                                     |  2 ++
>>>  kernel/sys.c                                  | 14 +++++++++++
>>>  kernel/trace/trace_output.c                   |  2 +-
>>>  lib/strncpy_from_user.c                       |  2 ++
>>>  lib/strnlen_user.c                            |  2 ++
>>>  mm/gup.c                                      |  4 +++
>>>  mm/madvise.c                                  |  2 ++
>>>  mm/mempolicy.c                                |  5 ++++
>>>  mm/migrate.c                                  |  1 +
>>>  mm/mincore.c                                  |  2 ++
>>>  mm/mlock.c                                    |  5 ++++
>>>  mm/mmap.c                                     |  7 ++++++
>>>  mm/mprotect.c                                 |  2 ++
>>>  mm/mremap.c                                   |  2 ++
>>>  mm/msync.c                                    |  2 ++
>>>  net/ipv4/tcp.c                                |  2 ++
>>>  tools/testing/selftests/arm64/.gitignore      |  1 +
>>>  tools/testing/selftests/arm64/Makefile        | 11 ++++++++
>>>  .../testing/selftests/arm64/run_tags_test.sh  | 12 +++++++++
>>>  tools/testing/selftests/arm64/tags_test.c     | 19 ++++++++++++++
>>>  25 files changed, 129 insertions(+), 16 deletions(-)
>>>  create mode 100644 tools/testing/selftests/arm64/.gitignore
>>>  create mode 100644 tools/testing/selftests/arm64/Makefile
>>>  create mode 100755 tools/testing/selftests/arm64/run_tags_test.sh
>>>  create mode 100644 tools/testing/selftests/arm64/tags_test.c
>>>
>>
Dave Hansen Feb. 22, 2019, 10:54 p.m. UTC | #4
On 2/22/19 4:53 AM, Andrey Konovalov wrote:
> The following testing approaches has been taken to find potential issues
> with user pointer untagging:
> 
> 1. Static testing (with sparse [3] and separately with a custom static
>    analyzer based on Clang) to track casts of __user pointers to integer
>    types to find places where untagging needs to be done.

First of all, it's really cool that you took this approach.  Sounds like
there was a lot of systematic work to fix up the sites in the existing
codebase.

But, isn't this a _bit_ fragile going forward?  Folks can't just "make
sparse" to find issues with missing untags.  This seems like something
where we would ideally add an __tagged annotation (or something) to the
source tree and then have sparse rules that can look for missed untags.
Andrey Konovalov Feb. 26, 2019, 5 p.m. UTC | #5
On Fri, Feb 22, 2019 at 5:10 PM Szabolcs Nagy <Szabolcs.Nagy@arm.com> wrote:
>
> On 22/02/2019 15:40, Andrey Konovalov wrote:
> > On Fri, Feb 22, 2019 at 4:35 PM Szabolcs Nagy <Szabolcs.Nagy@arm.com> wrote:
> >>
> >> On 22/02/2019 12:53, Andrey Konovalov wrote:
> >>> This patchset is meant to be merged together with "arm64 relaxed ABI" [1].
> >>>
> >>> arm64 has a feature called Top Byte Ignore, which allows to embed pointer
> >>> tags into the top byte of each pointer. Userspace programs (such as
> >>> HWASan, a memory debugging tool [2]) might use this feature and pass
> >>> tagged user pointers to the kernel through syscalls or other interfaces.
> >>>
> >>> Right now the kernel is already able to handle user faults with tagged
> >>> pointers, due to these patches:
> >>>
> >>> 1. 81cddd65 ("arm64: traps: fix userspace cache maintenance emulation on a
> >>>              tagged pointer")
> >>> 2. 7dcd9dd8 ("arm64: hw_breakpoint: fix watchpoint matching for tagged
> >>>             pointers")
> >>> 3. 276e9327 ("arm64: entry: improve data abort handling of tagged
> >>>             pointers")
> >>>
> >>> This patchset extends tagged pointer support to syscall arguments.
> >>>
> >>> For non-memory syscalls this is done by untaging user pointers when the
> >>> kernel performs pointer checking to find out whether the pointer comes
> >>> from userspace (most notably in access_ok). The untagging is done only
> >>> when the pointer is being checked, the tag is preserved as the pointer
> >>> makes its way through the kernel.
> >>>
> >>> Since memory syscalls (mmap, mprotect, etc.) don't do memory accesses but
> >>> rather deal with memory ranges, untagged pointers are better suited to
> >>> describe memory ranges internally. Thus for memory syscalls we untag
> >>> pointers completely when they enter the kernel.
> >>
> >> i think the same is true when user pointers are compared.
> >>
> >> e.g. i suspect there may be issues with tagged robust mutex
> >> list pointers because the kernel does
> >>
> >> futex.c:3541:   while (entry != &head->list) {
> >>
> >> where entry is a user pointer that may be tagged, and
> >> &head->list is probably not tagged.
> >
> > You're right. I'll expand the cover letter in the next version to
> > describe this more accurately. The patchset however contains "mm,
> > arm64: untag user pointers in mm/gup.c" that should take care of futex
> > pointers.
>
> the robust mutex list pointer is not a futex pointer,
> i'm not sure how the mm/gup.c patch helps.

Oh, I've misinterpreted what you said, sorry.

I've looked at the robust futex list implementation, and I'm not sure
if we need to add untagging here.

> >> futex.c:3541:   while (entry != &head->list) {

Here head has whatever value user has set via the set_robust_list
syscall and it might be tagged. AFAIU this loop iterates over the
robust list stored in userspace, until it encounters the head pointer
again, at which point the kernel decides that it has iterated over the
whole list and stops. The question is whether we want the user to use
the same tag for the pointer that is passed to the set_robust_list
syscall and the pointer that is used to mark the end of the robust
list.

Catalin, what do you think?

>
> >>
> >>> One of the alternative approaches to untagging that was considered is to
> >>> completely strip the pointer tag as the pointer enters the kernel with
> >>> some kind of a syscall wrapper, but that won't work with the countless
> >>> number of different ioctl calls. With this approach we would need a custom
> >>> wrapper for each ioctl variation, which doesn't seem practical.
> >>>
> >>> The following testing approaches has been taken to find potential issues
> >>> with user pointer untagging:
> >>>
> >>> 1. Static testing (with sparse [3] and separately with a custom static
> >>>    analyzer based on Clang) to track casts of __user pointers to integer
> >>>    types to find places where untagging needs to be done.
> >>>
> >>> 2. Static testing with grep to find parts of the kernel that call
> >>>    find_vma() (and other similar functions) or directly compare against
> >>>    vm_start/vm_end fields of vma.
> >>>
> >>> 3. Static testing with grep to find parts of the kernel that compare
> >>>    user pointers with TASK_SIZE or other similar consts and macros.
> >>>
> >>> 4. Dynamic testing: adding BUG_ON(has_tag(addr)) to find_vma() and running
> >>>    a modified syzkaller version that passes tagged pointers to the kernel.
> >>>
> >>> Based on the results of the testing the requried patches have been added
> >>> to the patchset.
> >>>
> >>> This patchset has been merged into the Pixel 2 kernel tree and is now
> >>> being used to enable testing of Pixel 2 phones with HWASan.
> >>>
> >>> This patchset is a prerequisite for ARM's memory tagging hardware feature
> >>> support [4].
> >>>
> >>> Thanks!
> >>>
> >>> [1] https://lkml.org/lkml/2018/12/10/402
> >>>
> >>> [2] http://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html
> >>>
> >>> [3] https://github.com/lucvoo/sparse-dev/commit/5f960cb10f56ec2017c128ef9d16060e0145f292
> >>>
> >>> [4] https://community.arm.com/processors/b/blog/posts/arm-a-profile-architecture-2018-developments-armv85a
> >>>
> >>> Changes in v10:
> >>> - Added "mm, arm64: untag user pointers passed to memory syscalls" back.
> >>> - New patch "fs, arm64: untag user pointers in fs/userfaultfd.c".
> >>> - New patch "net, arm64: untag user pointers in tcp_zerocopy_receive".
> >>> - New patch "kernel, arm64: untag user pointers in prctl_set_mm*".
> >>> - New patch "tracing, arm64: untag user pointers in seq_print_user_ip".
> >>>
> >>> Changes in v9:
> >>> - Rebased onto 4.20-rc6.
> >>> - Used u64 instead of __u64 in type casts in the untagged_addr macro for
> >>>   arm64.
> >>> - Added braces around (addr) in the untagged_addr macro for other arches.
> >>>
> >>> Changes in v8:
> >>> - Rebased onto 65102238 (4.20-rc1).
> >>> - Added a note to the cover letter on why syscall wrappers/shims that untag
> >>>   user pointers won't work.
> >>> - Added a note to the cover letter that this patchset has been merged into
> >>>   the Pixel 2 kernel tree.
> >>> - Documentation fixes, in particular added a list of syscalls that don't
> >>>   support tagged user pointers.
> >>>
> >>> Changes in v7:
> >>> - Rebased onto 17b57b18 (4.19-rc6).
> >>> - Dropped the "arm64: untag user address in __do_user_fault" patch, since
> >>>   the existing patches already handle user faults properly.
> >>> - Dropped the "usb, arm64: untag user addresses in devio" patch, since the
> >>>   passed pointer must come from a vma and therefore be untagged.
> >>> - Dropped the "arm64: annotate user pointers casts detected by sparse"
> >>>   patch (see the discussion to the replies of the v6 of this patchset).
> >>> - Added more context to the cover letter.
> >>> - Updated Documentation/arm64/tagged-pointers.txt.
> >>>
> >>> Changes in v6:
> >>> - Added annotations for user pointer casts found by sparse.
> >>> - Rebased onto 050cdc6c (4.19-rc1+).
> >>>
> >>> Changes in v5:
> >>> - Added 3 new patches that add untagging to places found with static
> >>>   analysis.
> >>> - Rebased onto 44c929e1 (4.18-rc8).
> >>>
> >>> Changes in v4:
> >>> - Added a selftest for checking that passing tagged pointers to the
> >>>   kernel succeeds.
> >>> - Rebased onto 81e97f013 (4.18-rc1+).
> >>>
> >>> Changes in v3:
> >>> - Rebased onto e5c51f30 (4.17-rc6+).
> >>> - Added linux-arch@ to the list of recipients.
> >>>
> >>> Changes in v2:
> >>> - Rebased onto 2d618bdf (4.17-rc3+).
> >>> - Removed excessive untagging in gup.c.
> >>> - Removed untagging pointers returned from __uaccess_mask_ptr.
> >>>
> >>> Changes in v1:
> >>> - Rebased onto 4.17-rc1.
> >>>
> >>> Changes in RFC v2:
> >>> - Added "#ifndef untagged_addr..." fallback in linux/uaccess.h instead of
> >>>   defining it for each arch individually.
> >>> - Updated Documentation/arm64/tagged-pointers.txt.
> >>> - Dropped "mm, arm64: untag user addresses in memory syscalls".
> >>> - Rebased onto 3eb2ce82 (4.16-rc7).
> >>>
> >>> Reviewed-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
> >>> Signed-off-by: Andrey Konovalov <andreyknvl@google.com>
> >>>
> >>> Andrey Konovalov (12):
> >>>   uaccess: add untagged_addr definition for other arches
> >>>   arm64: untag user pointers in access_ok and __uaccess_mask_ptr
> >>>   lib, arm64: untag user pointers in strn*_user
> >>>   mm, arm64: untag user pointers passed to memory syscalls
> >>>   mm, arm64: untag user pointers in mm/gup.c
> >>>   fs, arm64: untag user pointers in copy_mount_options
> >>>   fs, arm64: untag user pointers in fs/userfaultfd.c
> >>>   net, arm64: untag user pointers in tcp_zerocopy_receive
> >>>   kernel, arm64: untag user pointers in prctl_set_mm*
> >>>   tracing, arm64: untag user pointers in seq_print_user_ip
> >>>   arm64: update Documentation/arm64/tagged-pointers.txt
> >>>   selftests, arm64: add a selftest for passing tagged pointers to kernel
> >>>
> >>>  Documentation/arm64/tagged-pointers.txt       | 25 +++++++++++--------
> >>>  arch/arm64/include/asm/uaccess.h              | 10 +++++---
> >>>  fs/namespace.c                                |  2 +-
> >>>  fs/userfaultfd.c                              |  5 ++++
> >>>  include/linux/memory.h                        |  4 +++
> >>>  ipc/shm.c                                     |  2 ++
> >>>  kernel/sys.c                                  | 14 +++++++++++
> >>>  kernel/trace/trace_output.c                   |  2 +-
> >>>  lib/strncpy_from_user.c                       |  2 ++
> >>>  lib/strnlen_user.c                            |  2 ++
> >>>  mm/gup.c                                      |  4 +++
> >>>  mm/madvise.c                                  |  2 ++
> >>>  mm/mempolicy.c                                |  5 ++++
> >>>  mm/migrate.c                                  |  1 +
> >>>  mm/mincore.c                                  |  2 ++
> >>>  mm/mlock.c                                    |  5 ++++
> >>>  mm/mmap.c                                     |  7 ++++++
> >>>  mm/mprotect.c                                 |  2 ++
> >>>  mm/mremap.c                                   |  2 ++
> >>>  mm/msync.c                                    |  2 ++
> >>>  net/ipv4/tcp.c                                |  2 ++
> >>>  tools/testing/selftests/arm64/.gitignore      |  1 +
> >>>  tools/testing/selftests/arm64/Makefile        | 11 ++++++++
> >>>  .../testing/selftests/arm64/run_tags_test.sh  | 12 +++++++++
> >>>  tools/testing/selftests/arm64/tags_test.c     | 19 ++++++++++++++
> >>>  25 files changed, 129 insertions(+), 16 deletions(-)
> >>>  create mode 100644 tools/testing/selftests/arm64/.gitignore
> >>>  create mode 100644 tools/testing/selftests/arm64/Makefile
> >>>  create mode 100755 tools/testing/selftests/arm64/run_tags_test.sh
> >>>  create mode 100644 tools/testing/selftests/arm64/tags_test.c
> >>>
> >>
>
Andrey Konovalov Feb. 26, 2019, 5:18 p.m. UTC | #6
On Fri, Feb 22, 2019 at 11:55 PM Dave Hansen <dave.hansen@intel.com> wrote:
>
> On 2/22/19 4:53 AM, Andrey Konovalov wrote:
> > The following testing approaches has been taken to find potential issues
> > with user pointer untagging:
> >
> > 1. Static testing (with sparse [3] and separately with a custom static
> >    analyzer based on Clang) to track casts of __user pointers to integer
> >    types to find places where untagging needs to be done.
>
> First of all, it's really cool that you took this approach.  Sounds like
> there was a lot of systematic work to fix up the sites in the existing
> codebase.
>
> But, isn't this a _bit_ fragile going forward?  Folks can't just "make
> sparse" to find issues with missing untags.

Yes, this static approach can only be used as a hint to find some
places where untagging is needed, but certainly not all.

> This seems like something
> where we would ideally add an __tagged annotation (or something) to the
> source tree and then have sparse rules that can look for missed untags.

This has been suggested before, search for __untagged here [1].
However there are many places in the kernel where a __user pointer is
casted into unsigned long and passed further. I'm not sure if it's
possible apply a __tagged/__untagged kind of attribute to non-pointer
types, is it?

[1] https://patchwork.kernel.org/patch/10581535/
Dave Hansen Feb. 26, 2019, 5:35 p.m. UTC | #7
On 2/26/19 9:18 AM, Andrey Konovalov wrote:
>> This seems like something
>> where we would ideally add an __tagged annotation (or something) to the
>> source tree and then have sparse rules that can look for missed untags.
> This has been suggested before, search for __untagged here [1].
> However there are many places in the kernel where a __user pointer is
> casted into unsigned long and passed further. I'm not sure if it's
> possible apply a __tagged/__untagged kind of attribute to non-pointer
> types, is it?
> 
> [1] https://patchwork.kernel.org/patch/10581535/

I believe we have sparse checking __GFP_* flags.  We also have a gfp_t
for them and I'm unsure whether the sparse support is tied to _that_ or
whether it's just by tagging the type itself as being part of a discrete
address space.
Luc Van Oostenryck Feb. 26, 2019, 11:17 p.m. UTC | #8
On Tue, Feb 26, 2019 at 06:18:25PM +0100, Andrey Konovalov wrote:
> On Fri, Feb 22, 2019 at 11:55 PM Dave Hansen <dave.hansen@intel.com> wrote:
> >
> > On 2/22/19 4:53 AM, Andrey Konovalov wrote:
> > > The following testing approaches has been taken to find potential issues
> > > with user pointer untagging:
> > >
> > > 1. Static testing (with sparse [3] and separately with a custom static
> > >    analyzer based on Clang) to track casts of __user pointers to integer
> > >    types to find places where untagging needs to be done.
> >
> > First of all, it's really cool that you took this approach.  Sounds like
> > there was a lot of systematic work to fix up the sites in the existing
> > codebase.
> >
> > But, isn't this a _bit_ fragile going forward?  Folks can't just "make
> > sparse" to find issues with missing untags.
> 
> Yes, this static approach can only be used as a hint to find some
> places where untagging is needed, but certainly not all.
> 
> > This seems like something
> > where we would ideally add an __tagged annotation (or something) to the
> > source tree and then have sparse rules that can look for missed untags.
> 
> This has been suggested before, search for __untagged here [1].
> However there are many places in the kernel where a __user pointer is
> casted into unsigned long and passed further. I'm not sure if it's
> possible apply a __tagged/__untagged kind of attribute to non-pointer
> types, is it?
> 
> [1] https://patchwork.kernel.org/patch/10581535/

It's something that should need to be added to sparse since it's
different from what sparse already have (the existing __bitwise and
concept of address-space doesn't seem to do the job here).

-- Luc Van Oostenryck