Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Stone <michael@laptop.org>2009-12-30 03:11:22 (GMT)
committer Michael Stone <michael@laptop.org>2009-12-30 03:11:22 (GMT)
commitf2e593724f6e6ca613a1b2dee89443d1a08396b8 (patch)
treea8b9d9b55827e91cd70aac378f9f786f21506324
parentc13a583b283e396369065ea95442500deacc6ea3 (diff)
Fix an off-by-one error in format_buf().
format_buf had an off-by-one error which would result in silent output truncation. Fix the error and add a test case.
-rw-r--r--rainbow/nss/Makefile6
-rw-r--r--rainbow/nss/buf.c28
-rw-r--r--rainbow/nss/test_format_buf.c78
3 files changed, 100 insertions, 12 deletions
diff --git a/rainbow/nss/Makefile b/rainbow/nss/Makefile
index a733a5e..c4ff2ea 100644
--- a/rainbow/nss/Makefile
+++ b/rainbow/nss/Makefile
@@ -22,8 +22,9 @@ GIDS_OBJS = gids.o
TEST_SLIST_OBJS = test_slist.o slist.o
TEST_ENDGRENT_OBJS = test_endgrent.o
TEST_NAT_OBJS = test_nat.o nat.o
+TEST_FORMAT_BUF_OBJS = test_format_buf.o buf.o
ALL_OBJS = $(RAINBOW_OBJS) $(UIDS_OBJS) $(GIDS_OBJS) $(TEST_SLIST_OBJS) $(TEST_NAT_OBJS)
-BINARIES = libnss_rainbow.so.2 uids gids test_slist test_nat test_endgrent
+BINARIES = libnss_rainbow.so.2 uids gids test_slist test_nat test_endgrent test_format_buf
# targets
@@ -52,6 +53,9 @@ test_slist: $(TEST_SLIST_OBJS)
test_nat: $(TEST_NAT_OBJS)
$(CC) $(ALLCFLAGS) -o $@ $^
+test_format_buf: $(TEST_FORMAT_BUF_OBJS)
+ $(CC) $(ALLCFLAGS) -o $@ $^
+
uids: $(UIDS_OBJS)
$(CC) $(ALLCFLAGS) -o $@ $^
diff --git a/rainbow/nss/buf.c b/rainbow/nss/buf.c
index 5cf0fa4..75c62f9 100644
--- a/rainbow/nss/buf.c
+++ b/rainbow/nss/buf.c
@@ -52,7 +52,7 @@ int format_buf(char** buf, size_t* buflen, const char* fmt, ...)
* set *buflen to indicate the quantity of remaining space,
* and return 0.
* on error, format_buf will set errno, return 1, and will not modify *buf or *buflen.
- * *buf should know overlap with fmt or any optional arguments.
+ * *buf should not overlap with fmt or any optional arguments.
*/
if (*buflen < 1)
{
@@ -60,27 +60,33 @@ int format_buf(char** buf, size_t* buflen, const char* fmt, ...)
return 1;
}
- size_t safe_buflen = *buflen - 1;
-
va_list ap;
va_start(ap, fmt);
- int status = vsnprintf(*buf, safe_buflen, fmt, ap);
- SAVE_ERR(va_end(ap));
+
+ int status = vsnprintf(*buf, *buflen, fmt, ap);
+ int err = errno;
+
+ va_end(ap);
if (status < 0)
goto out_err;
size_t written = (size_t) status;
- if (safe_buflen < written) {
- errno = ERANGE;
+
+ err = ERANGE;
+ if (written >= *buflen)
goto out_err;
- }
- *buf += written+1;
- *buflen -= written+1;
+ err = EOVERFLOW;
+ LET(written = written + 1, written == 0,
+ "Integer overflow.", out_err);
+
+ *buf += written;
+ *buflen -= written;
return 0;
out_err:
- (*buf)[safe_buflen] = '\0';
+ (*buf)[*buflen-1] = '\0';
+ errno = err;
return 1;
}
diff --git a/rainbow/nss/test_format_buf.c b/rainbow/nss/test_format_buf.c
new file mode 100644
index 0000000..40577ba
--- /dev/null
+++ b/rainbow/nss/test_format_buf.c
@@ -0,0 +1,78 @@
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "cgen.h"
+#include "buf.h"
+#include "config/debug.h"
+
+int main() {
+ char init[] = "aaaa";
+ char buf[] = "aaaa";
+ char good5[] = "b\0aa";
+ char good2[] = "b\0aa";
+ char good1[] = "\0aaa";
+ char good0[] = "aaaa";
+
+ char* ptr;
+ size_t len, old_len, i;
+ int ret;
+
+ ptr = buf;
+ old_len = len = sizeof(buf);
+ ret = format_buf(&ptr, &len, "b");
+
+ assert(ret == 0 && errno == 0);
+ assert(len == old_len - 2);
+ assert(ptr == buf+2);
+ for(i = 0; i < sizeof(buf); i++)
+ assert(buf[i] == good5[i]);
+
+ for(i = 0; i < sizeof(buf); i++)
+ buf[i] = init[i];
+
+ ptr = buf;
+ old_len = len = 2;
+ ret = format_buf(&ptr, &len, "b");
+
+ assert(ret == 0 && errno == 0);
+ assert(len == old_len - 2);
+ assert(ptr == buf+2);
+ for(i = 0; i < sizeof(buf); i++)
+ assert(buf[i] == good2[i]);
+
+ for(i = 0; i < sizeof(buf); i++)
+ buf[i] = init[i];
+
+ ptr = buf;
+ old_len = len = 1;
+ ret = format_buf(&ptr, &len, "b");
+
+ assert(ret == 1 && errno == ERANGE);
+ assert(len == old_len);
+ assert(ptr == buf);
+ for(i = 0; i < sizeof(buf); i++)
+ assert(buf[i] == good1[i]);
+
+ for(i = 0; i < sizeof(buf); i++)
+ buf[i] = init[i];
+
+ ptr = buf;
+ old_len = len = 0;
+ ret = format_buf(&ptr, &len, "b");
+
+ assert(ret == 1 && errno == ERANGE);
+ assert(len == old_len);
+ assert(ptr == buf);
+ for(i = 0; i < sizeof(buf); i++)
+ assert(buf[i] == good0[i]);
+
+ for(i = 0; i < sizeof(buf); i++)
+ buf[i] = init[i];
+
+ return 0;
+}
+