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;
}
next prev parent 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).