arch/arm64/kernel/patch-scs.c:67:29: sparse: sparse: incorrect type in assignment (different base types)

From: kernel test robot
Date: Fri Nov 24 2023 - 09:40:16 EST


tree: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git master
head: f1a09972a45ae63efbd1587337c4be13b1893330
commit: 3b619e22c4601b444ed2d6a5458271f72625ac89 arm64: implement dynamic shadow call stack for Clang
date: 1 year ago
config: arm64-randconfig-r133-20231123 (https://download.01.org/0day-ci/archive/20231124/202311241547.VshdwLyK-lkp@xxxxxxxxx/config)
compiler: clang version 15.0.7 (https://github.com/llvm/llvm-project.git 8dfdcc7b7bf66834a761bd8de445840ef68e4d1a)
reproduce: (https://download.01.org/0day-ci/archive/20231124/202311241547.VshdwLyK-lkp@xxxxxxxxx/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@xxxxxxxxx>
| Closes: https://lore.kernel.org/oe-kbuild-all/202311241547.VshdwLyK-lkp@xxxxxxxxx/

sparse warnings: (new ones prefixed by >>)
arch/arm64/kernel/patch-scs.c:249:24: sparse: sparse: symbol 'scs_patch_vmlinux' was not declared. Should it be static?
>> arch/arm64/kernel/patch-scs.c:67:29: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] @@ got restricted __le32 [usertype] @@
arch/arm64/kernel/patch-scs.c:67:29: sparse: expected unsigned int [usertype]
arch/arm64/kernel/patch-scs.c:67:29: sparse: got restricted __le32 [usertype]
arch/arm64/kernel/patch-scs.c:70:29: sparse: sparse: incorrect type in assignment (different base types) @@ expected unsigned int [usertype] @@ got restricted __le32 [usertype] @@
arch/arm64/kernel/patch-scs.c:70:29: sparse: expected unsigned int [usertype]
arch/arm64/kernel/patch-scs.c:70:29: sparse: got restricted __le32 [usertype]

vim +67 arch/arm64/kernel/patch-scs.c

60
61 static void __always_inline scs_patch_loc(u64 loc)
62 {
63 u32 insn = le32_to_cpup((void *)loc);
64
65 switch (insn) {
66 case PACIASP:
> 67 *(u32 *)loc = cpu_to_le32(SCS_PUSH);
68 break;
69 case AUTIASP:
70 *(u32 *)loc = cpu_to_le32(SCS_POP);
71 break;
72 default:
73 /*
74 * While the DW_CFA_negate_ra_state directive is guaranteed to
75 * appear right after a PACIASP/AUTIASP instruction, it may
76 * also appear after a DW_CFA_restore_state directive that
77 * restores a state that is only partially accurate, and is
78 * followed by DW_CFA_negate_ra_state directive to toggle the
79 * PAC bit again. So we permit other instructions here, and ignore
80 * them.
81 */
82 return;
83 }
84 dcache_clean_pou(loc, loc + sizeof(u32));
85 }
86
87 /*
88 * Skip one uleb128/sleb128 encoded quantity from the opcode stream. All bytes
89 * except the last one have bit #7 set.
90 */
91 static int __always_inline skip_xleb128(const u8 **opcode, int size)
92 {
93 u8 c;
94
95 do {
96 c = *(*opcode)++;
97 size--;
98 } while (c & BIT(7));
99
100 return size;
101 }
102
103 struct eh_frame {
104 /*
105 * The size of this frame if 0 < size < U32_MAX, 0 terminates the list.
106 */
107 u32 size;
108
109 /*
110 * The first frame is a Common Information Entry (CIE) frame, followed
111 * by one or more Frame Description Entry (FDE) frames. In the former
112 * case, this field is 0, otherwise it is the negated offset relative
113 * to the associated CIE frame.
114 */
115 u32 cie_id_or_pointer;
116
117 union {
118 struct { // CIE
119 u8 version;
120 u8 augmentation_string[];
121 };
122
123 struct { // FDE
124 s32 initial_loc;
125 s32 range;
126 u8 opcodes[];
127 };
128 };
129 };
130
131 static int noinstr scs_handle_fde_frame(const struct eh_frame *frame,
132 bool fde_has_augmentation_data,
133 int code_alignment_factor)
134 {
135 int size = frame->size - offsetof(struct eh_frame, opcodes) + 4;
136 u64 loc = (u64)offset_to_ptr(&frame->initial_loc);
137 const u8 *opcode = frame->opcodes;
138
139 if (fde_has_augmentation_data) {
140 int l;
141
142 // assume single byte uleb128_t
143 if (WARN_ON(*opcode & BIT(7)))
144 return -ENOEXEC;
145
146 l = *opcode++;
147 opcode += l;
148 size -= l + 1;
149 }
150
151 /*
152 * Starting from 'loc', apply the CFA opcodes that advance the location
153 * pointer, and identify the locations of the PAC instructions.
154 */
155 while (size-- > 0) {
156 switch (*opcode++) {
157 case DW_CFA_nop:
158 case DW_CFA_remember_state:
159 case DW_CFA_restore_state:
160 break;
161
162 case DW_CFA_advance_loc1:
163 loc += *opcode++ * code_alignment_factor;
164 size--;
165 break;
166
167 case DW_CFA_advance_loc2:
168 loc += *opcode++ * code_alignment_factor;
169 loc += (*opcode++ << 8) * code_alignment_factor;
170 size -= 2;
171 break;
172
173 case DW_CFA_def_cfa:
174 case DW_CFA_offset_extended:
175 size = skip_xleb128(&opcode, size);
176 fallthrough;
177 case DW_CFA_def_cfa_offset:
178 case DW_CFA_def_cfa_offset_sf:
179 case DW_CFA_def_cfa_register:
180 case DW_CFA_same_value:
181 case DW_CFA_restore_extended:
182 case 0x80 ... 0xbf:
183 size = skip_xleb128(&opcode, size);
184 break;
185
186 case DW_CFA_negate_ra_state:
187 scs_patch_loc(loc - 4);
188 break;
189
190 case 0x40 ... 0x7f:
191 // advance loc
192 loc += (opcode[-1] & 0x3f) * code_alignment_factor;
193 break;
194
195 case 0xc0 ... 0xff:
196 break;
197
198 default:
199 pr_err("unhandled opcode: %02x in FDE frame %lx\n", opcode[-1], (uintptr_t)frame);
200 return -ENOEXEC;
201 }
202 }
203 return 0;
204 }
205
206 int noinstr scs_patch(const u8 eh_frame[], int size)
207 {
208 const u8 *p = eh_frame;
209
210 while (size > 4) {
211 const struct eh_frame *frame = (const void *)p;
212 bool fde_has_augmentation_data = true;
213 int code_alignment_factor = 1;
214 int ret;
215
216 if (frame->size == 0 ||
217 frame->size == U32_MAX ||
218 frame->size > size)
219 break;
220
221 if (frame->cie_id_or_pointer == 0) {
222 const u8 *p = frame->augmentation_string;
223
224 /* a 'z' in the augmentation string must come first */
225 fde_has_augmentation_data = *p == 'z';
226
227 /*
228 * The code alignment factor is a uleb128 encoded field
229 * but given that the only sensible values are 1 or 4,
230 * there is no point in decoding the whole thing.
231 */
232 p += strlen(p) + 1;
233 if (!WARN_ON(*p & BIT(7)))
234 code_alignment_factor = *p;
235 } else {
236 ret = scs_handle_fde_frame(frame,
237 fde_has_augmentation_data,
238 code_alignment_factor);
239 if (ret)
240 return ret;
241 }
242
243 p += sizeof(frame->size) + frame->size;
244 size -= sizeof(frame->size) + frame->size;
245 }
246 return 0;
247 }
248
> 249 asmlinkage void __init scs_patch_vmlinux(void)

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki