1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef __CEPH_DECODE_H |
3 | #define __CEPH_DECODE_H |
4 | |
5 | #include <linux/err.h> |
6 | #include <linux/bug.h> |
7 | #include <linux/slab.h> |
8 | #include <linux/time.h> |
9 | #include <asm/unaligned.h> |
10 | |
11 | #include <linux/ceph/types.h> |
12 | |
13 | /* |
14 | * in all cases, |
15 | * void **p pointer to position pointer |
16 | * void *end pointer to end of buffer (last byte + 1) |
17 | */ |
18 | |
19 | static inline u64 ceph_decode_64(void **p) |
20 | { |
21 | u64 v = get_unaligned_le64(p: *p); |
22 | *p += sizeof(u64); |
23 | return v; |
24 | } |
25 | static inline u32 ceph_decode_32(void **p) |
26 | { |
27 | u32 v = get_unaligned_le32(p: *p); |
28 | *p += sizeof(u32); |
29 | return v; |
30 | } |
31 | static inline u16 ceph_decode_16(void **p) |
32 | { |
33 | u16 v = get_unaligned_le16(p: *p); |
34 | *p += sizeof(u16); |
35 | return v; |
36 | } |
37 | static inline u8 ceph_decode_8(void **p) |
38 | { |
39 | u8 v = *(u8 *)*p; |
40 | (*p)++; |
41 | return v; |
42 | } |
43 | static inline void ceph_decode_copy(void **p, void *pv, size_t n) |
44 | { |
45 | memcpy(pv, *p, n); |
46 | *p += n; |
47 | } |
48 | |
49 | /* |
50 | * bounds check input. |
51 | */ |
52 | static inline bool ceph_has_room(void **p, void *end, size_t n) |
53 | { |
54 | return end >= *p && n <= end - *p; |
55 | } |
56 | |
57 | #define ceph_decode_need(p, end, n, bad) \ |
58 | do { \ |
59 | if (!likely(ceph_has_room(p, end, n))) \ |
60 | goto bad; \ |
61 | } while (0) |
62 | |
63 | #define ceph_decode_64_safe(p, end, v, bad) \ |
64 | do { \ |
65 | ceph_decode_need(p, end, sizeof(u64), bad); \ |
66 | v = ceph_decode_64(p); \ |
67 | } while (0) |
68 | #define ceph_decode_32_safe(p, end, v, bad) \ |
69 | do { \ |
70 | ceph_decode_need(p, end, sizeof(u32), bad); \ |
71 | v = ceph_decode_32(p); \ |
72 | } while (0) |
73 | #define ceph_decode_16_safe(p, end, v, bad) \ |
74 | do { \ |
75 | ceph_decode_need(p, end, sizeof(u16), bad); \ |
76 | v = ceph_decode_16(p); \ |
77 | } while (0) |
78 | #define ceph_decode_8_safe(p, end, v, bad) \ |
79 | do { \ |
80 | ceph_decode_need(p, end, sizeof(u8), bad); \ |
81 | v = ceph_decode_8(p); \ |
82 | } while (0) |
83 | |
84 | #define ceph_decode_copy_safe(p, end, pv, n, bad) \ |
85 | do { \ |
86 | ceph_decode_need(p, end, n, bad); \ |
87 | ceph_decode_copy(p, pv, n); \ |
88 | } while (0) |
89 | |
90 | /* |
91 | * Allocate a buffer big enough to hold the wire-encoded string, and |
92 | * decode the string into it. The resulting string will always be |
93 | * terminated with '\0'. If successful, *p will be advanced |
94 | * past the decoded data. Also, if lenp is not a null pointer, the |
95 | * length (not including the terminating '\0') will be recorded in |
96 | * *lenp. Note that a zero-length string is a valid return value. |
97 | * |
98 | * Returns a pointer to the newly-allocated string buffer, or a |
99 | * pointer-coded errno if an error occurs. Neither *p nor *lenp |
100 | * will have been updated if an error is returned. |
101 | * |
102 | * There are two possible failures: |
103 | * - converting the string would require accessing memory at or |
104 | * beyond the "end" pointer provided (-ERANGE) |
105 | * - memory could not be allocated for the result (-ENOMEM) |
106 | */ |
107 | static inline char *(void **p, void *end, |
108 | size_t *lenp, gfp_t gfp) |
109 | { |
110 | u32 len; |
111 | void *sp = *p; |
112 | char *buf; |
113 | |
114 | ceph_decode_32_safe(&sp, end, len, bad); |
115 | if (!ceph_has_room(p: &sp, end, n: len)) |
116 | goto bad; |
117 | |
118 | buf = kmalloc(size: len + 1, flags: gfp); |
119 | if (!buf) |
120 | return ERR_PTR(error: -ENOMEM); |
121 | |
122 | if (len) |
123 | memcpy(buf, sp, len); |
124 | buf[len] = '\0'; |
125 | |
126 | *p = (char *) *p + sizeof (u32) + len; |
127 | if (lenp) |
128 | *lenp = (size_t) len; |
129 | |
130 | return buf; |
131 | |
132 | bad: |
133 | return ERR_PTR(error: -ERANGE); |
134 | } |
135 | |
136 | /* |
137 | * skip helpers |
138 | */ |
139 | #define ceph_decode_skip_n(p, end, n, bad) \ |
140 | do { \ |
141 | ceph_decode_need(p, end, n, bad); \ |
142 | *p += n; \ |
143 | } while (0) |
144 | |
145 | #define ceph_decode_skip_64(p, end, bad) \ |
146 | ceph_decode_skip_n(p, end, sizeof(u64), bad) |
147 | |
148 | #define ceph_decode_skip_32(p, end, bad) \ |
149 | ceph_decode_skip_n(p, end, sizeof(u32), bad) |
150 | |
151 | #define ceph_decode_skip_16(p, end, bad) \ |
152 | ceph_decode_skip_n(p, end, sizeof(u16), bad) |
153 | |
154 | #define ceph_decode_skip_8(p, end, bad) \ |
155 | ceph_decode_skip_n(p, end, sizeof(u8), bad) |
156 | |
157 | #define ceph_decode_skip_string(p, end, bad) \ |
158 | do { \ |
159 | u32 len; \ |
160 | \ |
161 | ceph_decode_32_safe(p, end, len, bad); \ |
162 | ceph_decode_skip_n(p, end, len, bad); \ |
163 | } while (0) |
164 | |
165 | #define ceph_decode_skip_set(p, end, type, bad) \ |
166 | do { \ |
167 | u32 len; \ |
168 | \ |
169 | ceph_decode_32_safe(p, end, len, bad); \ |
170 | while (len--) \ |
171 | ceph_decode_skip_##type(p, end, bad); \ |
172 | } while (0) |
173 | |
174 | #define ceph_decode_skip_map(p, end, ktype, vtype, bad) \ |
175 | do { \ |
176 | u32 len; \ |
177 | \ |
178 | ceph_decode_32_safe(p, end, len, bad); \ |
179 | while (len--) { \ |
180 | ceph_decode_skip_##ktype(p, end, bad); \ |
181 | ceph_decode_skip_##vtype(p, end, bad); \ |
182 | } \ |
183 | } while (0) |
184 | |
185 | #define ceph_decode_skip_map_of_map(p, end, ktype1, ktype2, vtype2, bad) \ |
186 | do { \ |
187 | u32 len; \ |
188 | \ |
189 | ceph_decode_32_safe(p, end, len, bad); \ |
190 | while (len--) { \ |
191 | ceph_decode_skip_##ktype1(p, end, bad); \ |
192 | ceph_decode_skip_map(p, end, ktype2, vtype2, bad); \ |
193 | } \ |
194 | } while (0) |
195 | |
196 | /* |
197 | * struct ceph_timespec <-> struct timespec64 |
198 | */ |
199 | static inline void ceph_decode_timespec64(struct timespec64 *ts, |
200 | const struct ceph_timespec *tv) |
201 | { |
202 | /* |
203 | * This will still overflow in year 2106. We could extend |
204 | * the protocol to steal two more bits from tv_nsec to |
205 | * add three more 136 year epochs after that the way ext4 |
206 | * does if necessary. |
207 | */ |
208 | ts->tv_sec = (time64_t)le32_to_cpu(tv->tv_sec); |
209 | ts->tv_nsec = (long)le32_to_cpu(tv->tv_nsec); |
210 | } |
211 | static inline void ceph_encode_timespec64(struct ceph_timespec *tv, |
212 | const struct timespec64 *ts) |
213 | { |
214 | tv->tv_sec = cpu_to_le32((u32)ts->tv_sec); |
215 | tv->tv_nsec = cpu_to_le32((u32)ts->tv_nsec); |
216 | } |
217 | |
218 | /* |
219 | * sockaddr_storage <-> ceph_sockaddr |
220 | */ |
221 | #define CEPH_ENTITY_ADDR_TYPE_NONE 0 |
222 | #define CEPH_ENTITY_ADDR_TYPE_LEGACY __cpu_to_le32(1) |
223 | #define CEPH_ENTITY_ADDR_TYPE_MSGR2 __cpu_to_le32(2) |
224 | #define CEPH_ENTITY_ADDR_TYPE_ANY __cpu_to_le32(3) |
225 | |
226 | static inline void ceph_encode_banner_addr(struct ceph_entity_addr *a) |
227 | { |
228 | __be16 ss_family = htons(a->in_addr.ss_family); |
229 | a->in_addr.ss_family = *(__u16 *)&ss_family; |
230 | |
231 | /* Banner addresses require TYPE_NONE */ |
232 | a->type = CEPH_ENTITY_ADDR_TYPE_NONE; |
233 | } |
234 | static inline void ceph_decode_banner_addr(struct ceph_entity_addr *a) |
235 | { |
236 | __be16 ss_family = *(__be16 *)&a->in_addr.ss_family; |
237 | a->in_addr.ss_family = ntohs(ss_family); |
238 | WARN_ON(a->in_addr.ss_family == 512); |
239 | a->type = CEPH_ENTITY_ADDR_TYPE_LEGACY; |
240 | } |
241 | |
242 | extern int ceph_decode_entity_addr(void **p, void *end, |
243 | struct ceph_entity_addr *addr); |
244 | int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2, |
245 | struct ceph_entity_addr *addr); |
246 | |
247 | int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr); |
248 | void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr); |
249 | |
250 | /* |
251 | * encoders |
252 | */ |
253 | static inline void ceph_encode_64(void **p, u64 v) |
254 | { |
255 | put_unaligned_le64(val: v, p: (__le64 *)*p); |
256 | *p += sizeof(u64); |
257 | } |
258 | static inline void ceph_encode_32(void **p, u32 v) |
259 | { |
260 | put_unaligned_le32(val: v, p: (__le32 *)*p); |
261 | *p += sizeof(u32); |
262 | } |
263 | static inline void ceph_encode_16(void **p, u16 v) |
264 | { |
265 | put_unaligned_le16(val: v, p: (__le16 *)*p); |
266 | *p += sizeof(u16); |
267 | } |
268 | static inline void ceph_encode_8(void **p, u8 v) |
269 | { |
270 | *(u8 *)*p = v; |
271 | (*p)++; |
272 | } |
273 | static inline void ceph_encode_copy(void **p, const void *s, int len) |
274 | { |
275 | memcpy(*p, s, len); |
276 | *p += len; |
277 | } |
278 | |
279 | /* |
280 | * filepath, string encoders |
281 | */ |
282 | static inline void ceph_encode_filepath(void **p, void *end, |
283 | u64 ino, const char *path) |
284 | { |
285 | u32 len = path ? strlen(path) : 0; |
286 | BUG_ON(*p + 1 + sizeof(ino) + sizeof(len) + len > end); |
287 | ceph_encode_8(p, v: 1); |
288 | ceph_encode_64(p, v: ino); |
289 | ceph_encode_32(p, v: len); |
290 | if (len) |
291 | memcpy(*p, path, len); |
292 | *p += len; |
293 | } |
294 | |
295 | static inline void ceph_encode_string(void **p, void *end, |
296 | const char *s, u32 len) |
297 | { |
298 | BUG_ON(*p + sizeof(len) + len > end); |
299 | ceph_encode_32(p, v: len); |
300 | if (len) |
301 | memcpy(*p, s, len); |
302 | *p += len; |
303 | } |
304 | |
305 | /* |
306 | * version and length starting block encoders/decoders |
307 | */ |
308 | |
309 | /* current code version (u8) + compat code version (u8) + len of struct (u32) */ |
310 | #define CEPH_ENCODING_START_BLK_LEN 6 |
311 | |
312 | /** |
313 | * ceph_start_encoding - start encoding block |
314 | * @struct_v: current (code) version of the encoding |
315 | * @struct_compat: oldest code version that can decode it |
316 | * @struct_len: length of struct encoding |
317 | */ |
318 | static inline void ceph_start_encoding(void **p, u8 struct_v, u8 struct_compat, |
319 | u32 struct_len) |
320 | { |
321 | ceph_encode_8(p, v: struct_v); |
322 | ceph_encode_8(p, v: struct_compat); |
323 | ceph_encode_32(p, v: struct_len); |
324 | } |
325 | |
326 | /** |
327 | * ceph_start_decoding - start decoding block |
328 | * @v: current version of the encoding that the code supports |
329 | * @name: name of the struct (free-form) |
330 | * @struct_v: out param for the encoding version |
331 | * @struct_len: out param for the length of struct encoding |
332 | * |
333 | * Validates the length of struct encoding, so unsafe ceph_decode_* |
334 | * variants can be used for decoding. |
335 | */ |
336 | static inline int ceph_start_decoding(void **p, void *end, u8 v, |
337 | const char *name, u8 *struct_v, |
338 | u32 *struct_len) |
339 | { |
340 | u8 struct_compat; |
341 | |
342 | ceph_decode_need(p, end, CEPH_ENCODING_START_BLK_LEN, bad); |
343 | *struct_v = ceph_decode_8(p); |
344 | struct_compat = ceph_decode_8(p); |
345 | if (v < struct_compat) { |
346 | pr_warn("got struct_v %d struct_compat %d > %d of %s\n" , |
347 | *struct_v, struct_compat, v, name); |
348 | return -EINVAL; |
349 | } |
350 | |
351 | *struct_len = ceph_decode_32(p); |
352 | ceph_decode_need(p, end, *struct_len, bad); |
353 | return 0; |
354 | |
355 | bad: |
356 | return -ERANGE; |
357 | } |
358 | |
359 | #define ceph_encode_need(p, end, n, bad) \ |
360 | do { \ |
361 | if (!likely(ceph_has_room(p, end, n))) \ |
362 | goto bad; \ |
363 | } while (0) |
364 | |
365 | #define ceph_encode_64_safe(p, end, v, bad) \ |
366 | do { \ |
367 | ceph_encode_need(p, end, sizeof(u64), bad); \ |
368 | ceph_encode_64(p, v); \ |
369 | } while (0) |
370 | #define ceph_encode_32_safe(p, end, v, bad) \ |
371 | do { \ |
372 | ceph_encode_need(p, end, sizeof(u32), bad); \ |
373 | ceph_encode_32(p, v); \ |
374 | } while (0) |
375 | #define ceph_encode_16_safe(p, end, v, bad) \ |
376 | do { \ |
377 | ceph_encode_need(p, end, sizeof(u16), bad); \ |
378 | ceph_encode_16(p, v); \ |
379 | } while (0) |
380 | #define ceph_encode_8_safe(p, end, v, bad) \ |
381 | do { \ |
382 | ceph_encode_need(p, end, sizeof(u8), bad); \ |
383 | ceph_encode_8(p, v); \ |
384 | } while (0) |
385 | |
386 | #define ceph_encode_copy_safe(p, end, pv, n, bad) \ |
387 | do { \ |
388 | ceph_encode_need(p, end, n, bad); \ |
389 | ceph_encode_copy(p, pv, n); \ |
390 | } while (0) |
391 | #define ceph_encode_string_safe(p, end, s, n, bad) \ |
392 | do { \ |
393 | ceph_encode_need(p, end, n, bad); \ |
394 | ceph_encode_string(p, end, s, n); \ |
395 | } while (0) |
396 | |
397 | |
398 | #endif |
399 | |