Como posso criar um processo difícil de matar?

9

Eu quero criar um programa que será difícil de ser interrompido (mesmo para o administrador) assim que for iniciado (com privilégios de root). Uma vez iniciado o processo deve continuar a iniciar-se na inicialização até que seja solicitado a parar. O processo de parada deve levar algum tempo (ou seja, deve ser caro).

Eu sei que isso pode soar como um software mal-intencionado, mas eu quero por um motivo genuíno. Eu quero executar bloqueadores de sites no meu laptop (em que eu sou o administrador). E eu quero dificultar para mim mesmo pará-los.

A solução que pensei é a seguinte -

  1. O processo deve ser executado com um nome diferente sempre que for executado para que eu não possa prever o nome do processo e eliminá-lo.

  2. O processo será salvo em /etc/rc5.d no encerramento

  3. O processo irá criptografar seu nome usando um cypher em alguns conhecidos localização. O processo de parada terá que usar o bruteforce para recuperar o nome do programa e eliminá-lo.

Eu gostaria de encontrar uma boa solução para essa tarefa.

    
por Miheer 12.12.2013 / 14:36

2 respostas

8

Uma abordagem poderia ser usar namespaces de PID:

Inicialize seu sistema com um parâmetro init=/some/cmd as kernel, onde /some/cmd bifurca um processo em um novo namespace ( CLONE_NEWPID ) e executa /sbin/init nele (ele terá PID 1 nesse novo namespace e pid 2 no namespace raiz), então no pai, execute seu "programa".

Você provavelmente desejará uma forma de controlar seu programa de uma forma ou de outra (soquete TCP ou ABSTRACT Unix, por exemplo).

Você provavelmente desejará mlocar seu programa na memória e fechar a maioria das referências ao sistema de arquivos para que ele não dependa de nada.

Esse processo não será visto no resto do sistema. O resto do sistema será executado como em um container.

Se esse processo morrer, o kernel entrará em pânico, o que lhe dará uma garantia extra.

Um efeito colateral inconveniente é que não veremos os encadeamentos do kernel na saída de ps .

Como uma prova de conceito (usando este truque para inicializar uma cópia do seu sistema em uma máquina virtual qemu ):

Crie um /tmp/init como:

#! /bin/sh -
echo Starting
/usr/local/bin/unshare -fmp -- sh -c '
  umount /proc
  mount -nt proc p /proc
  exec bash <&2' &
ifconfig lo 127.1/8
exec socat tcp-listen:1234,fork,reuseaddr system:"ps -efH; echo still running"

(você precisa de unshare de uma versão recente do util-linux (2.14)). Acima estamos usando socat como o "programa" que apenas responde em conexões TCP na porta 1234 com a saída de ps -efH .

Em seguida, inicialize sua VM como:

kvm -kernel /boot/vmlinuz-$(uname -r) -initrd /boot/initrd.img-$(uname -r) \
    -m 1024 -fsdev local,id=r,path=/,security_model=none \
    -device virtio-9p-pci,fsdev=r,mount_tag=r -nographic -append \
    'root=r rootfstype=9p rootflags=trans=virtio console=ttyS0 init=/tmp/init rw'

Então, vemos:

Begin: Running /scripts/init-bottom ... done.
Starting
[...]
root@(none):/# ps -efH
UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 14:24 ?        00:00:00 bash
root         4     1  0 14:24 ?        00:00:00   ps -efH
root@(none):/# telnet localhost 1234
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
UID        PID  PPID  C STIME TTY          TIME CMD
root         2     0  0 14:24 ?        00:00:00 [kthreadd]
root         3     2  0 14:24 ?        00:00:00   [ksoftirqd/0]
[...]
root         1     0  2 14:24 ?        00:00:00 socat tcp-listen:1234,fork,reuseaddr system:ps -efH; echo still running
root       204     1  0 14:24 ?        00:00:00   /usr/local/bin/unshare -fmp -- sh -c    umount /proc   mount -nt proc p /proc   exec bash <&2
root       206   204  0 14:24 ?        00:00:00     bash
root       212   206  0 14:25 ?        00:00:00       telnet localhost 1234
root       213     1  0 14:25 ?        00:00:00   socat tcp-listen:1234,fork,reuseaddr system:ps -efH; echo still running
root       214   213  0 14:25 ?        00:00:00     socat tcp-listen:1234,fork,reuseaddr system:ps -efH; echo still running
root       215   214  0 14:25 ?        00:00:00       sh -c ps -efH; echo still running
root       216   215  0 14:25 ?        00:00:00         ps -efH
still running
Connection closed by foreign host.
root@(none):/# QEMU: Terminated
    
por 12.12.2013 / 15:27
1

Não tenho certeza se é a solução final ou se é a melhor maneira de fazer isso. Minhas opiniões:

  • Modifique init , pois é o primeiro processo se todos os outros morrerem também. Então, sua máquina só poderá ser usada com ela.

  • Crie um módulo do kernel e carregue módulos críticos dependendo dele (se ele for morto, causará uma reação em cadeia como o exemplo init ).

  • Modifique o kernel para ignorar as solicitações de eliminação de um determinado processo.

Tenha em mente que os dois últimos serão executados no modo kernel (que é muito limitado em termos de libs e, portanto, um). A modificação de init será executada no espaço do usuário, permitindo que você use muitos recursos dela.

    
por 12.12.2013 / 14:55