"O_PATH"는 무엇을 위해, 어떻게 사용해야 합니까?

"O_PATH"는 무엇을 위해, 어떻게 사용해야 합니까?

저는 Linux 4.x 기반 배포판을 사용하고 있으며 최근에 커널의 open()시스템 호출이 O_PATH공개 플래그를 지원하는 것을 발견했습니다.

해당 페이지에는 이론적으로 사용할 수 있는 시스템 호출 목록이 있지만 man그 아이디어가 무엇인지 잘 모르겠습니다. open(O_PATH)파일이 아닌 디렉토리만 사용 합니까 ? 이렇게 하면 디렉터리 경로 대신 파일 설명자를 사용하는 이유는 무엇입니까? 또한 거기에 나열된 대부분의 시스템 호출은 디렉토리별로 다르지 않은 것 같습니다. 그러면 O_PATH해당 디렉토리를 파일 설명자로 사용하여 일반 파일도 열 수 있습니까? 아니면 파일 설명자를 구했지만 기능이 제한되어 있나요?

O_PATH누군가 우리가 그것을 어떻게 사용해야 하고 어떻게 사용해야 하는지 에 대해 설득력 있는 설명을 줄 수 있습니까 ?

노트:

  • 필요하지 않는 한 그것이 어떻게 발전했는지에 대한 이력을 설명할 필요가 없습니다(관련 매뉴얼 페이지에 Linux 2.6.x, 3.5 및 3.6의 변경 사항이 언급되어 있습니다). 단지 현재 위치가 궁금할 뿐입니다.
  • libc나 다른 상위 수준 기능만 사용하라고 말하지 마세요. 저도 알고 있습니다.

답변1

설명open(2)매뉴얼 페이지는 시작하기 위한 몇 가지 단서를 제공합니다.

   O_PATH (since Linux 2.6.39)
          Obtain a file descriptor that can be used for two purposes:
          to  indicate  a location in the filesystem tree and to per‐
          form operations that act  purely  at  the  file  descriptor
          level.  The file itself is not opened, and other file oper‐
          ations  (e.g.,  read(2),  write(2),  fchmod(2),  fchown(2),
          fgetxattr(2), ioctl(2), mmap(2)) fail with the error EBADF.

때로는 파일이나 디렉터리를 열고 싶지 않을 때도 있습니다. 대신 특정 작업을 수행하려면 이 파일 시스템 개체에 대한 참조만 필요합니다(예: fchdir()열린 파일 설명자로 참조하는 디렉터리 O_PATH). 따라서 주목하는 것이 중요합니다. 이것이 우리의 목적이라면 O_PATH파일 자체가 실제로 열리지 않기 때문에 여는 것이 더 저렴해야 합니다.

그리고 덜 중요한 점: 존재하기 전에는 O_PATH파일 시스템 객체에 대한 참조를 얻는 방법은 를 사용하여 객체를 여는 것이었습니다 O_RDONLY. 그러나 이를 사용하려면 O_RDONLY객체에 대한 읽기 권한이 필요합니다. 그러나 실제로 개체를 읽을 필요가 없는 사용 사례도 많습니다. 예를 들어 바이너리를 실행하거나 디렉터리( fchdir())에 액세스하거나 디렉터리를 통해 디렉터리 내의 개체에 액세스하는 등입니다.

"*at()" 시스템 호출과 함께 사용됩니다.

