Fix: event notification capture error handling
[lttng-modules.git] / src / lib / msgpack / msgpack.c
index 0803bc657646b49f4dcbc7c3ffad244a0ec33a44..b9bac85f64ff8766ef6ec032bf9cee420ff8229d 100644 (file)
@@ -20,7 +20,6 @@
 
 #define _GNU_SOURCE
 #define _LGPL_SOURCE
-#include <stddef.h>
 
 #define MSGPACK_FIXSTR_ID_MASK         0xA0
 #define MSGPACK_FIXMAP_ID_MASK         0x80
 #include <linux/bug.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#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)
 {
@@ -143,20 +171,6 @@ static inline int lttng_msgpack_append_u64(
        return lttng_msgpack_append_buffer(writer, (uint8_t *) &value, sizeof(value));
 }
 
-static inline int lttng_msgpack_append_f64(
-               struct lttng_msgpack_writer *writer, double value)
-{
-
-       union {
-               double d;
-               uint64_t u;
-       } u;
-
-       u.d = value;
-
-       return lttng_msgpack_append_u64(writer, u.u);
-}
-
 static inline int lttng_msgpack_append_i8(
                struct lttng_msgpack_writer *writer, int8_t value)
 {
@@ -181,23 +195,6 @@ static inline int lttng_msgpack_append_i64(
        return lttng_msgpack_append_u64(writer, (uint64_t) value);
 }
 
-static inline int lttng_msgpack_encode_f64(
-               struct lttng_msgpack_writer *writer, double value)
-{
-       int ret;
-
-       ret = lttng_msgpack_append_u8(writer, MSGPACK_FLOAT64_ID);
-       if (ret)
-               goto end;
-
-       ret = lttng_msgpack_append_f64(writer, value);
-       if (ret)
-               goto end;
-
-end:
-       return ret;
-}
-
 static inline int lttng_msgpack_encode_fixmap(
                struct lttng_msgpack_writer *writer, uint8_t count)
 {
@@ -312,11 +309,58 @@ 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;
 
-       if (count < 0 || count >= (1 << 16)) {
+       if (count >= (1 << 16)) {
                ret = -1;
                goto end;
        }
@@ -343,7 +387,7 @@ int lttng_msgpack_begin_array(
 {
        int ret;
 
-       if (count < 0 || count >= (1 << 16)) {
+       if (count >= (1 << 16)) {
                ret = -1;
                goto end;
        }
@@ -370,7 +414,8 @@ int lttng_msgpack_write_str(struct lttng_msgpack_writer *writer,
 {
        int ret;
        size_t length = strlen(str);
-       if (length < 0 || length >= (1 << 16)) {
+
+       if (length >= (1 << 16)) {
                ret = -1;
                goto end;
        }
@@ -384,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);
@@ -492,9 +567,16 @@ end:
        return ret;
 }
 
-int lttng_msgpack_write_double(struct lttng_msgpack_writer *writer, double value)
+int lttng_msgpack_save_writer_pos(struct lttng_msgpack_writer *writer, uint8_t **pos)
+{
+       *pos = writer->write_pos;
+       return 0;
+}
+
+int lttng_msgpack_restore_writer_pos(struct lttng_msgpack_writer *writer, uint8_t *pos)
 {
-       return lttng_msgpack_encode_f64(writer, value);
+       writer->write_pos = pos;
+       return 0;
 }
 
 void lttng_msgpack_writer_init(struct lttng_msgpack_writer *writer,
This page took 0.025384 seconds and 4 git commands to generate.