[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-167-g4319a8f

edwin edwin at 77e5149b-7576-45b1-b177-96237e5ba77b
Fri Jun 12 19:11:37 UTC 2009


The following commit has been merged in the debian/unstable branch:
commit c90b6b0d0d12aa7404b34ced95ce1933f347d888
Author: edwin <edwin at 77e5149b-7576-45b1-b177-96237e5ba77b>
Date:   Mon Apr 20 14:26:48 2009 +0000

    Fix clamd INSTREAM handling inside IDSESSION (bb #1564).
    
    git-svn-id: http://svn.clamav.net/svn/clamav-devel/trunk@5049 77e5149b-7576-45b1-b177-96237e5ba77b

diff --git a/ChangeLog b/ChangeLog
index 0762d3a..7835f42 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Mon Apr 20 17:20:27 EEST 2009 (edwin)
+-------------------------------------
+ * clamd/server-th.c, unit_tests/check_clamd.c: Fix clamd INSTREAM
+ handling inside IDSESSION (bb #1564).
+
 Fri Apr 17 18:23:44 CEST 2009 (acab)
 ------------------------------------
  * clamav-milter/clamav-milter.c: spam syslog with start events (bb#1557)
diff --git a/clamd/server-th.c b/clamd/server-th.c
index 18038bd..5d28927 100644
--- a/clamd/server-th.c
+++ b/clamd/server-th.c
@@ -641,7 +641,7 @@ static int handle_stream(client_conn_t *conn, struct fd_buf *buf, const struct o
 		    pos = 4;
 		    memmove (buf->buffer, &buf->buffer[pos], buf->off - pos);
 		    buf->off -= pos;
-		    pos = 0;
+		    *ppos = 0;
 		    buf->id++;
 		    return 0;
 		}
@@ -651,6 +651,7 @@ static int handle_stream(client_conn_t *conn, struct fd_buf *buf, const struct o
 		     (unsigned long)buf->chunksize, (unsigned long)buf->quota);
 		conn_reply_error(conn, "INSTREAM size limit exceeded.");
 		*error = 1;
+		*ppos = pos;
 		return -1;
 	    } else {
 		buf->quota -= buf->chunksize;
diff --git a/unit_tests/check_clamd.c b/unit_tests/check_clamd.c
index 77c78b5..0d77e46 100644
--- a/unit_tests/check_clamd.c
+++ b/unit_tests/check_clamd.c
@@ -153,42 +153,52 @@ static void commands_teardown(void)
 #define VERSION_REPLY "ClamAV "REPO_VERSION""VERSION_SUFFIX
 
 #define VCMDS_REPLY VERSION_REPLY"| COMMANDS: SCAN QUIT RELOAD PING CONTSCAN VERSIONCOMMANDS VERSION STREAM END SHUTDOWN MULTISCAN FILDES STATS IDSESSION INSTREAM"
+
+enum idsession_support {
+    IDS_OK, /* accepted */
+    IDS_REJECT,
+    /* after sending this message, clamd will reply,  then accept 
+     * no further commands, but still reply to all active commands */
+    IDS_END /* the END command */
+};
+
 static struct basic_test {
     const char *command;
     const char *extra;
     const char *reply;
     int support_old;
     int skiproot;
+    enum idsession_support ids;
 } basic_tests[] = {
-    {"PING", NULL, "PONG", 1, 0},
-    {"RELOAD", NULL, "RELOADING", 1, 0},
-    {"VERSION", NULL, VERSION_REPLY, 1, 0},
-    {"VERSIONCOMMANDS", NULL, VCMDS_REPLY, 0, 0},
-    {"SCAN "SCANFILE, NULL, FOUNDREPLY, 1, 0},
-    {"SCAN "CLEANFILE, NULL, CLEANREPLY, 1, 0},
-    {"CONTSCAN "SCANFILE, NULL, FOUNDREPLY, 1, 0},
-    {"CONTSCAN "CLEANFILE, NULL, CLEANREPLY, 1, 0},
-    {"MULTISCAN "SCANFILE, NULL, FOUNDREPLY, 1, 0},
-    {"MULTISCAN "CLEANFILE, NULL, CLEANREPLY, 1, 0},
+    {"PING", NULL, "PONG", 1, 0, IDS_OK},
+    {"RELOAD", NULL, "RELOADING", 1, 0, IDS_REJECT},
+    {"VERSION", NULL, VERSION_REPLY, 1, 0, IDS_OK},
+    {"VERSIONCOMMANDS", NULL, VCMDS_REPLY, 0, 0, IDS_REJECT},
+    {"SCAN "SCANFILE, NULL, FOUNDREPLY, 1, 0, IDS_OK},
+    {"SCAN "CLEANFILE, NULL, CLEANREPLY, 1, 0, IDS_OK},
+    {"CONTSCAN "SCANFILE, NULL, FOUNDREPLY, 1, 0, IDS_REJECT},
+    {"CONTSCAN "CLEANFILE, NULL, CLEANREPLY, 1, 0, IDS_REJECT},
+    {"MULTISCAN "SCANFILE, NULL, FOUNDREPLY, 1, 0, IDS_REJECT},
+    {"MULTISCAN "CLEANFILE, NULL, CLEANREPLY, 1, 0, IDS_REJECT},
     /* unknown commnads */
-    {"RANDOM", NULL, UNKNOWN_REPLY, 1, 0},
+    {"RANDOM", NULL, UNKNOWN_REPLY, 1, 0, IDS_REJECT},
     /* commands invalid as first */
-    {"END", NULL, UNKNOWN_REPLY, 1, 0},
+    {"END", NULL, UNKNOWN_REPLY, 1, 0, IDS_END},
     /* commands for nonexistent files */
-    {"SCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1, 0},
-    {"CONTSCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1, 0},
-    {"MULTISCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1, 0},
+    {"SCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1, 0, IDS_OK},
+    {"CONTSCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1, 0, IDS_REJECT},
+    {"MULTISCAN "NONEXISTENT, NULL, NONEXISTENT_REPLY, 1, 0, IDS_REJECT},
     /* commands for access denied files */
-    {"SCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1, 1},
-    {"CONTSCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1, 1},
-    {"MULTISCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1, 1},
+    {"SCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1, 1, IDS_OK},
+    {"CONTSCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1, 1, IDS_REJECT},
+    {"MULTISCAN "ACCDENIED, NULL, ACCDENIED_REPLY, 1, 1, IDS_REJECT},
     /* commands with invalid/missing arguments */
-    {"SCAN", NULL, UNKNOWN_REPLY, 1, 0},
-    {"CONTSCAN", NULL, UNKNOWN_REPLY, 1, 0},
-    {"MULTISCAN", NULL, UNKNOWN_REPLY, 1, 0},
+    {"SCAN", NULL, UNKNOWN_REPLY, 1, 0, IDS_REJECT},
+    {"CONTSCAN", NULL, UNKNOWN_REPLY, 1, 0, IDS_REJECT},
+    {"MULTISCAN", NULL, UNKNOWN_REPLY, 1, 0, IDS_REJECT},
     /* commands with invalid data */
-    {"INSTREAM", "\xff\xff\xff\xff", "INSTREAM size limit exceeded. ERROR", 0, 0}, /* too big chunksize */
-    {"FILDES", "X", "No file descriptor received. ERROR", 1, 0}, /* FILDES w/o ancillary data */
+    {"INSTREAM", "\xff\xff\xff\xff", "INSTREAM size limit exceeded. ERROR", 0, 0, IDS_REJECT}, /* too big chunksize */
+    {"FILDES", "X", "No file descriptor received. ERROR", 1, 0, IDS_REJECT}, /* FILDES w/o ancillary data */
 };
 
 static void *recvpartial(int sd, size_t *len, int partial)
@@ -204,7 +214,6 @@ static void *recvpartial(int sd, size_t *len, int partial)
 	    buf = realloc(buf, *len);
 	    fail_unless(!!buf, "Cannot realloc buffer\n");
 	}
-
 	rc = recv(sd, buf + off, BUFSIZ, 0);
 	fail_unless_fmt(rc != -1, "recv() failed: %s\n", strerror(errno));
 	off += rc;
@@ -308,6 +317,7 @@ END_TEST
 #endif
 
 #define EXPECT_INSTREAM "stream: ClamAV-Test-File.UNOFFICIAL FOUND\n"
+#define EXPECT_INSTREAM0 "stream: ClamAV-Test-File.UNOFFICIAL FOUND"
 
 #define STATS_REPLY "POOLS: 1\n\nSTATE: VALID PRIMARY\n"
 START_TEST (test_stats)
@@ -335,16 +345,11 @@ START_TEST (test_stats)
 }
 END_TEST
 
-START_TEST (test_instream)
+static size_t prepare_instream(char *buf, size_t off, size_t buflen)
 {
-    int fd, nread, rc;
     struct stat stbuf;
+    int fd, nread;
     uint32_t chunk;
-    void *recvdata;
-    size_t len, expect_len;
-    char buf[4096] = "nINSTREAM\n";
-    size_t off = strlen(buf);
-
     fail_unless_fmt(stat(SCANFILE, &stbuf) != -1, "stat failed for %s: %s", SCANFILE, strerror(errno));
 
     fd = open(SCANFILE, O_RDONLY);
@@ -353,14 +358,26 @@ START_TEST (test_instream)
     chunk = htonl(stbuf.st_size);
     memcpy(&buf[off], &chunk, sizeof(chunk));
     off += 4;
-    nread = read(fd, &buf[off], sizeof(buf)-off-4);
-    fail_unless_fmt(nread == stbuf.st_size, "read failed: %s\n", strerror(errno));
+    nread = read(fd, &buf[off], buflen-off-4);
+    fail_unless_fmt(nread == stbuf.st_size, "read failed: %d != %d, %s\n", nread, stbuf.st_size, strerror(errno));
     off += nread;
     buf[off++]=0;
     buf[off++]=0;
     buf[off++]=0;
     buf[off++]=0;
     close(fd);
+    return off;
+}
+
+START_TEST (test_instream)
+{
+    void *recvdata;
+    size_t len, expect_len;
+    char buf[4096] = "nINSTREAM\n";
+    size_t off = strlen(buf);
+    int rc;
+
+    off = prepare_instream(buf, off, sizeof(buf));
 
     conn_setup();
     fail_unless((size_t)send(sockd, buf, off, 0) == off, "send() failed: %s\n", strerror(errno));
@@ -713,6 +730,110 @@ START_TEST (test_stream)
 }
 END_TEST
 
+#define END_CMD "zEND"
+#define INSTREAM_CMD "zINSTREAM"
+static void test_idsession_commands(int split, int instream)
+{
+    char buf[20480];
+    size_t i, len=0, j=0;
+    char *recvdata;
+    char *p = buf;
+    const char *replies[2 + sizeof(basic_tests)/sizeof(basic_tests[0])];
+
+    /* test all commands that must be accepted inside an IDSESSION */
+    for (i=0;i < sizeof(basic_tests)/sizeof(basic_tests[0]); i++) {
+	const struct basic_test *test = &basic_tests[i];
+	if (test->ids == IDS_OK) {
+	    fail_unless(p+strlen(test->command)+2 < buf+sizeof(buf), "Buffer too small");
+	    *p++ = 'z';
+	    strcpy(p, test->command);
+	    p += strlen(test->command);
+	    *p++ = '\0';
+	    if (test->extra) {
+		fail_unless(p+strlen(test->extra) < buf+sizeof(buf), "Buffer too small");
+		strcpy(p, test->extra);
+		p += strlen(test->extra);
+	    }
+	    replies[j++] = test->reply;
+	}
+	if (instream && test->ids == IDS_END) {
+	    uint32_t chunk;
+	    int fd;
+	    /* IDS_END - in middle of other commands, perfect for inserting
+	     * INSTREAM */
+	    fail_unless(p+sizeof(INSTREAM_CMD)+544< buf+sizeof(buf), "Buffer too small");
+	    memcpy(p, INSTREAM_CMD, sizeof(INSTREAM_CMD));
+	    p += sizeof(INSTREAM_CMD);
+	    p += prepare_instream(p, 0, 552);
+	    replies[j++] = EXPECT_INSTREAM0;
+	    fail_unless(p+sizeof(INSTREAM_CMD)+16388< buf+sizeof(buf), "Buffer too small");
+	    memcpy(p, INSTREAM_CMD, sizeof(INSTREAM_CMD));
+	    p += sizeof(INSTREAM_CMD);
+	    chunk=htonl(16384);
+	    memcpy(p, &chunk, 4);
+	    p+=4;
+	    memset(p, 0x5a, 16384);
+	    p += 16384;
+	    *p++='\0';
+	    *p++='\0';
+	    *p++='\0';
+	    *p++='\0';
+	    replies[j++] = "stream: OK";
+	}
+    }
+    fail_unless(p+sizeof(END_CMD) < buf+sizeof(buf), "Buffer too small");
+    memcpy(p, END_CMD, sizeof(END_CMD));
+    p += sizeof(END_CMD);
+
+    if (split) {
+	/* test corner-cases: 1-byte sends */
+	for (i=0;i<p-buf;i++)
+	    fail_unless((size_t)send(sockd, &buf[i], 1, 0) == 1, "send() failed: %u, %s\n", i, strerror(errno));
+    } else {
+	fail_unless((size_t)send(sockd, buf, p-buf, 0) == p-buf,"send() failed: %s\n", strerror(errno));
+    }
+    recvdata = recvfull(sockd, &len);
+    p = recvdata;
+    for (i=0;i < sizeof(basic_tests)/sizeof(basic_tests[0]); i++) {
+	const struct basic_test *test = &basic_tests[i];
+	if (test->ids == IDS_OK) {
+	    unsigned id;
+	    char *q = strchr(p, ':');
+	    fail_unless_fmt(!!q, "No ID in reply: %s\n", p);
+	    *q = '\0';
+	    fail_unless_fmt(sscanf(p, "%u", &id) == 1,"Wrong ID in reply: %s\n", p);
+	    fail_unless(id > 0, "ID cannot be zero");
+	    fail_unless_fmt(id <= j, "ID too big: %u, max: %u\n", id, j);
+	    q += 2;
+	    fail_unless_fmt(!strcmp(q, replies[id-1]),
+			    "Wrong ID reply for ID %u: %s, expected %s\n",
+			    id,
+			    q, replies[id-1]);
+	    p = q + strlen(q)+1;
+	}
+    }
+    free(recvdata);
+    conn_teardown();
+}
+
+#define ID_CMD "zIDSESSION"
+START_TEST(test_idsession)
+{
+    conn_setup();
+    fail_unless_fmt((size_t)send(sockd, ID_CMD, sizeof(ID_CMD), 0) == sizeof(ID_CMD),
+		    "send() failed: %s\n", strerror(errno));
+    test_idsession_commands(0, 0);
+    conn_setup();
+    fail_unless_fmt((size_t)send(sockd, ID_CMD, sizeof(ID_CMD), 0) == sizeof(ID_CMD),
+		    "send() failed: %s\n", strerror(errno));
+    test_idsession_commands(1, 0);
+    conn_setup();
+    fail_unless_fmt((size_t)send(sockd, ID_CMD, sizeof(ID_CMD), 0) == sizeof(ID_CMD),
+		    "send() failed: %s\n", strerror(errno));
+    test_idsession_commands(0, 1);
+}
+END_TEST
+
 static Suite *test_clamd_suite(void)
 {
     Suite *s = suite_create("clamd");
@@ -728,6 +849,7 @@ static Suite *test_clamd_suite(void)
     tcase_add_test(tc_commands, test_stats);
     tcase_add_test(tc_commands, test_instream);
     tcase_add_test(tc_commands, test_stream);
+    tcase_add_test(tc_commands, test_idsession);
     tc_stress = tcase_create("clamd stress test");
     suite_add_tcase(s, tc_stress);
     tcase_set_timeout(tc_stress, 20);

-- 
Debian repository for ClamAV



More information about the Pkg-clamav-commits mailing list