Implement lttng_msgpack_write_user_str
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Tue, 6 Sep 2022 15:57:58 +0000 (11:57 -0400)
committerMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Wed, 7 Sep 2022 20:07:38 +0000 (16:07 -0400)
Implement lttng_msgpack_write_user_str to allow safely capturing
user-space strings.

Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Change-Id: I0354382cdd599b041fd20e59bb673fda7d72b2be

include/lttng/msgpack.h
src/lib/msgpack/msgpack.c

index 0c63f1ba869d3b41eb95a7477cf8ab354c437f1a..f667db6ced654fb1c00e4fa7f3ef749638b25d9a 100644 (file)
@@ -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(
index fbbd96f0f97f22041a75342ebd40fb953ceeeff3..e7ff1e393cf33ac67625dbed2193edd475569cd1 100644 (file)
@@ -57,6 +57,7 @@
 #include <asm/byteorder.h>
 
 #include <lttng/msgpack.h>
+#include <lttng/probe-user.h>
 
 #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);
This page took 0.029639 seconds and 4 git commands to generate.