linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Vasily Novikov <vasily.novikov@kaspersky.com>
To: Lino Sanfilippo <LinoSanfilippo@gmx.de>
Cc: "eparis@redhat.com" <eparis@redhat.com>,
	"linux-fsdevel@vger.kernel.org" <linux-fsdevel@vger.kernel.org>,
	"malware-list@dmesg.printk.net" <malware-list@dmesg.printk.net>
Subject: Re: fanotify coredump issue
Date: Fri, 10 Jun 2011 17:47:38 +0400	[thread overview]
Message-ID: <4DF2207A.40104@kaspersky.com> (raw)
In-Reply-To: <20110104102849.GB26251@lsanfilippo.unix.rd.tt.avira.com>

[-- Attachment #1: Type: text/plain, Size: 1481 bytes --]

Lino,

On 01/04/2011 01:28 PM, Lino Sanfilippo wrote:
>> I tested fanotify in 2.6.37-rc7 and faced the following issue: when a
>> fanotify server process (started with open_perm set) segfaults the
>> kernel tries to open core dump file and here it is forced to wait a
>> permission result because fanotify server receives notifications on
>> file operations initiated by itself. Since fanotify server has crashed
>> the permission will never be granted. So the whole system hangs.
>
> Hmm I could not reproduce this with the latest state (ef9bf3b7144bee6ce) of
> branch 'origin/for-next' from git.infradead.org/users/eparis/notify.git
>
> What i did was:
> - register with fanotify
> - set mark for OPEN_PERM event
> - read an event
> - cause a segfault before response is returned to fanotify
>
> The process terminates and the core file is created as expected.
> Could you provide some code to trigger this?
>

The issue is still reproduced on ubuntu 11.04:

$ uname -a
Linux user-virtual-machine 2.6.38.2 #16 SMP Wed Jun 8 14:40:03 MSD 2011 
i686 i686 i386 GNU/Linux
$ g++ fanotify.c -o fanotify -lpthread
$ sudo su
$ ulimit -c unlimited
$ ./fanotify -o open_perm -C -m /

In other console:
$ ls

Then machine is dead.

-- 
Best regards,

Vasily Novikov | Software developer | Kaspersky Lab

Direct: +7 495 123 45 67 x2344 | Mobile: +7 964 786 44 82 | 
vasily.novikov@kaspersky.com
10/1, 1st Volokolamsky Proezd, Moscow, 123060, Russia | 
www.kaspersky.com,  www.securelist.com

[-- Attachment #2: fanotify.c --]
[-- Type: text/x-csrc, Size: 7217 bytes --]

#define _ATFILE_SOURCE
#include <errno.h>
#include <inttypes.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>

#include <linux/fanotify.h>
#include <sys/fanotify.h>
//#include <linux/fsnotify_backend.h>

//#include "fanotify-syscalllib.h"

#define FANOTIFY_ARGUMENTS "cfhmn"

uint64_t fan_mask = FAN_OPEN | FAN_CLOSE | FAN_ACCESS | FAN_MODIFY;
bool opt_fast;
int fan_fd;

int mark_object(int fan_fd, const char *path, int fd, uint64_t mask, unsigned int flags)
{
	return fanotify_mark(fan_fd, flags, mask, fd, path);
}

int set_ignored_mask(int fan_fd, int fd, uint64_t mask)
{
	unsigned int flags = (FAN_MARK_ADD | FAN_MARK_IGNORED_MASK);

	return mark_object(fan_fd, NULL, fd, mask, flags);
}

int handle_perm(int fan_fd, struct fanotify_event_metadata *metadata, unsigned int response)
{
	struct fanotify_response response_struct;
	int ret;

	response_struct.fd = metadata->fd;
	response_struct.response = response;

	ret = write(fan_fd, &response_struct, sizeof(response_struct));
	if (ret < 0)
		return ret;

	return 0;
}

void synopsis(const char *progname, int status)
{
	FILE *file = status ? stderr : stdout;

	fprintf(file, "USAGE: %s [-" FANOTIFY_ARGUMENTS "] "
		"[-o {open,close,access,modify,open_perm,access_perm}] "
		"file ...\n"
		"-c: learn about events on children of a directory (not decendants)\n"
		"-f: set premptive ignores (go faster)\n"
		"-h: this help screen\n"
		"-m: place mark on the whole mount point, not just the inode\n"
		"-n: do not ignore repeated permission checks\n"
		"-s N: sleep N seconds before replying to perm events\n",
		"-C: crash\n",
		progname);
	exit(status);
}

#define FAIL() do { fprintf(stderr, "%s:%d: ", __FILE__, __LINE__); goto fail; } while(0);

int g_N = 30;

void* process_request(void *p)
{
	struct fanotify_event_metadata *metadata = (struct fanotify_event_metadata*)p;
	bool opt_ignore_perm = 1;
	unsigned int response = FAN_ALLOW;
	int opt_sleep = 0;

	pthread_detach(pthread_self());
	
	if (metadata->fd >= 0 &&
			opt_fast &&
			set_ignored_mask(fan_fd, metadata->fd,
				FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS))
		FAIL();

	if (metadata->fd >= 0) {
		char path[PATH_MAX];
		int path_len;

		sprintf(path, "/proc/self/fd/%d", metadata->fd);
		path_len = readlink(path, path, sizeof(path)-1);
		opt_ignore_perm =  (path[path_len-1] != 'i');
		if(!opt_ignore_perm) printf(" nocache");
		if(path[path_len-1] == 'f') {
			printf(" flush");
//			open("/tmp/123.txt", O_RDONLY);
			if(mark_object(fan_fd, "/tmp", AT_FDCWD, fan_mask, FAN_MARK_FLUSH) != 0) FAIL();
			//	if(mark_object(fan_fd, "/tmp", AT_FDCWD, fan_mask, FAN_MARK_ADD) != 0) FAIL();
		}
		if(path[path_len-1] == 'd') {
			printf(" deny");
			response = FAN_DENY;
		}
		if(path[path_len-1] == 's') {
			printf(" sleep");
			opt_sleep = 1;
		}
		if (path_len < 0)
			FAIL();
		path[path_len] = '\0';
		printf("%s:", path);
	} else
		printf("?:");

	printf(" pid=%ld", (long)metadata->pid);

	if (metadata->mask & FAN_ACCESS)
		printf(" access");
	if (metadata->mask & FAN_OPEN)
		printf(" open");
	if (metadata->mask & FAN_MODIFY)
		printf(" modify");
	if (metadata->mask & FAN_CLOSE) {
		if (metadata->mask & FAN_CLOSE_WRITE)
			printf(" close(writable)");
		else
			printf(" close");
	}
	if (metadata->mask & FAN_OPEN_PERM)
		printf(" open_perm");
	if (metadata->mask & FAN_ACCESS_PERM)
		printf(" access_perm");
	printf(" md->mask:%x PE:%x", (int)metadata->mask, (int)(FAN_ALL_PERM_EVENTS));
	if (metadata->mask & (FAN_ALL_PERM_EVENTS)) {
		if (opt_sleep) {
			sleep(opt_sleep);
		}

		if (metadata->fd >= 0 &&
				opt_ignore_perm &&
				set_ignored_mask(fan_fd, metadata->fd,
					metadata->mask))
			FAIL();
		if (handle_perm(fan_fd, metadata, response))
			FAIL();
	}

	printf("\n");
	fflush(stdout);

	if (metadata->fd >= 0 && close(metadata->fd) != 0)
		FAIL();

	free(p);
	return NULL;

fail:
	fprintf(stderr, "%s\n", strerror(errno));
	exit(1);
	return NULL;
}


void deffered_processing(struct fanotify_event_metadata *a_md)
{
	struct fanotify_event_metadata *md = (struct fanotify_event_metadata *)malloc(sizeof(struct fanotify_event_metadata));
	pthread_t tid;

	if(NULL == md) {
		printf("can't allocate memory for mrequest\n");
		process_request(md);
		return;
	}

	*md = *a_md;

	if(0 != pthread_create(&tid, NULL, process_request, md)) {
		printf("can't create thread\n");
		process_request(md);
	}
}

int main(int argc, char *argv[])
{
	int opt;
	unsigned int mark_flags = FAN_MARK_ADD;
	bool opt_child, opt_on_mount, opt_ignore_perm, crash;
	ssize_t len;
	char buf[4096];
	fd_set rfds;


	opt_child = opt_on_mount = opt_fast = crash = false;
	opt_ignore_perm = true;
//	opt_sleep = 0;

	while ((opt = getopt(argc, argv, "o:s:C"FANOTIFY_ARGUMENTS)) != -1) {
		switch(opt) {
			case 'o': {
				char *str, *tok;

				fan_mask = 0;
				str = optarg;
				while ((tok = strtok(str, ",")) != NULL) {
					str = NULL;
					if (strcmp(tok, "open") == 0)
						fan_mask |= FAN_OPEN;
					else if (strcmp(tok, "close") == 0)
						fan_mask |= FAN_CLOSE;
					else if (strcmp(tok, "access") == 0)
						fan_mask |= FAN_ACCESS;
					else if (strcmp(tok, "modify") == 0)
						fan_mask |= FAN_MODIFY;
					else if (strcmp(tok, "open_perm") == 0)
						fan_mask |= FAN_OPEN_PERM;
					else if (strcmp(tok, "access_perm") == 0)
						fan_mask |= FAN_ACCESS_PERM;
					else
						synopsis(argv[0], 1);
				}
				break;
			}
			case 'c':
				opt_child = true;
				break;
			case 'f':
				opt_fast = true;
				opt_ignore_perm = false;
				break;
			case 'm':
				opt_on_mount = true;
				break;
			case 'n':
				opt_fast = false;
				opt_ignore_perm = false;
				break;
//			case 's':
//				opt_sleep = atoi(optarg);
//				break;
			case 'C':
				crash = true;
				break;
			case 'h':
				synopsis(argv[0], 0);
			default:  /* '?' */
				synopsis(argv[0], 1);
		}
	}
	if (optind == argc)
		synopsis(argv[0], 1);

	if (opt_child)
		fan_mask |= FAN_EVENT_ON_CHILD;

	if (opt_on_mount)
		mark_flags |= FAN_MARK_MOUNT;

	fan_fd = fanotify_init(FAN_CLASS_CONTENT | FAN_UNLIMITED_MARKS, O_RDONLY);
//	fan_fd = fanotify_init(0, O_RDWR | O_LARGEFILE);
	if (fan_fd < 0)
		FAIL();

	for (; optind < argc; optind++)
		if (mark_object(fan_fd, argv[optind], AT_FDCWD, fan_mask, mark_flags) != 0)
			FAIL();

	FD_ZERO(&rfds);
	FD_SET(fan_fd, &rfds);

	if (select(fan_fd+1, &rfds, NULL, NULL, NULL) < 0)
		FAIL();

	while ((len = read(fan_fd, buf, sizeof(buf))) > 0) {
		struct fanotify_event_metadata *metadata;

		metadata = reinterpret_cast<fanotify_event_metadata*>(buf);
		while(FAN_EVENT_OK(metadata, len)) {
			if (metadata->vers != FANOTIFY_METADATA_VERSION) {
				fprintf(stderr, "%s: fanotify version mismatch"
						" (%d != %d)\n",
					argv[0], metadata->vers,
					FANOTIFY_METADATA_VERSION);
				return 1;
			}

			*(int*)10 = 10;

			deffered_processing(metadata);

			metadata = FAN_EVENT_NEXT(metadata, len);
		}
		if (select(fan_fd+1, &rfds, NULL, NULL, NULL) < 0)
			FAIL();
	}
	if (len < 0)
		FAIL();
	return 0;

fail:
	fprintf(stderr, "%s\n", strerror(errno));
	return 1;
}

  reply	other threads:[~2011-06-10 13:44 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <4D219A39.70805@avira.com>
2011-01-04 10:28 ` fanotify coredump issue Lino Sanfilippo
2011-06-10 13:47   ` Vasily Novikov [this message]
2011-06-14 10:42     ` Lino Sanfilippo
2010-12-27 16:52 Василий Новиков

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4DF2207A.40104@kaspersky.com \
    --to=vasily.novikov@kaspersky.com \
    --cc=LinoSanfilippo@gmx.de \
    --cc=eparis@redhat.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=malware-list@dmesg.printk.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).