changeset 475:0ade7fb71c8c

Import Xavier's patches
author Louis Opter <kalessin@kalessin.fr>
date Sat, 25 Jun 2016 17:00:58 -0700
parents 59061c76f3b2
children e71203a47b63
files fix_stack_overflow_in_jsmn.patch fix_stack_underflow_in_jsonrpc.patch series use_systemd_user_group_keys.patch
diffstat 4 files changed, 269 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fix_stack_overflow_in_jsmn.patch	Sat Jun 25 17:00:58 2016 -0700
@@ -0,0 +1,229 @@
+# HG changeset patch
+# User Xavier Deguillard <deguilx@gmail.com>
+# Parent  69e2492f799fef0a248f7e0b2d46e050d1612644
+Fix a stack overflow in JSMN when parsing `null'
+
+Also, start updating that changelog!
+
+diff --git a/core/client.c b/core/client.c
+--- a/core/client.c
++++ b/core/client.c
+@@ -66,8 +66,6 @@
+     }
+ }
+ 
+-#pragma GCC diagnostic push
+-#pragma GCC diagnostic ignored "-Wswitch"
+ static void
+ lgtd_client_read_callback(struct bufferevent *bev, void *ctx)
+ {
+@@ -89,7 +87,7 @@
+         jsmn_parser jsmn_ctx;
+     parse_after_realloc:
+         jsmn_init(&jsmn_ctx);
+-        jsmnerr_t rv = jsmn_parse(&jsmn_ctx, buf, nbytes, tokens, ntokens);
++        int rv = jsmn_parse(&jsmn_ctx, buf, nbytes, tokens, ntokens);
+         switch (rv) {
+         case JSMN_ERROR_NOMEM:
+         case JSMN_ERROR_INVAL:
+@@ -138,7 +136,6 @@
+         nbytes = evbuffer_get_contiguous_space(input);
+     } while (nbytes);
+ }
+-#pragma GCC diagnostic pop
+ 
+ static void
+ lgtd_client_event_callback(struct bufferevent *bev, short events, void *ctx)
+diff --git a/core/jsmn.c b/core/jsmn.c
+--- a/core/jsmn.c
++++ b/core/jsmn.c
+@@ -20,8 +20,6 @@
+  * THE SOFTWARE.
+  */
+ 
+-#include <stdlib.h>
+-
+ #include "jsmn.h"
+ 
+ /**
+@@ -56,7 +54,7 @@
+ /**
+  * Fills next available token with JSON primitive.
+  */
+-static jsmnerr_t jsmn_parse_primitive(jsmn_parser *parser, const char *js,
++static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
+ 		size_t len, jsmntok_t *tokens, size_t num_tokens) {
+ 	jsmntok_t *token;
+ 	int start;
+@@ -103,9 +101,9 @@
+ }
+ 
+ /**
+- * Filsl next token with JSON string.
++ * Fills next token with JSON string.
+  */
+-static jsmnerr_t jsmn_parse_string(jsmn_parser *parser, const char *js,
++static int jsmn_parse_string(jsmn_parser *parser, const char *js,
+ 		size_t len, jsmntok_t *tokens, size_t num_tokens) {
+ 	jsmntok_t *token;
+ 
+@@ -172,12 +170,12 @@
+ /**
+  * Parse JSON string and fill tokens.
+  */
+-jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
++int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+ 		jsmntok_t *tokens, unsigned int num_tokens) {
+-	jsmnerr_t r;
++	int r;
+ 	int i;
+ 	jsmntok_t *token;
+-	int count = 0;
++	int count = parser->toknext;
+ 
+ 	for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
+ 		char c;
+@@ -262,7 +260,7 @@
+ 				parser->toksuper = parser->toknext - 1;
+ 				break;
+ 			case ',':
+-				if (tokens != NULL &&
++				if (tokens != NULL && parser->toksuper != -1 &&
+ 						tokens[parser->toksuper].type != JSMN_ARRAY &&
+ 						tokens[parser->toksuper].type != JSMN_OBJECT) {
+ #ifdef JSMN_PARENT_LINKS
+@@ -285,7 +283,7 @@
+ 			case '5': case '6': case '7' : case '8': case '9':
+ 			case 't': case 'f': case 'n' :
+ 				/* And they must not be keys of the object */
+-				if (tokens != NULL) {
++				if (tokens != NULL && parser->toksuper != -1) {
+ 					jsmntok_t *t = &tokens[parser->toksuper];
+ 					if (t->type == JSMN_OBJECT ||
+ 							(t->type == JSMN_STRING && t->size != 0)) {
+@@ -311,10 +309,12 @@
+ 		}
+ 	}
+ 
+-	for (i = parser->toknext - 1; i >= 0; i--) {
+-		/* Unmatched opened object or array */
+-		if (tokens[i].start != -1 && tokens[i].end == -1) {
+-			return JSMN_ERROR_PART;
++	if (tokens != NULL) {
++		for (i = parser->toknext - 1; i >= 0; i--) {
++			/* Unmatched opened object or array */
++			if (tokens[i].start != -1 && tokens[i].end == -1) {
++				return JSMN_ERROR_PART;
++			}
+ 		}
+ 	}
+ 
+diff --git a/core/jsmn.h b/core/jsmn.h
+--- a/core/jsmn.h
++++ b/core/jsmn.h
+@@ -37,20 +37,21 @@
+  * 	o Other primitive: number, boolean (true/false) or null
+  */
+ typedef enum {
+-	JSMN_PRIMITIVE = 0,
++	JSMN_UNDEFINED = 0,
+ 	JSMN_OBJECT = 1,
+ 	JSMN_ARRAY = 2,
+-	JSMN_STRING = 3
++	JSMN_STRING = 3,
++	JSMN_PRIMITIVE = 4
+ } jsmntype_t;
+ 
+-typedef enum {
++enum jsmnerr {
+ 	/* Not enough tokens were provided */
+ 	JSMN_ERROR_NOMEM = -1,
+ 	/* Invalid character inside JSON string */
+ 	JSMN_ERROR_INVAL = -2,
+ 	/* The string is not a full JSON packet, more bytes expected */
+ 	JSMN_ERROR_PART = -3
+-} jsmnerr_t;
++};
+ 
+ /**
+  * JSON token description.
+@@ -87,7 +88,7 @@
+  * Run JSON parser. It parses a JSON data string into and array of tokens, each describing
+  * a single JSON object.
+  */
+-jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
++int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
+ 		jsmntok_t *tokens, unsigned int num_tokens);
+ 
+ #ifdef __cplusplus
+diff --git a/core/pipe.c b/core/pipe.c
+--- a/core/pipe.c
++++ b/core/pipe.c
+@@ -68,8 +68,6 @@
+ 
+ static void lgtd_command_pipe_reset(struct lgtd_command_pipe *);
+ 
+-#pragma GCC diagnostic push
+-#pragma GCC diagnostic ignored "-Wswitch"
+ static void
+ lgtd_command_pipe_read_callback(evutil_socket_t socket, short events, void *ctx)
+ {
+@@ -106,7 +104,7 @@
+             ssize_t bufsz = evbuffer_get_length(pipe->read_buf);
+         parse_after_realloc:
+             jsmn_init(&jsmn_ctx);
+-            jsmnerr_t rv = jsmn_parse(&jsmn_ctx, buf, bufsz, tokens, ntokens);
++            int rv = jsmn_parse(&jsmn_ctx, buf, bufsz, tokens, ntokens);
+             switch (rv) {
+             case JSMN_ERROR_NOMEM:
+             case JSMN_ERROR_INVAL:
+@@ -153,7 +151,6 @@
+ 
+     lgtd_command_pipe_reset(pipe);
+ }
+-#pragma GCC diagnostic pop
+ 
+ static bool
+ _lgtd_command_pipe_open(const char *path)
+diff --git a/docs/changelog.rst b/docs/changelog.rst
+--- a/docs/changelog.rst
++++ b/docs/changelog.rst
+@@ -11,6 +11,38 @@
+   are added in a backwards-compatible manner;
+ - PATCH version gets incremented for backwards-compatible bug fixes.
+ 
++1.2.0 (unreleased)
++------------------
++
++This release doesn't have any new user-facing feature but packs a bunch of fixes
++and improvements, both in the code but also the documentation and examples.
++
++Also worth noting, is the full continuous integration pipeline that has been
++setup behind the scenes. It will hopefully make it a lot easier to work on the
++project.
++
++Fixes
++~~~~~
++
++- A couple of crash/security fixes by , one being in jsmn_
++  (JSON parser) which has been upgraded to its latest version;
++- FreeBSD build (more BSD fixes to come though, see GH-16_);
++- WIP…
++
++.. _jsmn: https://github.com/zserge/jsmn
++.. _GH-16: https://github.com/lopter/lightsd/issues/16
++
++Acknowledgments
++~~~~~~~~~~~~~~~
++
++Thanks to:
++
++- `Xavier Deguillard`_ for his contributions, additional automated tests will be
++  setup to make crashes and security issues much harder to creep in;
++- All the people who have been trying the project and reporting issues!
++
++.. _Xavier Deguillard: https://github.com/Rip-Rip
++
+ 1.1.2 (2015-11-30)
+ ------------------
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fix_stack_underflow_in_jsonrpc.patch	Sat Jun 25 17:00:58 2016 -0700
@@ -0,0 +1,17 @@
+# HG changeset patch
+# User Xavier Deguillard <deguilx@gmail.com>
+# Parent  a7efed63bc95fd9efac9dbb43cbdf93e1064fe9b
+Fix stack underflow in jsonrpc
+
+diff --git a/core/jsonrpc.c b/core/jsonrpc.c
+--- a/core/jsonrpc.c
++++ b/core/jsonrpc.c
+@@ -400,7 +400,7 @@
+     }
+ 
+     for (int si = 0; si != schema_size; si++) {
+-        if (!schema[si].optional) {
++        if (!schema[si].optional && schema[si].value_offset != -1) {
+             const jsmntok_t *seen = LGTD_JSONRPC_GET_JSMNTOK(
+                 output, schema[si].value_offset
+             );
--- a/series	Sat Jun 25 16:06:14 2016 -0700
+++ b/series	Sat Jun 25 17:00:58 2016 -0700
@@ -2,6 +2,9 @@
 dont_use_time_t.patch
 do_not_warn_on_unknown_packets.patch
 pkgbuild_fix.patch
+fix_stack_underflow_in_jsonrpc.patch
+fix_stack_overflow_in_jsmn.patch
+use_systemd_user_group_keys.patch
 add_power_transition.patch
 open_gateway_on_any_bulb_response.patch #+future
 make_gateway_write_callbacks_low_priority.patch #+future
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/use_systemd_user_group_keys.patch	Sat Jun 25 17:00:58 2016 -0700
@@ -0,0 +1,20 @@
+# HG changeset patch
+# User Xavier Deguillard <deguilx@gmail.com>
+# Parent  bc553481b7df85b46889177adb80d0428b98130c
+Use systemd's User/Group keys
+
+diff --git a/dist/lightsd.service b/dist/lightsd.service
+--- a/dist/lightsd.service
++++ b/dist/lightsd.service
+@@ -3,7 +3,10 @@
+ After=network.target
+ 
+ [Service]
+-ExecStart=/usr/bin/lightsd -t -v warning -u lightsd -s %t/lightsd/socket -c %t/lightsd/pipe
++ExecStart=/usr/bin/lightsd -t -v warning -s %t/lightsd/socket -c %t/lightsd/pipe
++User=lightsd
++Group=lightsd
++RuntimeDirectory=lightsd
+ Restart=on-failure
+ 
+ [Install]