[clamav-devel] New socket to manage dynamic mount/umount

[email protected]
Newsgroups gmane.comp.security.virus.clamav.devel
Message-ID <[email protected]>
‌‌Hello, In my work, we had the need to use the onaccess feature of clamav, but on new(dynamic) mount point. The actual fanoitify/inotify couldn't detect when a directory is mounted, so couldn't follow any mount. So we create a little patch to reflect what we've done against clamav v 0.99.2 In this way, we decide to test another approach : using a socket to add/remove file from the watch tree. A script monitor the mount (dbus-monitor for our needs). This has another benefit : the capacity to filter which mount point we want to follow. However, to simplify the work, we create another socket than the master, dedicated to this works (and so we could have multiple instances with different configurations). To avoid multiples way of declaring the socket, I factorize the already existent (in localserver), and use it in onaccess_ddd. The inner working is really simple : for each line written to the socket, we remove it from the watch tree (to be sure we doesn't duplicate anything).Then, we add it only if the path exist. In addition, I needed to add a little patch to desactivate onas_ddd_handle_extra_scanning. This one scan the directory even if we are "on access", and we want to avoid this. It begin at the 533 line in onaccess_ddd.c, and it is really crude (I didn't want to delete the function). The added functionnality is really a necessity for us, and any help so it could be incorporated into upstream will be appreciated :) Cordially

_______________________________________________
http://lurker.clamav.net/list/clamav-devel.html
Please submit your patches to our Bugzilla: http://bugs.clamav.net

http://www.clamav.net/contact.html#ml
clamav-socketonaccess.patch (application/octet-stream, 11.5 KB)
diff -ru -w B/clamav-devel-master/clamd/localserver.c clamav-devel-master/clamd/localserver.c
--- B/clamav-devel-master/clamd/localserver.c	2016-07-15 18:23:21.000000000 +0200
+++ clamav-devel-master/clamd/localserver.c	2016-07-20 12:07:15.141079360 +0200
@@ -52,56 +52,31 @@
     logg("!Localserver is not supported on this platform");
     return -1;
 }
+int createsocket(const char* sname,mode_t sock_mode ,int fix_stale,int backlog)
+{
+	logg("!Socket Creation is not supported on this platform");
+	return -1;
+}
 
 #else
