[lvm-devel] clvmd-command.c: unchecked realloc return value: potential DoS?

Jim Meyering jim at meyering.net
Thu Apr 26 16:21:04 UTC 2007


While this "case:" is solely for CLVMD_CMD_TEST, which is documented like this:

  #define CLVMD_CMD_TEST     4	/* Just for mucking about */

we wouldn't want a malicious client to be able to DoS a server
by provoking a low-memory condition and then sending a test message.

Here's the code:

int do_command(struct local_client *client, struct clvm_header *msg, int msglen,
	       char **buf, int buflen, int *retlen)
{
	...
	switch (msg->cmd) {
		/* Just a test message */
	case CLVMD_CMD_TEST:
		if (arglen > buflen) {
			buflen = arglen + 200;
			*buf = realloc(*buf, buflen);
		}
		uname(&nodeinfo);
		*retlen = 1 + snprintf(*buf, buflen, "TEST from %s: %s v%s",
				       nodeinfo.nodename, args,
				       nodeinfo.release);
		break;

Here's an untested patch:

	* daemons/clvmd/clvmd-command.c (do_command): Don't dereference NULL
	upon failed realloc.

Index: daemons/clvmd/clvmd-command.c
===================================================================
RCS file: /cvs/lvm2/LVM2/daemons/clvmd/clvmd-command.c,v
retrieving revision 1.14
diff -u -p -r1.14 clvmd-command.c
--- daemons/clvmd/clvmd-command.c	11 Dec 2006 14:00:26 -0000	1.14
+++ daemons/clvmd/clvmd-command.c	26 Apr 2007 16:10:17 -0000
@@ -95,13 +95,22 @@ int do_command(struct local_client *clie
 		/* Just a test message */
 	case CLVMD_CMD_TEST:
 		if (arglen > buflen) {
+			char *new_buf;
 			buflen = arglen + 200;
-			*buf = realloc(*buf, buflen);
+			new_buf = realloc(*buf, buflen);
+			if (new_buf == NULL) {
+				status = errno;
+				free (*buf);
+			}
+			*buf = new_buf;
+		}
+		if (*buf) {
+			uname(&nodeinfo);
+			*retlen = 1 + snprintf(*buf, buflen,
+					       "TEST from %s: %s v%s",
+					       nodeinfo.nodename, args,
+					       nodeinfo.release);
 		}
-		uname(&nodeinfo);
-		*retlen = 1 + snprintf(*buf, buflen, "TEST from %s: %s v%s",
-				       nodeinfo.nodename, args,
-				       nodeinfo.release);
 		break;

 	case CLVMD_CMD_LOCK_VG:

------------------------------
BTW, in the same function, I noticed that "*retlen" is not set consistently.
In the CLVMD_CMD_TEST and CLVMD_CMD_LOCK_VG cases, it's set to
"1 + snprintf(...)", so it includes the trailing NUL byte.
But here, it doesn't:

	case CLVMD_CMD_GET_CLUSTERNAME:
		status = clops->get_cluster_name(*buf, buflen);
		if (!status)
			*retlen = strlen(*buf);
		break;

I don't know enough to say whether there's a bug, but it's worth
fixing in any case, e.g.,

			*retlen = 1 + strlen(*buf);




More information about the lvm-devel mailing list