1

背景:

共有環境でルートディレクトリをオンザフライで設定できるnginx(Webサーバー)のモジュールを作成しています。ホスティング ユーザーごとに 1 つずつ、他のディレクトリを含むディレクトリがあります。要求されたドメインに関連するディレクトリ パスが与えられた場合、それが属するユーザーを特定する必要があります。

--public_dir
---user_1
---user_2
----com/example/www/_public/
---user_3

www.example.com は com/example/www に変換され、関数は「user_2」を返す必要があります

問題:

public_dir を開いてトラバースし、各第 1 レベルのディレクトリ (ユーザー) で com/example/www/_public/ の存在を確認し、結果をキャッシュすることで、これを成功させました。関数が最初に呼び出されたときに、すべてが期待どおりに実行されます。public_dir を再度開こうとすると、2 回目のセグメンテーション違反が発生します (前の関数呼び出しで正常に閉じられています)。

#define NGX_SHARED_ENV_SHARED_DIR "/var/www/public/"
#define NGX_SHARED_ENV_PUBLIC_DIR "_public"

char* ownerFromDir(char *dir){
    char *owner;
    char fullPath[strlen(NGX_SHARED_ENV_SHARED_DIR)+strlen(dir)+128];
    struct dirent *e;
    struct stat sb;

// ------------ERROR IN HERE----------------------------

    fprintf(stderr, "Before opendir\n");
    DIR *sharedDir = opendir(NGX_SHARED_ENV_SHARED_DIR);
    fprintf(stderr, "After opendir\n");

// -----------------------------------------------------

    if(sharedDir){
        while((e=readdir(sharedDir))!=NULL){
            //is the entry a directory?
            if(e->d_type!=DT_DIR){ 
                continue;
            }
            if(strcmp(e->d_name, ".")==0 || strcmp(e->d_name, "..")==0){
                continue;
            }
            // build a path to check for /var/www/public/userX/com/example/www/_public
            snprintf(fullPath, sizeof(fullPath), "%s%s/%s/%s", NGX_SHARED_ENV_SHARED_DIR, e->d_name, dir, NGX_SHARED_ENV_PUBLIC_DIR);
            stat(fullPath, &sb);
            //if a matching directory is found then copy the entry name into owner
            if(S_ISDIR(sb.st_mode)){ 
                int len = 1 + (int) strlen(e->d_name);
                owner = (char*) malloc(sizeof(char)*len);
                free(owner);
                memcpy(owner, &(e->d_name), len);
                break;
            }
        }
        closedir(sharedDir);
    }
    return owner;
}

gcc -g でデバッグ フラグを指定してコンパイルしても、gdb はあまり役に立ちません。

Breakpoint 1, ownerFromDir (dir=0x603450 "com/example") at ngx_module.h:43
43  char* ownerFromDir(char *dir){
(gdb) step
45      char fullPath[strlen(NGX_SHARED_ENV_SHARED_DIR)+strlen(dir)+128];
(gdb) step
48      fprintf(stderr, "Before opendir\n");
(gdb) step
Before opendir
49      DIR *sharedDir = opendir(NGX_SHARED_ENV_SHARED_DIR);
(gdb) step
50      fprintf(stderr, "After opendir\n");
(gdb) step
After opendir
51      if(sharedDir){
(gdb) continue
Continuing.

Breakpoint 1, ownerFromDir (dir=0x60b4a0 "com/example2") at ngx_module.h:43
43  char* ownerFromDir(char *dir){
(gdb) step
45      char fullPath[strlen(NGX_SHARED_ENV_SHARED_DIR)+strlen(dir)+128];
(gdb) step
48      fprintf(stderr, "Before opendir\n");
(gdb) step
Before opendir
49      DIR *sharedDir = opendir(NGX_SHARED_ENV_SHARED_DIR);
(gdb) step

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a99df2 in ?? () from /lib/x86_64-linux-gnu/libc.so.6

編集:バックトレース

(gdb) backtrace
#0  0x00007ffff7a99df2 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff7a9b446 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007ffff7a9dfc5 in malloc () from /lib/x86_64-linux-gnu/libc.so.6
#3  0x00007ffff7ad651b in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#4  0x0000000000400aea in ownerFromDir (dir=0x60b4a0 "com/example2") at ./ngx_module.h:48
#5  0x0000000000400cb2 in ownerFromDom (domain=0x40116c "example2.com") at ./ngx_module.h:82
#6  0x0000000000400f3f in testOwner (domain=0x40116c "example2.com", expect=0x401150 "user2") at ./ngx_module.c:45
#7  0x0000000000400e27 in runTests () at ./ngx_module.c:29
#8  0x0000000000400d0b in main (argc=1, argv=0x7fffffffe708) at ./ngx_module.c:10

誰でも私を正しい方向に向けることができますか?

4

1 に答える 1

2

あなたのコードは:

        if(S_ISDIR(sb.st_mode)){
            int len = 1 + (int) strlen(e->d_name);
            owner = (char*) malloc(sizeof(char)*len);
            free(owner);
            memcpy(owner, &(e->d_name), len);
            break;
        }

そしてそれは次のことにつながります:

return owner;

メモリを解放したため、memcpy()は無効になり (アクセスする権利のないメモリにアクセスする)、戻り値は少なくとも危険であり、間違いなく無効です (解放されたメモリへのポインタを返しています)。

free()このコードの を削除します。呼び出しコードで何が問題なのかは誰にもわかりませんが、適度にもっともらしい推測は「free()返された値があなた」であり、これは二重解放であり、これも深刻なノーノーです。

書かれているmemcpy()ように、ヒープが簡単に破損する可能性があります。二重解放はヒープを破壊する可能性があります。したがって、ヒープ破損の原因が 2 つあると、結果としてどこかでクラッシュが発生する可能性が非常に高くなり、opendir()メモリ割り当てが行われるため、もっともらしい犠牲者となります。その前にメモリ割り当てを行った場合、代わりにクラッシュする可能性があります。

于 2013-09-20T05:05:24.887 に答える