LINUX.ORG.RU

ошибка сигментирования в so

 , , ,


2

2

здравствуйте пишу динамическую библиотеку для перехвата системного вызова open которая должна тупо писать лог файл «такой-то» открыт успешно

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include <linux/fs.h>
#include <iss_mac.h>
#include <fstream>

using namespace std;
extern "C" int open(const char *filename, int flags, ...)
{
    mac_label l;
    mac_attr_t attr;

    int (*open_orig)(const char *filename, int flags, ...)=NULL;  //укзатель на оригинальный Open
    ssize_t (*write_orig)(int __fd,__const void *__buf,size_t __n)=NULL; //на оригинальный read
    ssize_t (*read_orig)(int __fd,void *__buf,size_t __nbytes)=NULL;
    int (*close_orig)(int __fd)=NULL; // на оригинальный close



    open_orig = (int (*)(const char*, int, ...))dlsym(RTLD_NEXT, "open");
    write_orig=(ssize_t (*)(int __fd,__const void *,size_t))dlsym(RTLD_NEXT,"write");
    close_orig=(int (*)(int __fd))dlsym(RTLD_NEXT,"close");
    read_orig=(ssize_t (*)(int __fd, void *__buf, size_t __nbytes))dlsym(RTLD_NEXT,"read");

    statmac(filename,&l,&attr);
    //int urs=l.lev;
    //int cats=l.cat;
    int urs=0;
    int cats=0;
    if (urs==0 || cats==0)
    {
        char buf[100];
        memset(buf,0,sizeof(buf));
        sprintf(buf,"файл %s открыт успешно\n",filename);
        int opis=open_orig("/openlog",O_CREAT | O_WRONLY | O_APPEND,0777);
        if (opis>0)
        {
            write_orig(opis,buf,strlen(buf));
            close_orig(opis);
        }
    }
    bool flag=false;
    char buf2[200];
    memset(buf2,0,sizeof(buf2));
    ifstream fal("/usr/local/szi/LDB/Groups_Obj",ios::in);
    if (fal.is_open())  
    {
        while (!fal.eof())
        {
            fal.getline(buf2,200);
            int i=0;
            char *pch=strtok(buf2,"\005");
            while (pch != NULL)
            {
                i=i+1;
                if (i==4)
                {
                    if (strstr(filename,pch)!=NULL)
                    {
                        sprintf(buf2,"файл %s открыт успешно\n",pch);
                        flag=true;
                        break;
                    }
                }
                pch = strtok (NULL,"\005");
            }
        }
        fal.close();
        if (flag==true)
        {
            int opis=open_orig("/openlog",O_CREAT | O_WRONLY | O_APPEND,0777);
            if (opis>0)
            {
                write_orig(opis,buf2,strlen(buf2));
                close_orig(opis);
            }
        }
    }
    va_list va;
    va_start(va, flags);
    mode_t mode = va_arg(va, mode_t);
    va_end(va);
    return open_orig(filename, flags,mode);  //передаем в оригинальную функцию open
}

компилирую

g++ -fPIC -shared main.cpp -ldl -lszi-com -o main.so -Wl,--no-undefined

запуск мс со скриптом происходит нормально

unset LD_PRELOAD
LD_PRELOAD=/main.so /usr/bin/mc

а допустим если запускать текстовый редактор textedit
unset LD_PRELOAD
LD_PRELOAD=/main.so /usr/bin/elk-textedit
то пишет ошибка сегментирования

ОС МСВС 5.7 основана на red hat

Для начала, такие вещи не пишут на C++. Я писал на C, и то тяжеловато было, уже подумывал про ассемблер. Сделай на си - может, что-то поменяется.

Если с gdb не выйдет, то вставляй printf, ищи где падает.

Потом, на фиг не надо тут varargs. Просто задай mode как обычный аргумент. При этом fcntl.h включать не надо.

iss_mac.h szi

Гы, аж на ностальгию пробило :D

anonymous ()
Ответ на: комментарий от anonymous

В пятом рхеле можно уже замутить. Я же не говорю, что там есть такие замуты, я просто напоминаю, что такие вещи могут помешать сбору дампа и стоит проверить. Я с МСВС давно дела не имел и вполне возможно, что они там для своих целей эту хрень подкрутили. Кароче просто дал совет, куда копать, если корка не собирается.

DELIRIUM ★★★★★ ()

Для начала, такие вещи не пишут на C++

плюсую анонимуса, пиши на чистом C.
Я бы ещё вынес указатели на оригинальные функции в глобальные переменные и проверку добавил как-то так:

if (open_orig == NULL) {
    open_orig = (int (*)(const char*, int, ...))dlsym(RTLD_NEXT, "open");
    write_orig=(ssize_t (*)(int __fd,__const void *,size_t))dlsym(RTLD_NEXT,"write");
    close_orig=(int (*)(int __fd))dlsym(RTLD_NEXT,"close");
    read_orig=(ssize_t (*)(int __fd, void *__buf, size_t __nbytes))dlsym(RTLD_NEXT,"read");
}

superuser ()
Последнее исправление: superuser (всего исправлений: 1)
Ответ на: комментарий от superuser

вопрос такой когда я буду переопределять метод write мне нужно знать имя файла который записывается(перезаписывается)... получается что при вызове opena мне нужно делать multimap с парой <дескриптор, имя файла> и соответственно каждому дескриптору прикреплять имя файла а потом уже в методе write смотреть какое имя файла соответствует дескриптору ?

kold2015 ()
Ответ на: комментарий от superuser

появился еще один вопрос. а как мне собственно узнать какое приложение вызвало метод open? из под ядра вроде как current->comm а как из пространства пользователя узнать(из моей программы)...?

kold2015 ()