/ proc / 파일을 파싱하는 것이 안전합니까?


152

구문 분석 /proc/net/tcp/하고 싶지만 안전합니까?

/proc/다른 프로세스 (또는 OS 자체)가 동시에 파일을 변경한다는 것을 두려워하지 말고 파일을 열고 읽으려면 어떻게해야 합니까?


29
+1. 즉 A의 지독한 좋은 질문입니다. 나는 단지 대답을 원했지만, 나는 전에 그런 종류의 일을 한 이후로 알아 내기를 기대합니다.
paxdiablo

1
나는 그것을 읽으면 연결 목록과 각 연결을 소유 한 UID를 때와 같이 제공 합니다. 그러나 문서화 된 것을 찾을 수 없으므로이 의견을 작성하십시오.
Tim Post

3
파일이 아니기 때문에 간단한 대답은 분명히 그렇습니다. 읽는 것이 항상 안전해야합니다. 답은 나중에 읽을 때 일관성이 없을 수 있지만 안전합니다.
Rory Alsop

sysctl을 대신 사용해야하는 이유입니다. (또한 더 적은 syscalls)
Good Person

@GoodPerson- 예를 들어 파일 sysctl구문 분석에 어떻게 도움 이 /proc/net/tcp/됩니까?
Kiril Kirov

답변:


111

일반적으로 아닙니다. (따라서 대부분의 답변이 잘못되었습니다.) 원하는 속성에 따라 안전 할 수 있습니다. 그러나의 파일 일관성에 대해 너무 많이 가정하면 코드의 버그로 끝나기 쉽습니다 /proc. 예를 들어, 일관된 스냅 샷 이라고 가정 한이 버그를/proc/mounts 참조하십시오 .

예를 들면 다음과 같습니다.

  • /proc/uptime이다 완전히 원자 누군가가 다른 답변에서 언급 한 바와 같이, - 그러나 단지 리눅스 2.6.30 이후 채 2 세입니다. 따라서이 작고 사소한 파일조차도 그때까지 경쟁 조건에 처해 있었고 여전히 대부분의 엔터프라이즈 커널에 있습니다. fs/proc/uptime.c현재 소스 또는 원자로 만든 커밋을 참조하십시오 . 2.6.30 이전의 커널에서는 약간의 open파일을 만들 수 read있습니다. 나중에 다시 돌아 오면 read얻는 부분이 첫 번째 부분과 일치하지 않습니다. (방금 이것을 시연했습니다-재미를 위해 직접 시도하십시오.)

  • /proc/mounts단일 원자 내의 read시스템 콜. 따라서 read전체 파일을 한 번에 모두 확보하면 시스템에서 마운트 지점의 일관된 단일 스냅 샷이 생성됩니다. 그러나 여러 read시스템 호출 을 사용하는 경우 (파일이 크면 정상적인 I / O 라이브러리를 사용하고이 문제에 특별한주의를 기울이지 않으면 정확하게 발생합니다.) 질환. 일관된 스냅 샷을 얻을 수있을뿐만 아니라 시작하기 전에 존재했거나 존재를 멈추지 않은 마운트 지점이 보이지 않을 수 있습니다. 그것은 하나의 원자의 것을보고 read()보기에서 m_start()fs/namespace.c 그것은 세마포어를 잡아 볼 것을 경비원이 될 때까지 계속 마운트 포인트의 목록, m_stop()호출, 때read()수행. 무엇이 잘못 될 수 있는지 확인하려면 작년의이 버그 (위에 링크 한 것과 동일한 버그)를 참고하십시오 /proc/mounts.

  • /proc/net/tcp실제로 묻는 것보다 그 일관성이 떨어집니다. 그건 단지 테이블의 각 행 내에서 원자 . 에서이, 모양을 보려면 listening_get_next()에서net/ipv4/tcp_ipv4.cestablished_get_next()똑같이 파일에 아래와 자물쇠를 볼 그들은 차례로 각 항목에 꺼내. 행마다 일관성이 부족하다는 것을 보여주기 위해 편리한 재현 코드가 없지만 일관성을 유지하는 잠금 장치 (또는 다른 것)는 없습니다. 네트워크는 종종 시스템의 매우 바쁜 부분이므로이 진단 도구에서 일관된 견해를 제시하는 것은 가치가 없습니다.

