key.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /* Key to pathname encoder
  3. *
  4. * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
  5. * Written by David Howells ([email protected])
  6. */
  7. #include <linux/slab.h>
  8. #include "internal.h"
  9. static const char cachefiles_charmap[64] =
  10. "0123456789" /* 0 - 9 */
  11. "abcdefghijklmnopqrstuvwxyz" /* 10 - 35 */
  12. "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /* 36 - 61 */
  13. "_-" /* 62 - 63 */
  14. ;
  15. static const char cachefiles_filecharmap[256] = {
  16. /* we skip space and tab and control chars */
  17. [33 ... 46] = 1, /* '!' -> '.' */
  18. /* we skip '/' as it's significant to pathwalk */
  19. [48 ... 127] = 1, /* '0' -> '~' */
  20. };
  21. static inline unsigned int how_many_hex_digits(unsigned int x)
  22. {
  23. return x ? round_up(ilog2(x) + 1, 4) / 4 : 0;
  24. }
  25. /*
  26. * turn the raw key into something cooked
  27. * - the key may be up to NAME_MAX in length (including the length word)
  28. * - "base64" encode the strange keys, mapping 3 bytes of raw to four of
  29. * cooked
  30. * - need to cut the cooked key into 252 char lengths (189 raw bytes)
  31. */
  32. bool cachefiles_cook_key(struct cachefiles_object *object)
  33. {
  34. const u8 *key = fscache_get_key(object->cookie), *kend;
  35. unsigned char ch;
  36. unsigned int acc, i, n, nle, nbe, keylen = object->cookie->key_len;
  37. unsigned int b64len, len, print, pad;
  38. char *name, sep;
  39. _enter(",%u,%*phN", keylen, keylen, key);
  40. BUG_ON(keylen > NAME_MAX - 3);
  41. print = 1;
  42. for (i = 0; i < keylen; i++) {
  43. ch = key[i];
  44. print &= cachefiles_filecharmap[ch];
  45. }
  46. /* If the path is usable ASCII, then we render it directly */
  47. if (print) {
  48. len = 1 + keylen;
  49. name = kmalloc(len + 1, GFP_KERNEL);
  50. if (!name)
  51. return false;
  52. name[0] = 'D'; /* Data object type, string encoding */
  53. memcpy(name + 1, key, keylen);
  54. goto success;
  55. }
  56. /* See if it makes sense to encode it as "hex,hex,hex" for each 32-bit
  57. * chunk. We rely on the key having been padded out to a whole number
  58. * of 32-bit words.
  59. */
  60. n = round_up(keylen, 4);
  61. nbe = nle = 0;
  62. for (i = 0; i < n; i += 4) {
  63. u32 be = be32_to_cpu(*(__be32 *)(key + i));
  64. u32 le = le32_to_cpu(*(__le32 *)(key + i));
  65. nbe += 1 + how_many_hex_digits(be);
  66. nle += 1 + how_many_hex_digits(le);
  67. }
  68. b64len = DIV_ROUND_UP(keylen, 3);
  69. pad = b64len * 3 - keylen;
  70. b64len = 2 + b64len * 4; /* Length if we base64-encode it */
  71. _debug("len=%u nbe=%u nle=%u b64=%u", keylen, nbe, nle, b64len);
  72. if (nbe < b64len || nle < b64len) {
  73. unsigned int nlen = min(nbe, nle) + 1;
  74. name = kmalloc(nlen, GFP_KERNEL);
  75. if (!name)
  76. return false;
  77. sep = (nbe <= nle) ? 'S' : 'T'; /* Encoding indicator */
  78. len = 0;
  79. for (i = 0; i < n; i += 4) {
  80. u32 x;
  81. if (nbe <= nle)
  82. x = be32_to_cpu(*(__be32 *)(key + i));
  83. else
  84. x = le32_to_cpu(*(__le32 *)(key + i));
  85. name[len++] = sep;
  86. if (x != 0)
  87. len += snprintf(name + len, nlen - len, "%x", x);
  88. sep = ',';
  89. }
  90. goto success;
  91. }
  92. /* We need to base64-encode it */
  93. name = kmalloc(b64len + 1, GFP_KERNEL);
  94. if (!name)
  95. return false;
  96. name[0] = 'E';
  97. name[1] = '0' + pad;
  98. len = 2;
  99. kend = key + keylen;
  100. do {
  101. acc = *key++;
  102. if (key < kend) {
  103. acc |= *key++ << 8;
  104. if (key < kend)
  105. acc |= *key++ << 16;
  106. }
  107. name[len++] = cachefiles_charmap[acc & 63];
  108. acc >>= 6;
  109. name[len++] = cachefiles_charmap[acc & 63];
  110. acc >>= 6;
  111. name[len++] = cachefiles_charmap[acc & 63];
  112. acc >>= 6;
  113. name[len++] = cachefiles_charmap[acc & 63];
  114. } while (key < kend);
  115. success:
  116. name[len] = 0;
  117. object->d_name = name;
  118. object->d_name_len = len;
  119. _leave(" = %s", object->d_name);
  120. return true;
  121. }