Leitura adicional

Leitura adicional

man 7 daemon

Quando um daemon SysV tradicional é iniciado, ele deve executar as etapas a seguir como parte da inicialização. Observe que essas etapas são desnecessárias para daemons de novo estilo (veja abaixo) e só devem ser implementadas se a compatibilidade com SysV for essencial.

[...]

6. No filho, chame setsid() para desconectar de qualquer terminal e criar uma sessão independente.

7. Na criança, chame fork() novamente,para garantir que o daemon nunca mais possa readquirir um terminal.

mas compare isso com processos iniciados sem nenhum vestígio de compatibilidade com SysV:

$ ps -efj
UID        PID  PPID  PGID   SID  C STIME TTY          TIME CMD
root         1     0     1     1  0 May10 ?        00:06:44 /sbin/init
...
root       185     1   185   185  0 May10 ?        00:09:48 /lib/systemd/systemd-journald
root     16434     1 16434 16434  0 May26 ?        00:00:11 /usr/sbin/rsyslogd -n

Os processos para ambos rsyslog.servicee systemd-journal.servicesão líderes de sessão (SID = PID).

Parece que se tais programas fossem configurados para registrar em um TTY, eles ganhariam o TTY como um terminal de controle e receberiam um sinal indesejado/fatal quando o TTY fosse desligado/recebesse Ctrl+C, respectivamente. A menos que eles se lembrem de definir O_NOCTTY ao abrir o arquivo TTY.

Parece que isso é uma pequena armadilha ao escrever ou converter um programa para ser executado como um serviço systemd sem qualquer compatibilidade com SysV, se o seu programa suportar a gravação de mensagens em arquivos personalizados. Isso não parece ser apontado por este documento que defende o estilo systemd. O documento implica o contrário, insistindo que o double-fork é necessário para evitar isso no SysV e depois não menciona isso como um problema ao descrever as etapas que um serviço nativo do systemd usaria.

Isso está correto? O systemd fornece alguma proteção contra isso que esqueci ou o problema foi apontado em outro lugar no documento do systemd?

Responder1

O systemd fornece alguma proteção contra isso […]?

Você está assumindo que deveria. Pelo contrário, considere configurações TTYPathe serviços como [email protected]. A capacidade de obter um terminal de controle é na verdadenecessário, para que o gerenciamento de serviços possa abranger os serviços de login TTY, que precisam fazer exatamente isso.

O que realmente protege contra isso é abandonar a alocação automática de um terminal de controle em open()e descartar a semântica antiga. Ouseriaproteger contra isso. Não é o caso no Linux, mas no FreeBSD, NetBSD, OpenBSD e Hurd hoje em dia a O_NOCTTYsinalização open()é totalmente supérflua. OapenasA maneira de adquirir um terminal de controle é exigi-lo explicitamente, com ioctl(…TIOSCTTY). Na verdade, esse tem sido o caso há quase um quarto de século, desde os dias do 4.4BSD.

Enquanto isso, o hábito de adquirir no Linux é o hábito que também existe há muito tempo, muito antes do systemd:O_NOCTTYem todos os lugares. ☺

(Sim, as bibliotecas GNU e musl C não fornecem isso para você fopen(). Esse é um dos vários motivos pelos quais fdopen()ainda é um mecanismo útil.)

O gerenciamento de serviços com o conjunto de ferramentas nosh service-manageradota uma abordagem um pouco diferente sobre isso. Em vez de sempre transformar processos daemon em líderes de sessão, cada serviço recebendo seu próprio objeto de sessão do kernel que então não vê utilidade, apenas serviços específicos também se encadeiam setsidexplicitamente; como serviços que usam , serviços onde, claro, está configurando o terminal de controle e serviços. (Conforme observado na fonte do serviço, chama a si mesmo.)ttylogin@*open-controlling-ttyagetty@*agettygetty@*mgettysetsid()

Leitura adicional

Responder2

O systemd não protege os programas de serviço contra a aquisição de um terminal de controle. Eles precisam se proteger ao abrir arquivos de log especificados pelo usuário, usando o O_NOCTTYsinalizador.

$ rpm -q systemd
systemd-238-8.git0e0aa59.fc28.x86_64

$ systemctl cat test
# /etc/systemd/system/test.service
[Service]
Type=simple
ExecStart=/bin/sh -c "exec cat </dev/tty10 >/dev/tty10"

$ systemctl status test
● test.service
   Loaded: loaded (/etc/systemd/system/test.service; static; vendor preset: disabled)
   Active: active (running) since Fri 2018-06-01 11:28:41 BST; 1min 35s ago
 Main PID: 12173 (cat)
    Tasks: 1 (limit: 4915)
   Memory: 180.0K
   CGroup: /system.slice/test.service
           └─12173 cat

Jun 01 11:28:41 alan-laptop systemd[1]: Started test.service.

$ ps -ejf
UID        PID  PPID  PGID   SID  C STIME TTY          TIME CMD
...
root     12173     1 12173 12173  0 11:28 tty10    00:00:00 cat

Também confirmei que mudar para tty10 e pressionar Ctrl+C interrompe o catprocesso.

informação relacionada