Future use of the API can benefit from bounds checking. Signed-off-by: Dan Aloni <d...@kernelim.com> --- include/linux/base64-armor.h | 17 +++++++++++------ lib/base64-armor.c | 20 ++++++++++++++++++-- net/ceph/crypto.c | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/include/linux/base64-armor.h b/include/linux/base64-armor.h index e5160c77bb2f..bb0b4491799e 100644 --- a/include/linux/base64-armor.h +++ b/include/linux/base64-armor.h @@ -8,11 +8,13 @@ * not contain newlines, depending on input length. * * @dst: Beginning of the destination buffer. + * @dst_max: Maximum amount of bytes to write to the destination buffer. * @src: Beginning of the source buffer. * @end: Sentinel for the source buffer, pointing one byte after the * last byte to be encoded. * - * Returns the number of bytes written to the destination buffer. + * Returns the number of bytes written to the destination buffer, or + * an error of the output buffer is insufficient in size. * * _Neither_ the input or output are expected to be NULL-terminated. * @@ -22,19 +24,21 @@ * * See base64_encode_buffer_bound below. */ - -extern int base64_armor(char *dst, const char *src, const char *end); +extern int base64_armor(char *dst, int dst_max, const char *src, + const char *end); /** * base64_unarmor: Perform armored base64 decoding. * * @dst: Beginning of the destination buffer. + * @dst_max: Maximum amount of bytes to write to the destination buffer. * @src: Beginning of the source buffer * @end: Sentinel for the source buffer, pointing one byte after the * last byte to be encoded. * - * Returns the number of bytes written to the destination buffer, or - * -EINVAL if the source buffer contains invalid bytes. + * Returns the number of bytes written to the destination buffer, + * -EINVAL if the source buffer contains invalid bytes, or -ENOSPC + * if the output buffer is insufficient in size. * * _Neither_ the input or output are expected to be NULL-terminated. * @@ -43,7 +47,8 @@ extern int base64_armor(char *dst, const char *src, const char *end); * * See base64_decode_buffer_bound below. */ -extern int base64_unarmor(char *dst, const char *src, const char *end); +extern int base64_unarmor(char *dst, int dst_max, const char *src, + const char *end); /* diff --git a/lib/base64-armor.c b/lib/base64-armor.c index e07d25ac2850..f4a289f8da6a 100644 --- a/lib/base64-armor.c +++ b/lib/base64-armor.c @@ -33,7 +33,7 @@ static int decode_bits(char c) return -EINVAL; } -int base64_armor(char *dst, const char *src, const char *end) +int base64_armor(char *dst, int dst_max, const char *src, const char *end) { int olen = 0; int line = 0; @@ -42,6 +42,8 @@ int base64_armor(char *dst, const char *src, const char *end) unsigned char a, b, c; a = *src++; + if (dst_max < 4) + return -ENOSPC; *dst++ = encode_bits(a >> 2); if (src < end) { b = *src++; @@ -62,17 +64,22 @@ int base64_armor(char *dst, const char *src, const char *end) } olen += 4; line += 4; + dst_max -= 4; + if (line == 64) { line = 0; + if (dst_max < 1) + return -ENOSPC; *(dst++) = '\n'; olen++; + dst_max--; } } return olen; } EXPORT_SYMBOL(base64_unarmor); -int base64_unarmor(char *dst, const char *src, const char *end) +int base64_unarmor(char *dst, int dst_max, const char *src, const char *end) { int olen = 0; @@ -92,13 +99,22 @@ int base64_unarmor(char *dst, const char *src, const char *end) if (a < 0 || b < 0 || c < 0 || d < 0) return -EINVAL; + if (dst_max < 1) + return -ENOSPC; *dst++ = (a << 2) | (b >> 4); + dst_max--; if (src[2] == '=') return olen + 1; + if (dst_max < 1) + return -ENOSPC; *dst++ = ((b & 15) << 4) | (c >> 2); + dst_max--; if (src[3] == '=') return olen + 2; + if (dst_max < 1) + return -ENOSPC; *dst++ = ((c & 3) << 6) | d; + dst_max--; olen += 3; src += 4; } diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 25e04e3b1aa4..f7c75368989a 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -116,7 +116,7 @@ int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey) buf = kmalloc(blen, GFP_NOFS); if (!buf) return -ENOMEM; - blen = base64_unarmor(buf, inkey, inkey+inlen); + blen = base64_unarmor(buf, blen, inkey, inkey+inlen); if (blen < 0) { kfree(buf); return blen; -- 2.14.3