Re: Buffer overflows

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2007-08-30 at 21:09 -0700, Linus Torvalds wrote:
> 
> On Fri, 31 Aug 2007, Timo Sirainen wrote:
> > > 
> > > Perhaps because your patch was using a totally nonstandard and slow
> > > interface, and had nasty string declaration issues, as people even pointed
> > > out to you.
> > 
> > Slow?
> 
> Having a string library, and then implementing "str_append()" with a 
> strlen() sounds pretty disgusting to me. 
> 
> Gcc could have optimized the strlen() away for constant string arguments, 
> but since you made the thing out-of-line, it can't do that any more.
> 
> So yes, I bet there are faster string libraries out there.

Oh, well that's easy to fix. But I don't think the speed matters much in
string manipulation, it's usually not done in performance critical
paths.

> > The code should be easy to verify to be secure, and with some kind of a safe
> > string API it's a lot easier than trying to figure out corner cases where
> > strcpy() calls break.
> 
> I actually looked at the patches, and the "stringbuf()" thing was just too 
> ugly to live. It was also nonportable, in that you use the reserved 
> namespace (which we do extensively in the kernel, but that's an 
> "embdedded" application that doesn't use system header files).
> 
> So the API was anything but "safe".

Some of those were fixed in the patch I sent at the beginning of this
thread. But since you asked, attached is yet another version of it. As
far as I know it's fully C99 compatible. Would be C89 but there's that
va_copy() call.

I guess it could still be optimized more, but at least strlen() is now
in a macro. :)

Or if you don't like the STR_STATIC() macro, another way would be:

#define STR_STATIC_INIT(buf) { buf, sizeof(buf), 0, }

char static_buf[1024];
struct string str = STR_STATIC_INIT(static_buf);

str_append(&str, "hello world");

--- /dev/null	2007-07-12 03:40:41.165212167 +0300
+++ str.h	2007-08-31 07:35:04.000000000 +0300
@@ -0,0 +1,33 @@
+#ifndef STR_H
+#define STR_H
+
+struct string {
+	char *buf;
+
+	unsigned int alloc_size;
+	unsigned int len;
+
+	unsigned int malloced:1;
+	unsigned int overflowed:1;
+};
+
+#define STR_STATIC(name, size) \
+	struct { \
+	  struct string str; \
+	  char string_buf[(size) + 1]; \
+	} name = { { (name).string_buf, sizeof((name).string_buf), 0, } }
+
+extern struct string *str_alloc(unsigned int initial_size);
+extern void str_free(struct string **str);
+
+extern void str_append_n(struct string *str, const char *cstr,
+			 unsigned int len);
+extern void str_printfa(struct string *str, const char *fmt, ...)
+	__attribute__((format (printf, 2, 3)));
+extern void str_truncate(struct string *str, unsigned int len);
+
+#define str_append(str, cstr) str_append_n(str, cstr, strlen(cstr))
+#define str_c(str) ((str)->buf)
+#define str_len(str) ((str)->len)
+
+#endif
--- /dev/null	2007-07-12 03:40:41.165212167 +0300
+++ str.c	2007-08-31 07:36:56.000000000 +0300
@@ -0,0 +1,85 @@
+#include "str.h"
+#include "git-compat-util.h"
+
+struct string *str_alloc(unsigned int initial_size)
+{
+	struct string *str;
+
+	str = xcalloc(sizeof(*str), 1);
+	str->alloc_size = initial_size + 1;
+	str->buf = xmalloc(str->alloc_size);
+	str->buf[0] = '\0';
+	return str;
+}
+
+void str_free(struct string **_str)
+{
+	struct string *str = *_str;
+
+	if (str->malloced)
+		free(str->buf);
+	str->buf = NULL;
+	free(str);
+
+	*_str = NULL;
+}
+
+static void str_grow_if_needed(struct string *str, unsigned int *len)
+{
+	unsigned int avail = str->alloc_size - str->len;
+
+	if (*len >= avail) {
+		if (!str->malloced) {
+			/* static buffer size */
+			*len = avail;
+			str->overflowed = 1;
+		} else {
+			str->alloc_size = (str->len + *len) * 2;
+			str->buf = xrealloc(str->buf, str->alloc_size);
+		}
+	}
+}
+
+void str_append_n(struct string *str, const char *cstr, unsigned int len)
+{
+	str_grow_if_needed(str, &len);
+	memcpy(str->buf + str->len, cstr, len);
+	str->len += len;
+	str->buf[str->len] = '\0';
+}
+
+void str_printfa(struct string *str, const char *fmt, ...)
+{
+	unsigned int len, avail = str->alloc_size - str->len;
+	va_list va, va2;
+	int ret;
+
+	va_start(va, fmt);
+	va_copy(va2, va);
+	ret = vsnprintf(str->buf + str->len, avail, fmt, va);
+	assert(ret >= 0);
+
+	if ((unsigned int)ret >= avail) {
+		if (!str->malloced) {
+			str->overflowed = 1;
+			ret = avail == 0 ? 0 : avail-1;
+		} else {
+			len = ret;
+			str_grow_if_needed(str, &len);
+			avail = str->alloc_size - str->len;
+
+			ret = vsnprintf(str->buf + str->len, avail, fmt, va2);
+			assert(ret >= 0 && (unsigned int)ret < avail);
+		}
+	}
+	str->len += ret;
+	va_end(va);
+}
+
+void str_truncate(struct string *str, unsigned int len)
+{
+	if (len >= str->alloc_size)
+		len = str->alloc_size - 1;
+	str->len = len;
+	str->buf[len] = '\0';
+}

Attachment: signature.asc
Description: This is a digitally signed message part


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux