変更できない属性セットを持つファイルを検索するには?

変更できない属性セットを持つファイルを検索するには?

構成監査の理由から、ext3ファイルシステムで不変属性セット(pass chattr +i)を持つファイルを検索できるようにしたいと思います。findこのタスクまたは同様のオプションが見つかりません。さてlsattr、各ディレクトリの出力を解析するスクリプトを直接書く必要があるようです。より良いアプローチを提供する標準ユーティリティはありますか?

答え1

これは、コマンドパイプラインを介してlsattrコマンドをパイプすることによって部分的に実行できますgrep

lsattr -R | grep +i

ただし、ファイルext3システム全体に言及すると、検索には他のいくつかのディレクトリが含まれ、/proc無視/devしたいいくつかのエラーが報告されることがあります。おそらくコマンドを実行できます。

lsattr -R 2>/dev/null | grep -- "-i-"

grepPCREツールを使用して、grep「-i-」をより厳密に一致させることができます。

lsattr -R 2>/dev/null | grep -P "(?<=-)i(?=-)"

これは次の状況に適用されます。

$ lsattr -R 2>/dev/null afile | grep -P "(?<=-)i(?=-)"
----i--------e-- afile

しかし、それは完璧ではありません。 immutableフラグの周りに他の属性が有効になっている場合、その属性は一致せず、名前は上記のパターンと一致するファイルにだまされます。たとえば、次のようになります。

$ lsattr -R 2>/dev/null afile* | grep -P "(?<=-)i(?=-)"
----i--------e-- afile
-------------e-- afile-i-am

次のようにパターンをもう少し強化できます。

$ lsattr -a -R 2>/dev/null afile* | grep -P "(?<=-)i(?=-).* "
----i--------e-- afile

しかし、それでも脆弱であるため、ファイルシステムのファイルに基づいて追加の調整が必要です。言うまでもなくツイートファイル名に改行文字を含めると、上記のパターンをかなり簡単に操作できることが注釈に記載されていますgrep

引用する

https://groups.google.com/forum/#!topic/alt.os.linux/LkatROg2SlM

答え2

このスクリプトの目的が監査である場合は、任意のファイル名(改行を含む名前など)を正しく処理することが特に重要です。lsattrこの場合、出力はlsattrあいまいになる可能性があるため、複数のファイルで同時に使用することはできません。

find一度に1つのファイルを繰り返し呼び出すことができます。lsattrしかし、速度は遅くなります。

find / -xdev -exec sh -c '
  for i do
     attrs=$(lsattr -d "$i"); attrs=${attrs%% *}
     case $attrs in
       *i*) printf "%s\0" "$i";;
     esac
  done' sh {} +

lsattrPerl、Python、Rubyなどのあまり珍しい言語を使用し、自分で作業を行うことをお勧めします。 ioctlシステムコールをlsattr発行FS_IOC_GETFLAGSし、ファイルのインデックスノードフラグ。これはPythonの概念証明です。

#!/usr/bin/env python2
import array, fcntl, os, sys
S_IFMT =  0o170000
S_IFDIR = 0o040000
S_IFREG = 0o100000
FS_IOC_GETFLAGS = 0x80086601
EXT3_IMMUTABLE_FL = 0x00000010
count = 0
def check(filename):
    mode = os.lstat(filename).st_mode
    if mode & S_IFMT not in [S_IFREG, S_IFDIR]:
        return
    fd = os.open(filename, os.O_RDONLY)
    a = array.array('L', [0])
    fcntl.ioctl(fd, FS_IOC_GETFLAGS, a, True)
    if a[0] & EXT3_IMMUTABLE_FL: 
        sys.stdout.write(filename + '\0')
        global count
        count += 1
    os.close(fd)
for x in sys.argv[1:]:
    for (dirpath, dirnames, filenames) in os.walk(x):
        for name in dirnames + filenames:
            check(os.path.join(dirpath, name))
if count != 0: exit(1)

答え3

私に正しい方向(私が見逃したスイッチ-R)を教えてくれたRamesh、slm、Stéphaneに感謝しますlsattr。残念ながら、これまではどんな答えも正解ではないようです。

私は次のことを思い出しました。

lsattr -aR .//. | sed -rn '/i.+\.\/\/\./s/\.\/\///p'

これにより、ファイルが変更不可能に見えるように改行を使用するのを防ぎます。もちろんいいえファイルを変更できないようにし、ファイル名に改行を含めないようにします。しかし、そのようなファイルはルートでこのように生成される必要があるため、私のユースケースでは、そのようなファイルが私のファイルシステムに存在しないと確信できます。 (このアプローチは、rootユーザーが破損する可能性がある侵入検知には適していませんが、lsattr同じrootユーザーに属する同じシステムユーティリティを使用するのには適していません。)

答え4

使用するには遅すぎると、find -exec解析出力lsattrは次のようになります。同様に信頼できないls、Pythonを次のように使用します。ザイルズの答えioctlPythonインタプリタが32ビットか64ビットかによって定数を選択する必要があります。

当面の問題はやや低レベルなので、より低いレベルに進みます。 C ++はスクリプト言語ほど悪くはありません:)ボーナスとしてCプリプロセッサのすべての機能を使用してシステムCヘッダファイルにアクセスできます。 。

次のプログラムは、ファイルシステム内に残っている不変ファイル、つまりマウントポイントを超えないファイルを検索します。必要に応じてマウントポイントにわたって明確なツリーを検索するには、呼び出しからFTW_MOUNTフラグを削除しますnftw。そしてシンボリックリンクに従わない。これに従うには、FTW_PHYSマーカーを削除してください。

#define _FILE_OFFSET_BITS 64
#include <iostream>
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <sys/stat.h>
#include <ftw.h>

bool isImmutable(const char* path)
{
    static const int EXT3_IMMUTABLE_FLAG=0x10;

    const int fd=open(path,O_RDONLY|O_NONBLOCK|O_LARGEFILE);
    if(fd<=0)
    {
        perror(("Failed to open file \""+std::string(path)+"\"").c_str());
        return false;
    }
    unsigned long attrs;
    if(ioctl(fd,FS_IOC_GETFLAGS,&attrs)==-1)
    {
        perror(("Failed to get flags for file \""+std::string(path)+"\"").c_str());
        close(fd);
        return false;
    }
    close(fd);
    return attrs & EXT3_IMMUTABLE_FLAG;
}

int processPath(const char* path, const struct stat* info, int type, FTW* ftwbuf)
{
    switch(type)
    {
    case FTW_DNR:
        std::cerr << "Failed to read directory: " << path << "\n";
        return 0;
    case FTW_F:
        if(isImmutable(path))
            std::cout << path << '\n';
        return 0;
    }
    return 0;
}

int main(int argc, char** argv)
{
    if(argc!=2)
    {
        std::cerr << "Usage: " << argv[0] << " dir\n";
        return 1;
    }
    static const int maxOpenFDs=15;
    if(nftw(argv[1],processPath,maxOpenFDs,FTW_PHYS|FTW_MOUNT))
    {
        perror("nftw failed");
        return 1;
    }
}

関連情報