계속 다른 부분 /proc/net/tcp의 각 행 내에서 원자는에서 버퍼링 seq_read()당신이 읽을 수 있는fs/seq_file.c . 이렇게하면 read()한 행의 일부 가되면 전체 행의 텍스트가 버퍼에 유지되므로 다음 read()행이 새 행을 시작하기 전에 나머지 행을 가져옵니다. /proc/mounts여러 read()호출 을 수행하더라도 동일한 메커니즘이 각 행을 원자로 유지 하는 데 사용 /proc/uptime되며 최신 커널에서는 원자를 유지하는 데 사용 되는 메커니즘이기도합니다 . 커널은 메모리 사용에 대해 신중하기 때문에이 메커니즘은 전체 파일을 버퍼링 하지 않습니다 .

에있는 대부분의 파일은 /proc적어도 일관되게 유지되며 /proc/net/tcp, 각 행은 제공하는 정보에 관계없이 하나의 항목을 일관된 그림으로 표시합니다. 대부분의 파일 은 동일한 seq_file추상화를 사용하기 때문 입니다. 그러나이 /proc/uptime예에서 알 수 있듯이 일부 파일은 seq_file2009 년 에 사용하기 위해 여전히 마이그레이션되고 있습니다 . 나는 여전히 오래된 메커니즘을 사용하고 그 정도의 원 자성을 갖지 않는 것도 있습니다. 이 경고는 거의 문서화되어 있지 않습니다. 주어진 파일에 대한 유일한 보증은 소스를 읽는 것입니다.

의 경우 /proc/net/tcp,이를 읽고 두려움없이 각 행을 구문 분석 할 수 있습니다. 그러나 한 번에 여러 줄에서 결론을 얻으려고하면 다른 프로세스와 커널 읽는 동안 변경하고 버그를 생성 할 수 있습니다.


1
readdir 원자 성은 어떻습니까? / proc / self / fd를 읽는 것처럼? 안전 해요?
소켓 페어

그것은 질문에 대답하는 것이 아니라 사용할 수있는 가동 시간을 확인하는 방법에 대해 추가하는 것 clock_gettime(2)입니다 CLOCK_MONOTONIC(아마도 내가 알지 못하는 기술이 있지만 개인적으로 부팅 시간 이후에만 보았습니다). Linux의 경우 옵션도 있습니다 sysinfo(2).
Pryftan

44

의 파일이 있지만 /proc사용자 공간에서 일반 파일로 표시, 그들이 진짜로 사용자 공간에서 표준 파일 작업을 지원 파일이 아니라 실체없는 ( open, read, close). 이것은 커널에 의해 변경되는 디스크에 일반 파일이있는 것과는 상당히 다릅니다.

모든 커널은 sprintf-like 함수를 사용하여 내부 상태를 자체 메모리로 인쇄하고 read(2)시스템 호출 을 실행할 때마다 해당 메모리가 사용자 공간에 복사됩니다 .

커널은 이러한 호출을 일반 파일과는 완전히 다른 방식으로 처리하므로 읽을 때 데이터의 전체 스냅 샷을 준비 할 수 있고 open(2)동시에 커널은 동시 호출이 일관되고 원자적임을 보장 할 수 있습니다. 나는 그것을 아무데도 읽지 못했지만, 그렇지 않으면 실제로 의미가 없습니다.

내 조언은 특정 Unix 풍미에서 proc 파일의 구현을 살펴 보는 것입니다. 이것은 실제로 표준에 의해 통제되지 않는 구현 문제입니다 (출력 형식 및 내용 그대로).

가장 간단한 예는 uptimeLinux 에서 proc 파일을 구현하는 것입니다 . 에 제공된 콜백 함수에서 전체 버퍼가 어떻게 생성되는지 확인하십시오 single_open.


