399 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2#ifndef __CEPH_DECODE_H3#define __CEPH_DECODE_H4 5#include <linux/err.h>6#include <linux/bug.h>7#include <linux/slab.h>8#include <linux/time.h>9#include <linux/unaligned.h>10 11#include <linux/ceph/types.h>12 13/*14 * in all cases,15 * void **p pointer to position pointer16 * void *end pointer to end of buffer (last byte + 1)17 */18 19static inline u64 ceph_decode_64(void **p)20{21 u64 v = get_unaligned_le64(*p);22 *p += sizeof(u64);23 return v;24}25static inline u32 ceph_decode_32(void **p)26{27 u32 v = get_unaligned_le32(*p);28 *p += sizeof(u32);29 return v;30}31static inline u16 ceph_decode_16(void **p)32{33 u16 v = get_unaligned_le16(*p);34 *p += sizeof(u16);35 return v;36}37static inline u8 ceph_decode_8(void **p)38{39 u8 v = *(u8 *)*p;40 (*p)++;41 return v;42}43static 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 */52static 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, and92 * decode the string into it. The resulting string will always be93 * terminated with '\0'. If successful, *p will be advanced94 * past the decoded data. Also, if lenp is not a null pointer, the95 * length (not including the terminating '\0') will be recorded in96 * *lenp. Note that a zero-length string is a valid return value.97 *98 * Returns a pointer to the newly-allocated string buffer, or a99 * pointer-coded errno if an error occurs. Neither *p nor *lenp100 * 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 or104 * beyond the "end" pointer provided (-ERANGE)105 * - memory could not be allocated for the result (-ENOMEM)106 */107static inline char *ceph_extract_encoded_string(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(&sp, end, len))116 goto bad;117 118 buf = kmalloc(len + 1, gfp);119 if (!buf)120 return ERR_PTR(-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 132bad:133 return ERR_PTR(-ERANGE);134}135 136/*137 * skip helpers138 */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) \146ceph_decode_skip_n(p, end, sizeof(u64), bad)147 148#define ceph_decode_skip_32(p, end, bad) \149ceph_decode_skip_n(p, end, sizeof(u32), bad)150 151#define ceph_decode_skip_16(p, end, bad) \152ceph_decode_skip_n(p, end, sizeof(u16), bad)153 154#define ceph_decode_skip_8(p, end, bad) \155ceph_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 timespec64198 */199static 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 extend204 * the protocol to steal two more bits from tv_nsec to205 * add three more 136 year epochs after that the way ext4206 * 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}211static 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_sockaddr220 */221#define CEPH_ENTITY_ADDR_TYPE_NONE 0222#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 226static 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}234static 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 242extern int ceph_decode_entity_addr(void **p, void *end,243 struct ceph_entity_addr *addr);244int ceph_decode_entity_addrvec(void **p, void *end, bool msgr2,245 struct ceph_entity_addr *addr);246 247int ceph_entity_addr_encoding_len(const struct ceph_entity_addr *addr);248void ceph_encode_entity_addr(void **p, const struct ceph_entity_addr *addr);249 250/*251 * encoders252 */253static inline void ceph_encode_64(void **p, u64 v)254{255 put_unaligned_le64(v, (__le64 *)*p);256 *p += sizeof(u64);257}258static inline void ceph_encode_32(void **p, u32 v)259{260 put_unaligned_le32(v, (__le32 *)*p);261 *p += sizeof(u32);262}263static inline void ceph_encode_16(void **p, u16 v)264{265 put_unaligned_le16(v, (__le16 *)*p);266 *p += sizeof(u16);267}268static inline void ceph_encode_8(void **p, u8 v)269{270 *(u8 *)*p = v;271 (*p)++;272}273static 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 encoders281 */282static 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, 1);288 ceph_encode_64(p, ino);289 ceph_encode_32(p, len);290 if (len)291 memcpy(*p, path, len);292 *p += len;293}294 295static 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, len);300 if (len)301 memcpy(*p, s, len);302 *p += len;303}304 305/*306 * version and length starting block encoders/decoders307 */308 309/* current code version (u8) + compat code version (u8) + len of struct (u32) */310#define CEPH_ENCODING_START_BLK_LEN 6311 312/**313 * ceph_start_encoding - start encoding block314 * @struct_v: current (code) version of the encoding315 * @struct_compat: oldest code version that can decode it316 * @struct_len: length of struct encoding317 */318static inline void ceph_start_encoding(void **p, u8 struct_v, u8 struct_compat,319 u32 struct_len)320{321 ceph_encode_8(p, struct_v);322 ceph_encode_8(p, struct_compat);323 ceph_encode_32(p, struct_len);324}325 326/**327 * ceph_start_decoding - start decoding block328 * @v: current version of the encoding that the code supports329 * @name: name of the struct (free-form)330 * @struct_v: out param for the encoding version331 * @struct_len: out param for the length of struct encoding332 *333 * Validates the length of struct encoding, so unsafe ceph_decode_*334 * variants can be used for decoding.335 */336static 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 355bad: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#endif399