user_fixup.c 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. /* user_fixup.c: Fix up user copy faults.
  2. *
  3. * Copyright (C) 2004 David S. Miller <davem@redhat.com>
  4. */
  5. #include <linux/compiler.h>
  6. #include <linux/kernel.h>
  7. #include <linux/string.h>
  8. #include <linux/errno.h>
  9. #include <asm/uaccess.h>
  10. /* Calculating the exact fault address when using
  11. * block loads and stores can be very complicated.
  12. *
  13. * Instead of trying to be clever and handling all
  14. * of the cases, just fix things up simply here.
  15. */
  16. static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset)
  17. {
  18. unsigned long fault_addr = current_thread_info()->fault_address;
  19. unsigned long end = start + size;
  20. if (fault_addr < start || fault_addr >= end) {
  21. *offset = 0;
  22. } else {
  23. *offset = start - fault_addr;
  24. size = end - fault_addr;
  25. }
  26. return size;
  27. }
  28. unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size)
  29. {
  30. unsigned long offset;
  31. size = compute_size((unsigned long) from, size, &offset);
  32. if (likely(size))
  33. memset(to + offset, 0, size);
  34. return size;
  35. }
  36. unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size)
  37. {
  38. unsigned long offset;
  39. return compute_size((unsigned long) to, size, &offset);
  40. }
  41. unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size)
  42. {
  43. unsigned long fault_addr = current_thread_info()->fault_address;
  44. unsigned long start = (unsigned long) to;
  45. unsigned long end = start + size;
  46. if (fault_addr >= start && fault_addr < end)
  47. return end - fault_addr;
  48. start = (unsigned long) from;
  49. end = start + size;
  50. if (fault_addr >= start && fault_addr < end)
  51. return end - fault_addr;
  52. return size;
  53. }