3
@Ignacio : 나는 proc파일이 커널에 의해 쓰기 위해 열린 일반 파일 이라고 생각하는 인상을 남겼 기 때문에 OP를이 방향으로 가리키고 있습니다.
Blagovest Buyukliev

4
특정 파일의 구현에 대한 조언은 좋습니다. 불행히도 open()파일이 모두 스냅 샷되었다는 추측 은 많은 파일, 특히 /proc/net/tcpOP와 관련하여 잘못되었습니다 . 이러한 의미를 제공하는 비용에 대해 생각한다면 이는 의미가 있습니다. 모든 TCP 연결을 기록하는 내부 데이터 구조를 잠그는 것과 같은 작업을 수행해야합니다. 데이터를 스캔하고 버퍼로 포맷하기에 충분합니다. 실제로 일어나는 일에 대한 자세한 내용은 내 대답을 참조하십시오.
그렉 가격

16

/ proc은 가상 파일 시스템입니다. 실제로 커널 내부를 편리하게 볼 수 있습니다. 읽는 것이 안전하지만 (여기있는 이유) 가상 파일의 내부가 최신 버전의 커널로 발전 할 수 있기 때문에 장기적으로 위험합니다.

편집하다

Linux 커널 문서 , 1.4 장 네트워킹의 proc 문서에서 더 많은 정보를 얻을 수 있습니다. 시간이지나면서 정보가 어떻게 진화하는지 정보를 찾을 수 없습니다. 나는 그것이 얼어 붙었다 고 생각했지만 명확한 대답을 할 수는 없습니다.

편집 2

Sco doc 에 따르면 (리눅스는 아니지만 * nix의 모든 맛이 그렇게 작동한다고 확신합니다)

프로세스 상태 및 결과적으로 / proc 파일의 내용이 인스턴트에서 인스턴트로 변경 될 수 있지만 / proc 파일의 단일 read (2)는 상태의``정상적인 ''표현을 반환합니다. 즉, 읽기는 프로세스 상태의 원 자성 스냅 샷 실행중인 프로세스의 / proc 파일에 적용된 연속 읽기에는 이러한 보장이 적용되지 않습니다. 또한 as (주소 공간) 파일에 적용된 I / O에 대해서는 원 자성이 보장되지 않습니다. 프로세스 주소 공간의 내용은 해당 프로세스의 LWP 또는 시스템의 다른 프로세스에 의해 동시에 수정 될 수 있습니다.


3
"생각한다"? 확실한 답변을
얻는

커널에서 / proc의 구현을 감안할 때 이것은 리눅스에서도 마찬가지입니다. 단일 읽기 호출에서 procfs 파일을 읽는 경우, 읽은 proc 파일이 올바르게 커널 측으로 구현되었다고 가정하면 일관성이 있습니다.
Erik

8
나는 당신이 SCO보다 더 나쁜 정보원을 생각 해낼 수 있다고 생각하지 않으며 proc다른 커널간에 비슷한 행동 을하는 것처럼 (또는 존재한다고 가정 할 때) 유닉스 시스템에서는 필요하지 않다고 생각합니다. )가 당신에게 상처를 줄 것입니다.
니콜라스 기사

1
@Nicholas : 글쎄, 커널 문서에서 확실한 대답을 찾을 수 없었습니다. 알고 있다면 자유롭게 지적하십시오.
Bruce

2
SCO 문서가 그렇게 말합니다. 불행히도 Linux에서는 항상 사실이 아니며, 특히 /proc/net/tcpOP의 주요 관심사 인 사실이 아닙니다 . 오히려 출력의 각 개별 행만 원자 적입니다. 자세한 내용은 내 답변을 참조하십시오.
그렉 가격

14

Linux 커널의 procfs API는 읽기가 일관된 데이터를 리턴하도록 인터페이스를 제공합니다. 의 의견을 읽으십시오 __proc_file_read. 큰 주석 블록의 항목 1)이이 인터페이스를 설명합니다.

