Post List

Global Naming CreateFileMapping

HANDLE CreateFileMappingA( HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect, DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName );



[ lpName ] 

File Mapping Object의 이름으로 NULL 인 경우 이름없이 만들어진다.
이미 mapping 되어있는 object의 name과 일치한다면 flProtect가 지정하는 보호기능을 사용하여 object에 access를 요청한다.

또 한가지 ! lpName에 "Global" 접두사를 붙이는 경우 (ex: lpName = "Global\\test.mmf") global namespace를 만들수 있는데
이는 SeCreateGlobalPrivilege 권한이 필요하다고 나와있다.

[ SeCreateGlobalPrivilege ]


알아낸 바로는 Administrators 그룹, 서비스 계정의 경우 기본으로 SeCreateGlobalPrivilege 권한이 있다고 한다.
따라서 일반 응용 프로그램의 경우에 일반적으로 관리자 권한으로 실행하지 않으면 CreateFileMapping 함수에서 0x5 값이 return 되며,
이는 ERROR_ACCESS_DENIED 이다.

<Sample Source>

#include <stdio.h>
#include <windows.h>

#define THREAD_NUM    10
#define MMFNAME        "Global\\test_mmf"
#define PAGE_SIZE    0x100

int main()
{
    HANDLE hMapping;
    char *buf;
    hMapping = CreateFileMapping(
            INVALID_HANDLE_VALUE,
            NULL,
            PAGE_READWRITE,
            0,
            PAGE_SIZE,
            MMFNAME
    );
    if(hMapping == NULL) {
        printf("hMapping is NULL (%d)\n", GetLastError());
        return 0;
    }
    buf = (char *)MapViewOfFile(hMapping, PAGE_READONLY, 0, 0, PAGE_SIZE);
    if(buf == NULL) {
        printf("buf is NULL (%d)\n", GetLastError());
        CloseHandle(hMapping);
        return 0;
    }
    strcat(buf, "test mmf code !\0");
    printf("BUF: %s\n", buf);

    UnmapViewOfFile(buf);
    CloseHandle(hMapping);

    return 0;
}



<추가>

.NET과 관리자 권한으로 실행된 daemon에서 mmf 통신을 시도하려다가 access 에러가 발생하였다. 

.NET이 먼저 FileMapping을 하면 관리자권한의 daemon process가 정상적으로 접근해서 read/write가 정상적으로 진행됬는데, 
daemon process가 먼저 FileMapping을 한 경우에 .NET이 access denied 가 발생하였다.


아직까지는 정확한 원인은 모르지만 관리자권한의 daemon process에서 CreateFileMapping을 통해 생성한 object에 .NET이 접근할 때 해당 권한을 상속받지 못하는것으로 추측된다.

Stack Overflow에서 찾은 내용으로 해결하였는데 모두 이해하지는 못해서 잘못된 내용일 수도 있지만 우선은 정리해 둔다.

DWORD SetSecurityInfo( HANDLE handle, SE_OBJECT_TYPE ObjectType, SECURITY_INFORMATION SecurityInfo, PSID psidOwner, PSID psidGroup, PACL pDacl, PACL pSacl );


[ ObjectType ]

typedef enum _SE_OBJECT_TYPE { SE_UNKNOWN_OBJECT_TYPE, SE_FILE_OBJECT, SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_LMSHARE, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT, SE_DS_OBJECT, SE_DS_OBJECT_ALL, SE_PROVIDER_DEFINED_OBJECT, SE_WMIGUID_OBJECT, SE_REGISTRY_WOW64_32KEY, SE_REGISTRY_WOW64_64KEY } SE_OBJECT_TYPE;

handle object의 유형으로 enum으로 정의되어있는 상수들 중 하나를 넣으면 된다. 

[ SecurityInfo ]

설정할 보안 정보의 유형을 나타내는 bit flag.
이 부분을 아직 이해를 못하였다. 

[ pDacl ]

object에 대한 DACL 포인터로 access 권한을 설정할 수 있는것으로 보인다.
NULL로 설정할 경우 object에 대한 (모든) access 권한이 모든 사용자에게 부여된다.

<sample code1>
#include <stdio.h>
#include <windows.h>


#define THREAD_NUM    10
#define MMFNAME        "Global\\test_mmf"
#define PAGE_SIZE    0x100


int main()
{
    HANDLE hMapping;
    char *buf;
    hMapping = CreateFileMapping(
            INVALID_HANDLE_VALUE,
            NULL,
            PAGE_READWRITE,
            0,
            PAGE_SIZE,
            MMFNAME
    );
    if(hMapping == NULL) {
        printf("hMapping is NULL (%d)\n", GetLastError());
        return 0;
    }

    SetSecurityInfo(hMapping , SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, 0, 0, (PACL) NULL, NULL);
    buf = (char *)MapViewOfFile(hMapping ,FILE_MAP_ALL_ACCESS, 0, 0,PAGE_SIZE);

    if(buf == NULL) {
        printf("buf is NULL (%d)\n", GetLastError());
        CloseHandle(hMapping);
        return 0;
    }
    strcat(buf, "test mmf code !\0");
    printf("BUF: %s\n", buf);


    UnmapViewOfFile(buf);
    CloseHandle(hMapping);


    return 0;
}



댓글 없음:

댓글 쓰기