1 /* SPDX-License-Identifier: GPL-2.0 */ 2 #ifndef __TRACE_PROBE_KERNEL_H_ 3 #define __TRACE_PROBE_KERNEL_H_ 4 5 #define FAULT_STRING "(fault)" 6 7 /* 8 * This depends on trace_probe.h, but can not include it due to 9 * the way trace_probe_tmpl.h is used by trace_kprobe.c and trace_eprobe.c. 10 * Which means that any other user must include trace_probe.h before including 11 * this file. 12 */ 13 /* Return the length of string -- including null terminal byte */ 14 static nokprobe_inline int 15 fetch_store_strlen_user(unsigned long addr) 16 { 17 const void __user *uaddr = (__force const void __user *)addr; 18 int ret; 19 20 ret = strnlen_user_nofault(uaddr, MAX_STRING_SIZE); 21 /* 22 * strnlen_user_nofault returns zero on fault, insert the 23 * FAULT_STRING when that occurs. 24 */ 25 if (ret <= 0) 26 return strlen(FAULT_STRING) + 1; 27 return ret; 28 } 29 30 /* Return the length of string -- including null terminal byte */ 31 static nokprobe_inline int 32 fetch_store_strlen(unsigned long addr) 33 { 34 int ret, len = 0; 35 u8 c; 36 37 #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 38 if (addr < TASK_SIZE) 39 return fetch_store_strlen_user(addr); 40 #endif 41 42 do { 43 ret = copy_from_kernel_nofault(&c, (u8 *)addr + len, 1); 44 len++; 45 } while (c && ret == 0 && len < MAX_STRING_SIZE); 46 47 /* For faults, return enough to hold the FAULT_STRING */ 48 return (ret < 0) ? strlen(FAULT_STRING) + 1 : len; 49 } 50 51 static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void *base, int len) 52 { 53 if (ret >= 0) { 54 *(u32 *)dest = make_data_loc(ret, __dest - base); 55 } else { 56 strscpy(__dest, FAULT_STRING, len); 57 ret = strlen(__dest) + 1; 58 } 59 } 60 61 /* 62 * Fetch a null-terminated string from user. Caller MUST set *(u32 *)buf 63 * with max length and relative data location. 64 */ 65 static nokprobe_inline int 66 fetch_store_string_user(unsigned long addr, void *dest, void *base) 67 { 68 const void __user *uaddr = (__force const void __user *)addr; 69 int maxlen = get_loc_len(*(u32 *)dest); 70 void *__dest; 71 long ret; 72 73 if (unlikely(!maxlen)) 74 return -ENOMEM; 75 76 __dest = get_loc_data(dest, base); 77 78 ret = strncpy_from_user_nofault(__dest, uaddr, maxlen); 79 set_data_loc(ret, dest, __dest, base, maxlen); 80 81 return ret; 82 } 83 84 /* 85 * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max 86 * length and relative data location. 87 */ 88 static nokprobe_inline int 89 fetch_store_string(unsigned long addr, void *dest, void *base) 90 { 91 int maxlen = get_loc_len(*(u32 *)dest); 92 void *__dest; 93 long ret; 94 95 #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 96 if ((unsigned long)addr < TASK_SIZE) 97 return fetch_store_string_user(addr, dest, base); 98 #endif 99 100 if (unlikely(!maxlen)) 101 return -ENOMEM; 102 103 __dest = get_loc_data(dest, base); 104 105 /* 106 * Try to get string again, since the string can be changed while 107 * probing. 108 */ 109 ret = strncpy_from_kernel_nofault(__dest, (void *)addr, maxlen); 110 set_data_loc(ret, dest, __dest, base, maxlen); 111 112 return ret; 113 } 114 115 static nokprobe_inline int 116 probe_mem_read_user(void *dest, void *src, size_t size) 117 { 118 const void __user *uaddr = (__force const void __user *)src; 119 120 return copy_from_user_nofault(dest, uaddr, size); 121 } 122 123 static nokprobe_inline int 124 probe_mem_read(void *dest, void *src, size_t size) 125 { 126 #ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE 127 if ((unsigned long)src < TASK_SIZE) 128 return probe_mem_read_user(dest, src, size); 129 #endif 130 return copy_from_kernel_nofault(dest, src, size); 131 } 132 133 #endif /* __TRACE_PROBE_KERNEL_H_ */ 134