Linux에서 실행 중인 프로세스의 기능을 변경할 수 있습니까? 파일을 여는 경로를 변경할 수 있습니까(예: 출력 리디렉션)?
그렇다면 어떻게?
답변1
그러한 프로세스의 환경을 외부에서 바꿀 수는 없지만 꼭 그래야 한다면 할 수 있습니다.ptrace(2)
프로세스(실제로는 스레드이지만 단순화를 위해 프로세스라고 계속 말하겠습니다) 및 변경을 수행하는 데 충분한 도구를 사용합니다.작동 중. 물론 프로덕션 용도에 의존하는 것은 이상하겠지만 ptrace
, 그것이 유일한 선택이라면...
gdb
이것을 할 수 있다
프로세스(또는 더 많은 gdb-fu가 있는 일부 스레드)에 연결하여 동작을 변경하고 분리하도록 할 수 있습니다. 충분히 빠르게 완료되면(예: 스크립트로 작성) 프로세스가 더 똑똑해지지 않습니다. 에 따라프로세스 운영 및 조치초기화할 때 항상 ptrace
동일한 사용자일 수는 없으므로 루트 액세스 권한이 필요하거나 최소한CAP_SYS_PTRACE
능력. 프로세스에 수행된 작업이 실제로 수행되었습니다.그 자체를 통해: 프로세스가 이미 해당 기능을 변경하도록 허용된 경우(종종 필수임 CAP_SETPCAP
) 자체적으로 그렇게 할 수 있습니다. 작업이 허용되지 않으면 ptrace
루트를 통해 수행하더라도 도움이 되지 않습니다. 마찬가지로 로그 파일을 닫고 다른 곳에서 다시 여는 것도 쉽습니다.
UL Q&A의 몇 가지 예(그 중 일부는 제가 작성한 것입니다):
탭 인터페이스와 해당 파일 설명자 간의 연결을 찾는 방법은 무엇입니까?: 해결 방법은 커널 3.14 이전에는 커널이 /proc/pid/fdinfo/를 통해 이 정보를 제공하지 않았기 때문입니다.
현재 프로세스의 네트워크 공유를 취소하는 방법: gdb를 실행하여 프로세스의 네트워크 네임스페이스를 (영구적으로) 변경하고 이를 네트워크에서 효과적으로 격리합니다.
프로그램이 삭제된 파일을 쓰지 못하도록 방지: 프로그램이 런어웨이 로그 파일을 변경하도록 합니다. 귀하의 질문에 대한 답변의 두 번째 예입니다.
문제를 해결하려면 첫 번째 예를 들어보세요...
gdb를 사용하여 실행 중인 프로세스의 기능 제한
bash
예제는 루트로 실행되는(따라서 완전히 작동하는) 셸에서 수행됩니다 gdb
(또한 루트로 실행됨). 이것은 복잡하기 때문에쿠카기능프로그램이 링크되지 않는지 모르기 때문에 개발 환경이 필요하지 않고 추가 gdb-fu가 필요하지 않은 더 간단하지만 더 지루한(구조 조작이 필요하므로) 접근 방식을 선택했습니다. 직접 gdb에서 Always Known에 정의된 시스템 호출을 사용합니다.
첫 학기:
# echo test > /tmp/test
# chown nobody /tmp/test
# chmod 600 /tmp/test
# cat < /tmp/test
test
# cat /tmp/test
test
# echo $$
5237
# grep ^Cap /proc/$$/status
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
#
두 번째 학기:
# gdb -q -p 5237
Attaching to process 5237
Reading symbols from /bin/bash...(no debugging symbols found)...done.
[...]
0x00007fb774737681 in pselect () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) set $malloc=(void *(*)(long long)) malloc
(gdb) print $malloc(4*(2+3*2))
$1 = (void *) 0xc4ecc8
(gdb) set *((unsigned int *)($1))=0x20080522
(gdb) set *((unsigned int *)($1)+1)=getpid()
(gdb) print capget($1, (unsigned int *)$1+2)
$2 = 0
(gdb) set *((unsigned int *)($1)+2) &= ~(1<<1|1<<2)
(gdb) print capset($1, (unsigned int *)$1+2)
$3 = 0
(gdb) call free($1)
$4 = 0
(gdb) quit
A debugging session is active.
Inferior 1 [process 5237] will be detached.
Quit anyway? (y or n) y
Detaching from program: /bin/bash, process 5237
#
그래서 이 할당된 메모리는64비트 해결 방법 스타일, 필수*cap_user_header_t
그리고cap_user_data_t[2]
구조, 일부 설정마법의 가치,검색됨현재 프로세스 능력과삭제됨 CAP_DAC_OVERRIDE
그리고CAP_DAC_READ_SEARCH
기능에서 효과적으로 설정하여 해당 기능을 읽을 수 없도록 /tmp/test
하고 결국 할당된 메모리를 해제합니다.
첫 학기로 돌아가서:
# grep ^Cap /proc/$$/status
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003ffffffff9
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
# cat < /tmp/test
bash: /tmp/test: Permission denied
# cat /tmp/test
test
#
차이점은 무엇입니까? 리디렉션을 사용할 때 bash 프로세스는 더 이상 제한된 액세스로 루트가 아닌 파일에 액세스할 수 없으며 실패합니다(fork 후, 실행 전 cat
). 새로운 프로세스를 (포킹하고) 실행할 때,루트는 모든 기능을 복원합니다.다른 집합에서 제거되지 않는 한: 다른 방법으로 변경할 수 있는 기능 경계 집합(prctl(PR_CAPBSET_DROP, ...)
). 이것이 cat
리디렉션 없이 실행해도 여전히 잘 작동하는 이유입니다(예:뿌리).
답변2
열린 파일의 경로를 변경하려면 하드 링크를 사용할 수 있지만 원본 파일과 동일한 파일 시스템에 남아 있어야 합니다. 애플리케이션이 파일을 열면 파일 핸들과 파일의 inode만 중요합니다. 하드 링크는 단순히 동일한 inode에 대해 다른 파일 이름/경로를 제공합니다.
이름을 바꾸거나 재구성하려는 경우에 이 방법이 효과적일 수 있습니다. 재부팅 시 새 위치가 선택되도록 모든 구성 파일을 업데이트해야 합니다. 공간 등을 확보하기 위해 새 파일 시스템으로 이동하려는 경우에는 이 방법이 작동하지 않습니다.
때로는 특정 단일(보통 SIGHUP)이 전송되고 애플리케이션이 모든 파일 핸들을 닫은 다음 다시 엽니다. 이 경우 일반적으로 conf를 다시 로드하므로 새 파일 경로를 선택할 수도 있습니다. 그러나 이 동작은 응용 프로그램에 따라 크게 달라집니다. 데이터 유형에 따라 이는 매우 위험할 수도 있으며 데이터 손실이나 손상으로 이어질 수도 있습니다.
나는 낙관적이지는 않지만 프로세스를 변경할 능력이 없다고 생각합니다. 종료하고 다시 시작해야 합니다.