즉, 반환 된 데이터의 일관성을 유지하기 위해이 인터페이스를 올바르게 사용하는 것은 특정 proc 파일의 구현에 달려 있습니다. 따라서 귀하의 질문에 대답하기 위해 : 아니오, 커널은 읽는 동안 proc 파일의 일관성을 보장하지 않지만 일관성을 제공하기 위해 해당 파일의 구현 수단을 제공합니다.


4
불행히도, 많은 파일 /proc은 실제로 일관성을 제공하지 않습니다. 자세한 내용은 내 답변을 참조하십시오.
그렉 가격

3
또한 __proc_file_read()에 찬성하여 더 이상 사용되지 않습니다 seq_file. 긴 블록 주석 바로 위의 다소 분노한 주석 (Linus의 주석)을 참조하십시오.
그렉 가격

6

임베디드 ARM 대상에서 현재 드라이버 개발을 수행하고 있기 때문에 Linux 2.6.27.8에 대한 소스가 있습니다.

linux-2.6.27.8-lpc32xx/net/ipv4/raw.c934 행 의 파일은 다음과 같습니다.

    seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
            " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
            i, src, srcp, dest, destp, sp->sk_state,
            atomic_read(&sp->sk_wmem_alloc),
            atomic_read(&sp->sk_rmem_alloc),
            0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
            atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));

어떤 출력

[wally@zenetfedora ~]$ cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15160 1 f552de00 299
   1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 13237 1 f552ca00 299
...

함수 raw_sock_seq_show()의 계층 구조의 일부인 procfs의 처리 함수. procfs 읽기가 정보를 업데이트하는 것보다 훨씬 덜 일반적 이기 때문에 텍스트는 파일을 read()요청할 때까지 텍스트가 생성되지 않습니다 ./proc/net/tcp

내와 같은 일부 드라이버는 single로 proc_read 함수를 구현합니다 sprintf(). 핵심 드라이버 구현의 추가 문제는 단일 읽기 동안 중간 커널 공간 버퍼에 맞지 않을 수있는 매우 긴 출력을 처리하는 것입니다.

64K 읽기 버퍼를 사용하는 프로그램으로 테스트했지만 proc_read가 데이터를 반환하기 위해 시스템에서 3072 바이트의 커널 공간 버퍼가 발생합니다. 많은 양의 텍스트를 반환하려면 고급 포인터로 여러 번의 호출이 필요합니다. 둘 이상의 I / O가 필요할 때 반환 된 데이터를 일관되게 만드는 올바른 방법을 모르겠습니다. 확실히 각 항목 /proc/net/tcp은 일관성이 있습니다. 나란히 라인이 다른 시간에 스냅 샷 될 가능성이 있습니다.


정말 죄송합니다. 많이 얻지 못했습니다. 따라서을 사용하면 ifstream안전하지 않지만 사용 read하면 안전하다는 것을 의미합니까? 또는 ifstream내부적으로 사용 read합니까? 그리고 당신은 무엇을 제안합니까?
Kiril Kirov

@Kiril : 혼란을 드려 죄송합니다. 이것은 데이터의 /proc/net/tcp형식이 어떻게 지정 되는지에 대한 설명이며 다른 사람이 데이터를 읽는 방법과는 완전히 독립적입니다.
wallyk

1
네! 그리고 다른 라인 (in /proc/net/tcp)이 동일한 스냅 샷에서 나온 것이 아니라고 추측합니다 . 몇 가지 설명은 내 답변을 참조하십시오.
그렉 가격

3