-
-int localserver(const struct optstruct *opts)
+int createsocket(const char* sname,mode_t sock_mode ,int fix_stale,int backlog)
 {
 	struct sockaddr_un server;
-	int sockfd, backlog;
+	int sockfd;
 	STATBUF foo;
 	char *estr;
         char *sockdir;
         char *pos;
         struct stat sb;
         int cnt;
-
-    int num_fd = sd_listen_fds(0);
-    if (num_fd > 2)
-    {
-        logg("!LOCAL: Received more than two file descriptors from systemd.\n");
+	if (NULL==sname){
+		logg("!LOCAL: Ensure parent directory exists.\n");
         return -1;
     }
-    else if (num_fd > 0)
-    {
-        /* use socket passed by systemd */
-        int i;
-        for(i = 0; i < num_fd; i += 1)
-        {
-            sockfd = SD_LISTEN_FDS_START + i;
-            if (sd_is_socket(sockfd, AF_UNIX, SOCK_STREAM, 1) == 1)
-            {
-                /* correct socket */
-                break;
-            }
-            else
-            {
-                /* wrong socket */
-                sockfd = -2;
-            }
-        }
-        if (sockfd == -2)
-        {
-            logg("#LOCAL: No local AF_UNIX SOCK_STREAM socket received from systemd.\n");
-            return -2;
-        }
-        logg("#LOCAL: Received AF_UNIX SOCK_STREAM socket from systemd.\n");
-        return sockfd;
-    }
     /* create socket */
     memset((char *) &server, 0, sizeof(server));
     server.sun_family = AF_UNIX;
-    strncpy(server.sun_path, optget(opts, "LocalSocket")->strarg, sizeof(server.sun_path));
+	strncpy(server.sun_path, sname, sizeof(server.sun_path));
     server.sun_path[sizeof(server.sun_path)-1]='\0';
 
     pos = NULL;
@@ -122,19 +97,6 @@
 
         if (stat(sockdir, &sb)) {
             if (errno == ENOENT) {
-                mode_t sock_mode;
-                if(optget(opts, "LocalSocketMode")->enabled) {
-                    char *end;
-                    sock_mode = strtol(optget(opts, "LocalSocketMode")->strarg, &end, 8);
-
-                    if(*end) {
-                        logg("!Invalid LocalSocketMode %s\n", optget(opts, "LocalSocketMode")->strarg);
-                        free(sockdir);
-                        return -1;
-                    }
-                } else {
-                    sock_mode = 0777;
-                }
 
                 if (mkdir(sockdir, sock_mode)) {
                     logg("!LOCAL: Could not create socket directory: %s: %s\n", sockdir, strerror(errno));
@@ -163,7 +125,7 @@
 		close(sockfd);
 		return -1;
 	    }
-	    if(optget(opts, "FixStaleSocket")->enabled) {
+			if(fix_stale) {
 		logg("#LOCAL: Removing stale socket file %s\n", server.sun_path);
 		if(unlink(server.sun_path) == -1) {
 		    estr = strerror(errno);
@@ -192,7 +154,6 @@
 
     logg("#LOCAL: Unix socket file %s\n", server.sun_path);
 
-    backlog = optget(opts, "MaxConnectionQueueLength")->numarg;
     logg("#LOCAL: Setting connection queue length to %d\n", backlog);
 
     if(listen(sockfd, backlog) == -1) {
@@ -203,5 +164,61 @@
     }
 
     return sockfd;
+
+}
+
+int localserver(const struct optstruct *opts)
+{
+	int sockfd;
+	mode_t sock_mode;
+
+	int num_fd = sd_listen_fds(0);
+	if (num_fd > 2)
+	{
+		logg("!LOCAL: Received more than two file descriptors from systemd.\n");
+		return -1;
+	}
+	else if (num_fd > 0)
+	{
+		/* use socket passed by systemd */
+		int i;
+		for(i = 0; i < num_fd; i += 1)
+		{
+			sockfd = SD_LISTEN_FDS_START + i;
+			if (sd_is_socket(sockfd, AF_UNIX, SOCK_STREAM, 1) == 1)
+			{
+				/* correct socket */
+				break;
+			}
+			else
+			{
+				/* wrong socket */
+				sockfd = -2;
+			}
+		}
+		if (sockfd == -2)
+		{
+			logg("#LOCAL: No local AF_UNIX SOCK_STREAM socket received from systemd.\n");
+			return -2;
+		}
+		logg("#LOCAL: Received AF_UNIX SOCK_STREAM socket from systemd.\n");
+		return sockfd;
+	}
+
+
+	if(optget(opts, "LocalSocketMode")->enabled) {
+		char *end;
+		sock_mode = strtol(optget(opts, "LocalSocketMode")->strarg, &end, 8);
+
+		if(*end) {
+			logg("!Invalid LocalSocketMode %s\n", optget(opts, "LocalSocketMode")->strarg);
+			return -1;
+		}
+	} else {
+		sock_mode = 0777;
+	}
+	logg("creating a socket %s - %d\n",optget(opts, "LocalSocket")->strarg,(int)sock_mode);
+
+	return createsocket(optget(opts, "LocalSocket")->strarg, sock_mode, optget(opts, "FixStaleSocket")->enabled,optget(opts, "MaxConnectionQueueLength")->numarg);
 }
 #endif
diff -ru -w B/clamav-devel-master/clamd/localserver.h clamav-devel-master/clamd/localserver.h
--- B/clamav-devel-master/clamd/localserver.h	2016-07-15 18:23:21.000000000 +0200
+++ clamav-devel-master/clamd/localserver.h	2016-07-19 15:35:54.103079360 +0200
@@ -25,5 +25,6 @@
 #include "shared/optparser.h"
 
 int localserver(const struct optstruct *opts);
+int createsocket(const char* sname,mode_t sock_mode ,int fix_stale,int backlog);
 
 #endif
diff -ru -w B/clamav-devel-master/clamd/onaccess_ddd.c clamav-devel-master/clamd/onaccess_ddd.c
--- B/clamav-devel-master/clamd/onaccess_ddd.c	2016-07-15 18:23:21.000000000 +0200
+++ clamav-devel-master/clamd/onaccess_ddd.c	2016-07-21 14:02:31.497079360 +0200
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <fts.h>
 #include <fcntl.h>
@@ -55,6 +56,7 @@
 #include "server.h"
 #include "others.h"
 #include "scanner.h"
+#include "localserver.h"
 
 static int onas_ddd_init_ht(uint32_t ht_size);
 static int onas_ddd_init_wdlt(uint64_t nwatches);
@@ -293,6 +295,7 @@
 	uint64_t in_mask = IN_ONLYDIR | IN_MOVE | IN_DELETE | IN_CREATE;
 	fd_set rfds;
 	char buf[4096];
+	char buf2[4096];
 	ssize_t bread;
 	const struct inotify_event *event;
 	int ret, len;
@@ -393,14 +396,151 @@
 
 	FD_ZERO(&rfds);
 	FD_SET(onas_in_fd, &rfds);
+	int maxfs=onas_in_fd+1;
+	int sockfd=-1;
+	int index=0;
+
+	if(optget(tharg->opts, "OnAccessSocket")->enabled) {
+		char* sockname = optget(tharg->opts, "OnAccessSocket")->strarg;
+		sockfd=createsocket(sockname,0660,1,128);
+		if (sockfd >=0)
+		{
+			logg("ScanOnAccess: Adding socket to notifications\n");
+			FD_SET(sockfd,&rfds);
+			if (maxfs<=sockfd)
+			{
+				maxfs=sockfd+1;
+			}
+		}
+	}
+	int offset_write=0;
+	const int sizesie=sizeof(struct inotify_event);
+	int acceptfd=-1;//TODO accept any number of connection
+#define SIZEFDARRAY 10
+	int fdarray[SIZEFDARRAY];
+	fdarray[0]=onas_in_fd;
+	fdarray[1]=sockfd;
+	for (index=2;index<SIZEFDARRAY;fdarray[index++]=-1);
 
 	while (1) {
+		FD_ZERO(&rfds);
+		maxfs=-1;
+		for ( index=0; index<SIZEFDARRAY;index++)
+		{
+			if (fdarray[index]>=0){
+				FD_SET(fdarray[index],&rfds);
+				if ((fdarray[index] +1)>maxfs)
+				{
+					maxfs=fdarray[index]+1;
+				}	
+			}
+			
+		}
 		do {
-			ret = select(onas_in_fd + 1, &rfds, NULL, NULL, NULL);
+			ret = select(maxfs, &rfds, NULL, NULL, NULL);
 		} while(ret == -1 && errno == EINTR);
+		bread=-1;
+
+		
+		int nextfd=-1;
+		for (index=0; index<SIZEFDARRAY;index++)
+		{
+			if (fdarray[index]>=0 && FD_ISSET(fdarray[index],&rfds))
+			{
+				nextfd=index;
+				break;
+			}
+		}
+
+
+		
+		if (nextfd ==0)//inotify
+		{
+				logg("ScanOnAccess: New inotify notification\n");
+				bread = read(onas_in_fd, buf, sizeof(buf));
+		}
+		else if(nextfd==1)//master socket
+		{
+				int temp_fd=accept(sockfd,NULL,NULL);
+				nextfd=-1;
+				for (index=2;index<SIZEFDARRAY;++index)
+				{
+					if (fdarray[index]<=0)
+					{
+						nextfd=index;
+					}
+				}
+				if (nextfd==-1 && temp_fd>=0)
+				{
+					logg("Too many client on socket %d\n",sockfd);
+					dprintf(temp_fd,"Too many clients, bye\n");
+					close(temp_fd);
+				}
+				else if (temp_fd>=0)
+				{
+					logg("ScanOnAccess: New socket notification\n");
+					fdarray[nextfd]=temp_fd;
+					FD_SET(temp_fd,&rfds);
+					if (maxfs<=temp_fd)
+					{
+						maxfs=temp_fd+1;
+					}
+				}
+			}
+			else if (nextfd>=2)
+			{
+				int nb=1;
+				while( ((nb=read(fdarray[nextfd],buf2+offset_write,1))==1) && offset_write<sizeof(buf2))
+				{
+					if (buf2[offset_write]=='\n')
+					{
+						buf2[offset_write]='\0';
+						offset_write=0;
+						break;
+					}
+					else
+						offset_write++;
+				}
+				if (nb<=0)//TODO validate with a non buffering system it's still work
+				{
+					logg("ScanOnAccess: end of socket\n");
+					closesocket(fdarray[nextfd]);
+					fdarray[nextfd]=-1;
+				}
+				else
+				{
+					int lenpath=strlen(buf2)+1;//\0 must be taken into account
+					struct inotify_event *tmpsie;
+					tmpsie=(struct inotify_event*)buf;
+					tmpsie->wd=-1;//use only for the log
+					tmpsie->len=lenpath;
+					tmpsie->mask=IN_DELETE;//doesn't manage IN_DELETE_SELF or IN_UNMOUNT
+								//We use it to clean all existing watch, then recreate one if it's needed
+								//
+					memcpy(tmpsie->name,buf2,lenpath);
+					bread=sizesie+lenpath;
+					logg("ScanOnAccess: Deleting from socket %s (size : %d (%d)).\n",buf2,bread,lenpath);
+					if (0==access(buf2,F_OK))
+					{
+						
+						tmpsie=(struct inotify_event*)(buf+bread);
+						tmpsie->wd=-1;
+						tmpsie->len=lenpath;
+						tmpsie->mask=IN_CREATE;
+						memcpy(tmpsie->name,buf2,lenpath);
 
-		while((bread = read(onas_in_fd, buf, sizeof(buf))) > 0) {
+						bread+=sizesie+lenpath;
+						logg("ScanOnAccess: Adding from socket %s (size : %d (%d)).\n",buf2,bread,lenpath);
+					}
+					buf2[0]='\0';
+				}
+			}else{
+				logg("Unknown FD ?\n");
+			}
 
+
+		if (bread>0)
+		{
 			/* Handle events. */
 			int wd;
 			char *p = buf;
@@ -410,7 +550,10 @@
 
 				event = (const struct inotify_event *) p;
 				wd = event->wd;
+				if (wd >0)
 				path = wdlt[wd];
+				else
+					path="/";
 				child = event->name;
 
 				len = strlen(path);
@@ -533,6 +677,7 @@
 	struct scth_thrarg *scth_tharg = NULL;
 	pthread_attr_t scth_attr;
 	pthread_t scth_pid = 0;
+	return;//Create a scan of all the device, and We don't need it!
 
 	do {
 		if (pthread_attr_init(&scth_attr)) break;
diff -ru -w B/clamav-devel-master/shared/optparser.c clamav-devel-master/shared/optparser.c
--- B/clamav-devel-master/shared/optparser.c	2016-07-15 18:23:21.000000000 +0200
+++ clamav-devel-master/shared/optparser.c	2016-07-19 18:04:06.563079360 +0200
@@ -409,6 +409,7 @@
     { "OnAccessIncludePath", "on-access-include", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "This option specifies a directory (including all files and directories\ninside it), which should be scanned on access. This option can\nbe used multiple times.", "/home\n/students" },
 
     { "OnAccessExcludePath", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "This option allows excluding directories from on-access scanning. It can\nbe used multiple times. Only works with DDD system.", "/home/bofh\n/root" },
+    { "OnAccessSocket", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "This option allows to manually add file to watch, so a script or other mean could use clamav wwithout restart it", "/tmp/sock-dbus.clamd" },
 
     { "OnAccessExcludeUID", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, FLAG_MULTIPLE, OPT_CLAMD, "With this option you can whitelist specific UIDs. Processes with these UIDs\nwill be able to access all files.\nThis option can be used multiple times (one per line).", "0" },
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.