From: Mathieu Desnoyers Date: Tue, 6 Sep 2022 15:57:58 +0000 (-0400) Subject: Implement lttng_msgpack_write_user_str X-Git-Url: https://git.lttng.org./?a=commitdiff_plain;h=cf1798f4db44d6dab99038fe26a96d27a606e813;p=lttng-modules.git Implement lttng_msgpack_write_user_str Implement lttng_msgpack_write_user_str to allow safely capturing user-space strings. Signed-off-by: Mathieu Desnoyers Change-Id: I0354382cdd599b041fd20e59bb673fda7d72b2be --- diff --git a/include/lttng/msgpack.h b/include/lttng/msgpack.h index 0c63f1ba..f667db6c 100644 --- a/include/lttng/msgpack.h +++ b/include/lttng/msgpack.h @@ -50,6 +50,8 @@ int lttng_msgpack_write_signed_integer( struct lttng_msgpack_writer *writer, int64_t value); int lttng_msgpack_write_str(struct lttng_msgpack_writer *writer, const char *value); +int lttng_msgpack_write_user_str(struct lttng_msgpack_writer *writer, + const char __user *value); int lttng_msgpack_begin_map(struct lttng_msgpack_writer *writer, size_t count); int lttng_msgpack_end_map(struct lttng_msgpack_writer *writer); int lttng_msgpack_begin_array( diff --git a/src/lib/msgpack/msgpack.c b/src/lib/msgpack/msgpack.c index fbbd96f0..e7ff1e39 100644 --- a/src/lib/msgpack/msgpack.c +++ b/src/lib/msgpack/msgpack.c @@ -57,6 +57,7 @@ #include #include +#include #define INT8_MIN (-128) #define INT16_MIN (-32767-1) @@ -113,6 +114,33 @@ end: return ret; } +static inline int lttng_msgpack_append_user_buffer( + struct lttng_msgpack_writer *writer, + const uint8_t __user *ubuf, + size_t length) +{ + int ret = 0; + + lttng_msgpack_assert(ubuf); + + /* Ensure we are not trying to write after the end of the buffer. */ + if (writer->write_pos + length > writer->end_write_pos) { + ret = -1; + goto end; + } + + if (lttng_copy_from_user_check_nofault(writer->write_pos, ubuf, length)) { + /* + * After a successful strlen user, a page fault on copy is handled by + * considering the string as empty, returning a success. + */ + goto end; + } + writer->write_pos += length; +end: + return ret; +} + static inline int lttng_msgpack_append_u8( struct lttng_msgpack_writer *writer, uint8_t value) { @@ -281,6 +309,53 @@ end: return ret; } +static inline int lttng_msgpack_encode_user_fixstr( + struct lttng_msgpack_writer *writer, + const char __user *ustr, + uint8_t len) +{ + int ret; + + lttng_msgpack_assert(len <= MSGPACK_FIXSTR_MAX_LENGTH); + + ret = lttng_msgpack_append_u8(writer, MSGPACK_FIXSTR_ID_MASK | len); + if (ret) + goto end; + + ret = lttng_msgpack_append_user_buffer(writer, (uint8_t __user *) ustr, len); + if (ret) + goto end; + +end: + return ret; +} + +static inline int lttng_msgpack_encode_user_str16( + struct lttng_msgpack_writer *writer, + const char __user *ustr, + uint16_t len) +{ + int ret; + + lttng_msgpack_assert(len > MSGPACK_FIXSTR_MAX_LENGTH); + + ret = lttng_msgpack_append_u8(writer, MSGPACK_STR16_ID); + if (ret) + goto end; + + ret = lttng_msgpack_append_u16(writer, len); + if (ret) + goto end; + + ret = lttng_msgpack_append_user_buffer(writer, (uint8_t __user *) ustr, len); + if (ret) + goto end; + +end: + return ret; +} + + int lttng_msgpack_begin_map(struct lttng_msgpack_writer *writer, size_t count) { int ret; @@ -354,6 +429,36 @@ end: return ret; } +/* + * Provide the same behavior on lttng_strlen_user_inatomic page fault as the + * lttng ring buffer: truncate the last string character. + */ +int lttng_msgpack_write_user_str(struct lttng_msgpack_writer *writer, + const char __user *ustr) +{ + int ret; + size_t length = max_t(size_t, lttng_strlen_user_inatomic(ustr), 1); + + if (length >= (1 << 16)) { + ret = -1; + goto end; + } + + /* + * Handle empty string and strlen user page fault as empty string. + */ + if (length == 1) + return lttng_msgpack_write_str(writer, ""); + + if (length <= MSGPACK_FIXSTR_MAX_LENGTH) + ret = lttng_msgpack_encode_user_fixstr(writer, ustr, length); + else + ret = lttng_msgpack_encode_user_str16(writer, ustr, length); + +end: + return ret; +} + int lttng_msgpack_write_nil(struct lttng_msgpack_writer *writer) { return lttng_msgpack_append_u8(writer, MSGPACK_NIL_ID);