의 일반적인(유일한 것은 아님) 용도는 , 등과 같은 O_PATH"*at" 시스템 호출과 함께 사용하기 위해 참조할 수 있도록 디렉토리를 여는 것입니다. 비슷한 이름( ,, 으로 대략적으로 생각할 수 있는 이 시스템 호출 계열은 여러 가지 목적으로 사용됩니다. 디렉토리 경로 대신 파일 설명자를 사용하려면?" ". 매뉴얼 페이지를 더 자세히 살펴보면 다음 텍스트를 찾을 수 있습니다("*at" 시스템 호출 근거가 있는 부제목 아래). openat()fstatat()fchownat()open()fstat()fchown()open(2)

   First,  openat()  allows  an  application to avoid race conditions
   that could occur when using open() to open  files  in  directories
   other  than  the current working directory.  These race conditions
   result from the fact that some component of the  directory  prefix
   given  to  open()  could  be  changed in parallel with the call to
   open().  Suppose, for example, that we wish  to  create  the  file
   path/to/xxx.dep  if  the  file path/to/xxx exists.  The problem is
   that between the existence check and the file creation step,  path
   or  to  (which might be symbolic links) could be modified to point
   to a different location.  Such races can be avoided by  opening  a
   file descriptor for the target directory, and then specifying that
   file descriptor as the dirfd argument of (say) fstatat(2) and ope‐
   nat().

이를 좀 더 구체적으로 설명하자면... 현재 작업 디렉터리 외부의 디렉터리에서 여러 작업을 수행하려는 프로그램이 있다고 가정해 보겠습니다. 즉, 사용하는 파일 이름의 일부로 일부 디렉터리 접두어를 지정해야 한다는 의미입니다. 예를 들어, 경로 이름이 이라고 가정하면 /dir1/dir2/file다음 두 가지 작업을 수행하려고 합니다.

  1. 몇 가지 확인을 수행합니다 /dir1/dir2/file(예: 파일 소유자 또는 마지막 수정 날짜 등).
  2. 이 검사 결과에 만족한다면 동일한 디렉터리에서 다른 파일 시스템 작업을 수행할 수도 있습니다(예: /dir1/dir2/file.new.

이제 먼저 전통적인 경로 이름 기반 시스템 호출을 사용하여 모든 작업을 수행했다고 가정해 보겠습니다.

struct stat stabuf;
stat("/dir1/dir2/file", &statbuf);
if ( /* Info returned in statbuf is to our liking */ ) {
    fd = open("/dir1/dir2/file.new", O_CREAT | O_RDWR, 0600);
    /* And then populate file referred to by fd */
}

이제 디렉터리 접두사에서 /dir1/dir2구성 요소 중 하나(예 dir2: )가 실제로 기호 링크(디렉토리 참조)이고통화 stat()사이open()dir2악의적인 행위자는 다른 디렉터리를 가리키도록 심볼릭 링크의 대상을 변경할 수 있습니다 . 이것은 시간 경쟁 조건을 사용하는 고전적인 시간 확인입니다. 우리 프로그램은 한 디렉터리에서 파일을 검사했지만 속여서 다른 디렉터리(아마도 보안에 민감한 디렉터리)에 파일을 생성했습니다. 여기서 중요한 점은 경로 이름은 /dir/dir2동일해 보이지만 참조하는 내용이 완전히 달라진다는 것입니다.

이러한 문제를 피하기 위해 "*at" 호출을 사용할 수 있습니다. 먼저 작업을 수행할 디렉터리에 대한 핸들을 얻습니다.

dirfd = open("/dir/dir2", O_PATH);

여기서 핵심 포인트 dirfd안정적인/dir1/dir2를 호출할 때 경로가 참조하는 디렉터리에 대한 참조입니다 open(). 이후에 기호 링크의 대상이 변경되더라도 이것이 참조하는 내용에는 dir2영향을 미치지 않습니다 . 이제 dirfd위의 stat()and 호출에 상응하는 "*at" 호출을 사용하여 검사 + 작업을 수행 할 수 있습니다 open().

fstatat(dirfd, ""file", &statbuf)
struct stat stabuf;
fstatat(dirfd, "file", &statbuf);
if ( /* Info returned in statbuf is to our liking */ ) {
    fd = openat(dirfd, "file.new", O_CREAT | O_RDWR, 0600);
    /* And then populate file referred to by fd */
}

이 단계에서는 경로 이름의 심볼릭 링크를 조작해도 /dir/dir2아무런 효과가 없습니다. 확인( fstatat()) 및 조작( openat())은 동일한 디렉토리에서 발생하는 것이 보장됩니다.

"*at()" 호출을 사용하는 또 다른 목적이 있는데, 이는 멀티 스레드 프로그램에서 "스레드별 현재 작업 디렉터리"라는 아이디어와 관련이 있지만(열린 디렉터리를 다시 사용할 수 있음 O_PATH) 이 용도가 아닐까 생각됩니다. 귀하의 질문과 관련이 있을 수 있습니다. 질문은 별로 관련이 없습니다. open(2)더 알고 싶으면 매뉴얼 페이지를 읽어보도록 하겠습니다.

일반 파일의 파일 설명자와 함께 사용됩니다.

일반 파일의 한 가지 용도 O_PATH는 실행 권한이 있는 바이너리 파일을 여는 것입니다(그러나 반드시 읽기 권한은 아니므로 파일을 여는 데 사용할 수 없습니다 O_RDONLY). 그런 다음 이 파일 설명자를 다음으로 전달할 수 있습니다.fexecve(3)프로그램을 실행합니다. 본질적으로 fexecve(fd, argv, envp)모든 주장은 다음과 같습니다 .fd

snprintf(buf, "/proc/self/fd/%d", fd);
execve(buf, argv, envp);

(glibc 2.27부터 시작하더라도 구현에서는 대신 다음을 사용합니다.execveat(2)시스템 호출을 제공하는 커널의 시스템 호출입니다. )

관련 정보