알려지지 않은 버그가 없으면 /proc손상된 데이터를 읽거나 오래된 데이터와 새 데이터를 혼합하여 사용할 수 있는 경쟁 조건이 없습니다 . 이런 의미에서 안전합니다. 그러나 여전히 읽은 많은 데이터 /proc가 생성 되 자마자 시간이 지남에 따라 경쟁 조건이 남아 있으며 , 더 나아가서 읽고 / 처리 할 때까지 더 오래 걸릴 수 있습니다. 예를 들어 프로세스는 언제든지 죽을 수 있으며 새로운 프로세스에 동일한 pid를 할당 할 수 있습니다. 경쟁 조건없이 사용할 수있는 유일한 프로세스 ID는 자신의 자식 프로세스입니다. 네트워크 정보 (오픈 포트 등)와 대부분의 정보도 마찬가지입니다 /proc. 나는 데이터에 의존하는 것이 나쁘고 위험한 관행이라고 생각합니다./proc자신의 프로세스 및 잠재적으로 자식 프로세스에 대한 데이터를 제외하고는 정확합니다. 물론 /proc정보 / 로깅 등을 위해 사용자 / 관리자에게 다른 정보를 제공하는 것이 여전히 유용 할 수 있습니다 . 목적.


내 자신의 프로세스 (PID의 경우)를 사용하여 일부 정보 를 얻고 사용 하기 위해이 작업을 수행하고 있습니다 . 안전해야합니다. getpid()
Kiril Kirov

1
예, 나는 그것을 완전히 안전하다고 생각합니다.
R .. GitHub 중지 지원 얼음

하위 프로세스가 다른 프로세스보다 더 잘 작동한다는 데 동의하지 않습니다. 마찬가지로 지금까지 같은 /proc인터페이스에 관한 한, 그들은 모두 같은 약점과 강점을 가지고있다. 어쨌든 OP는 프로세스가 아닌 장치 드라이버 관련 정보를 묻습니다.
wallyk

1
pid N가 자식 프로세스 인 경우, pid 가 -family 함수 N를 호출 할 때까지 pid가 여전히 동일한 프로세스를 참조 하도록 할 수 있습니다 wait. 이렇게하면 인종이 없습니다.
R .. GitHub 중지 지원 얼음

-1이 범람하고 설명이없는 것은 무엇입니까?
R .. GitHub 중지 지원 얼음

2

/ proc 파일에서 읽을 때 커널은 해당 proc 파일에 대한 "읽기"기능으로 미리 등록 된 함수를 호출합니다. __proc_file_readfs / proc / generic.c 의 기능을 참조하십시오 .

따라서 proc read의 안전성은 커널이 읽기 요청을 충족시키기 위해 호출하는 기능만큼 안전합니다. 해당 함수가 터치하는 모든 데이터를 올바르게 잠그고 버퍼에서 반환하면 해당 함수를 사용하여 읽는 것이 안전합니다. / proc / net / tcp에 대한 읽기 요청을 만족시키는 데 사용되는 것과 같은 proc 파일은 한동안 사용되어 왔으며 철저한 검토를 거쳤으므로 사용자가 요청할 수있는만큼 안전합니다. 실제로, 많은 일반적인 Linux 유틸리티는 proc 파일 시스템에서 읽고 다른 방식으로 출력 형식을 지정합니다. (머리 꼭대기에서 'ps'와 'netstat'가이를 수행한다고 생각합니다).

언제나 그렇듯이, 당신은 그것에 대해 나의 말을 할 필요가 없습니다. 당신은 당신의 두려움을 진정 소스를 볼 수 있습니다. proc_net_tcp.txt의 다음 문서는 / proc / net / tcp에 대한 "읽기"기능이 작동하는 위치를 알려주므로 해당 proc 파일에서 읽을 때 실행되는 실제 코드를보고 자신이 없는지 직접 확인할 수 있습니다 잠금 위험.

이 문서는 / proc / net / tcp 및 / proc / net / tcp6 인터페이스에 대해 설명합니다.
이 인터페이스는 tcp_diag를 위해 더 이상 사용되지 않습니다. 이 / proc 인터페이스는 현재 활성화 된 TCP 연결에 대한 정보를 제공하며 각각 net / ipv4 / tcp_ipv4.c의 tcp4_seq_show () 및 net / ipv6 / tcp_ipv6.c의 tcp6_seq_show ()에 의해 구현됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.