Bir işlemin aynı dosya adı için farklı bir dosya okuması


9

Bir dosyayı okuyan bir uygulamam var. En diyelim ProcessName ve dosya ~ / .configuration . İşlem adı çalıştığında daima ~ / .configuration yazar ve farklı yapılandırılamaz. Ayrıca, "~ / .configuration" 'a dayanan, öncesi ve sonrası, ancak işlem adı çalışırken buna bağlı olmayan başka uygulamalar da vardır .

Paketleme işlem_adı içeriğini değiştiren bir komut ~ / .configuration bir seçenek olmakla birlikte, (içindekiler dışarı takas ederken) bu arzu değildir bu yüzden, söz konusu dosyanın önceki içeriğini kaybetti nerede Geçenlerde, bir elektrik kesintisi vardı.

LD_DEBUG=files processnameBelirli bir dosyayı okumaya çalıştığında bir işlemi farklı içerikleri okumaya kandırmanın bir yolu (belki de uzaktan ilgili bir şey kullanmak ?) Var mı ? Yürütülebilir dosyadaki dosya adını aramak ve değiştirmek biraz fazla invazivdir, ancak aynı zamanda çalışması gerekir.

open()Aramayı devralan bir çekirdek modülü yazmanın mümkün olduğunu biliyorum ( https://news.ycombinator.com/item?id=2972958 ), ancak daha basit veya daha temiz bir yol var mı?

DÜZENLEME: ararken ~ / .configuration yılında ProcessName ben okumadan önce başka dosya hakkı okumaya çalıştım keşfetti yürütülebilir ~ / .configuration . Sorun çözüldü.


2
Bu LD_PRELOAD, biraz benzer bir problemde olduğu gibi veya FUSE yoluyla yapılabilir , ancak mevcut herhangi bir uygulamayı bilmiyorum.
Gilles 'SO- kötü olmayı bırak'

Yanıtlar:


6

Linux'un son sürümlerinde , bağlanma ad alanının paylaşımını kaldırabilirsiniz . Yani, sanal dosya sistemini farklı şekilde görüntüleyen işlemleri başlatabilirsiniz (dosya sistemleri farklı monte edilmişse).

Bu da yapılabilir chroot, ancak unsharedavanıza daha fazla adapte olur.

Gibi chroot, unsharemount ad alanına ayrıcalıklı süper kullanıcı gerekir .

Yani, var demek ~/.configurationve ~/.configuration-for-that-cmddosyaları.

~/.configurationAslında orada bir bağlama aparatı olan bir işlemi başlatabilir ~/.configuration-for-that-cmdve orada çalıştırabilirsiniz that-cmd.

sevmek:

sudo unshare -m sh -c "
   mount --bind '$HOME/.configuration-for-that-cmd' \
                '$HOME/.configuration' &&
     exec that-cmd"

that-cmdve tüm soyundan gelen süreçler farklı bir görecek ~/.configuration.

that-cmdyukarıdaki gibi çalışır root, kullanımı sudo -u another-user that-cmdbir şekilde çalıştırmak için gerekirse başka kullanıcı .


Sanırım çözümünüz şimdiye kadar verilen ikisinden daha iyi (ve OP'nin peşinde olduğu şey göz önüne alındığında, zamana veya bir algılama sürecinin sonuçlarına göre yeniden yönlendirmek benim için havalı görünüyor), ancak bence tek bir dosya istiyorlar farklı göstermek için. Bu yüzden muhtemelen başka bir yere monte etmek ve gerçek yönlendirme noktası olarak hareket etmek için farklı montaj noktalarına güvenerek bir sembolik bağlantı kullanmak zorunda kalacaklardı.
2013 Bratchley

1
@JoelDavis, sadece dizin olanları değil, herhangi bir dosyayı bağlayabilirsiniz.
Stéphane Chazelas

TIL. Bununla birlikte güvenlik kontrolleri var mı? Ben (/ etc / fstab gelen bağlama) olduğu bir alt dizini kullanarak denedim ve "Bir dizin değil" döndürdü ama hemen hemen aynı şeyi yaptı /testve sorunsuz çalıştı.
Bratchley

Aslında, nm farkı görebiliyorum, ilk kez bir dizine ve sonraki bir dosyaya yaptım. Sadece VFS'yi uygun şekilde yönlendirdiğini / değiştireceğini varsayıyordum. Her neyse, yeni oyuncak için teşekkürler.
Bratchley

3

Yumuşak bağlantılar.

İki yapılandırma dosyası oluşturun ve çoğu zaman yumuşak bir bağlantıyla birini işaret edin, ancak özel uygulama çalışırken yumuşak bağlantıyı diğerini gösterecek şekilde değiştirin.

(Bunun korkunç bir saldırı olduğunu biliyorum, ancak dosya içeriğini değiştirmekten biraz daha güvenilir).

Veya $ HOME'u değiştirin.

Can sıkıcı işlemi başlatan komut dosyasında, $ HOME'u normal $ HOME dizini altında bir şey olacak şekilde ayarlayın ve uygulamanız orada bulunan yapılandırma dosyasını kullanmalıdır (test edildi ve temel kabuk komutları için çalışıyor, ~ $ HOME'a genişliyor).

İşlemin başka ne yaptığına bağlı olarak, $ HOME değişikliğinin istenmeyen sonuçları olabilir (yani çıktı dosyaları yanlış yerde olabilir).


1

Bunu LD_PRELOAD hile kullanarak yapabilirsiniz . İşte belirli bir önekle başlayan yolları başka bir konuma eşleyen bir uygulama. Kod da github üzerindedir .

Örneğin, /etc/kök olmadan bir dosyanın varlığını taklit edebilirsiniz. Bu, dosya /etc/ownCloud/sync-exclude.listolmadığında çalışmayı reddeden owncloud istemcisi için gerekliydi .

Bir dizini diğerine eşlemek için open()ve open64()işlevlerini geçersiz kılarak çalışır , örneğin tüm open()çağrılar /etc/ownCloud/...yönlendirilebilir /home/user1/.etc/ownCloud/....

Sadece programınızı ayarlayın path_map, sonra derleyin ve programınızı önceden yüklenmiş lib ile çalıştırın:

gcc -std=c99 -Wall -shared -fPIC path-mapping.c -o path-mapping.so -ldl

LD_PRELOAD=/path/to/my/path-mapping.so someprogram

Kaynak kodu path-mapping.c:

#define _GNU_SOURCE

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <dlfcn.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdarg.h>
#include <malloc.h>

// List of path pairs. Paths beginning with the first item will be
// translated by replacing the matching part with the second item.
static const char *path_map[][2] = {
    { "/etc/ownCloud/", "/home/user1/.etc/ownCloud/" },
};

__thread char *buffer = NULL;
__thread int buffer_size = -1;

typedef FILE* (*orig_fopen_func_type)(const char *path, const char *mode);
typedef int (*orig_open_func_type)(const char *pathname, int flags, ...);

static int starts_with(const char *str, const char *prefix) {
    return (strncmp(prefix, str, strlen(prefix)) == 0);
}

static char *get_buffer(int min_size) {
    int step = 63;
    if (min_size < 1) {
        min_size = 1;
    }
    if (min_size > buffer_size) {
        if (buffer != NULL) {
            free(buffer);
            buffer = NULL;
            buffer_size = -1;
        }
        buffer = malloc(min_size + step);
        if (buffer != NULL) {
            buffer_size = min_size + step;
        }
    }
    return buffer;
}

static const char *fix_path(const char *path)
{
    int count = (sizeof path_map) / (sizeof *path_map); // Array length
    for (int i = 0; i < count; i++) {
        const char *prefix = path_map[i][0];
        const char *replace = path_map[i][1];
        if (starts_with(path, prefix)) {
            const char *rest = path + strlen(prefix);
            char *new_path = get_buffer(strlen(path) + strlen(replace) - strlen(prefix));
            strcpy(new_path, replace);
            strcat(new_path, rest);
            printf("Mapped Path: %s  ==>  %s\n", path, new_path);
            return new_path;
        }
    }
    return path;
}


int open(const char *pathname, int flags, ...)
{
    const char *new_path = fix_path(pathname);

    orig_open_func_type orig_func;
    orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open");

    // If O_CREAT is used to create a file, the file access mode must be given.
    if (flags & O_CREAT) {
        va_list args;
        va_start(args, flags);
        int mode = va_arg(args, int);
        va_end(args);
        return orig_func(new_path, flags, mode);
    } else {
        return orig_func(new_path, flags);
    }
}

int open64(const char *pathname, int flags, ...)
{
    const char *new_path = fix_path(pathname);

    orig_open_func_type orig_func;
    orig_func = (orig_open_func_type)dlsym(RTLD_NEXT, "open64");

    // If O_CREAT is used to create a file, the file access mode must be given.
    if (flags & O_CREAT) {
        va_list args;
        va_start(args, flags);
        int mode = va_arg(args, int);
        va_end(args);
        return orig_func(new_path, flags, mode);
    } else {
        return orig_func(new_path, flags);
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.