O Chromium falha ao iniciar porque a negação de soquetes do servidor também nega AF_NETLINK sockets e, por algum motivo, o Chromium precisa se comunicar com udev , o que exigiu AF_NETLINK sockets. Eu não tenho uma fonte obviamente autoritária, mas vou tentar explicar os primeiros princípios usando o código fonte subjacente e espero não cometer muitos erros no processo.
Comecei a investigar a primeira mensagem de erro. O código que produz a mensagem de erro no Chromium é o link linha 138:
// Request notifications.
struct sockaddr_nl addr = {};
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
// TODO(szym): Track RTMGRP_LINK as well for ifi_type, http://crbug.com/113993
addr.nl_groups = RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR | RTMGRP_NOTIFY |
RTMGRP_LINK;
int rv = bind(netlink_fd_,
reinterpret_cast<struct sockaddr*>(&addr),
sizeof(addr));
if (rv < 0) {
PLOG(ERROR) << "Could not bind NETLINK socket";
AbortAndForceOnline();
return;
}
A falha real relacionada ao grsec ocorre na chamada bind() , que tenta configurar um soquete de link de rede que receberá notificações sempre que uma interface de endereço IPv4 ou IPv6 for alterada e sempre que um estado de link for alterado.
Esta chamada é tratada por um syscall no kernel, em net/socket.c :
SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen)
{
struct socket *sock;
struct sockaddr_storage address;
int err, fput_needed;
Isto declara o syscall e algumas variáveis locais. Você pode ver que a declaração syscall corresponde à chamada bind() no código do Chromium: int fd, struct sockaddr __user * umyaddr, int addrlen .
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (sock) {
Isso procura o soquete a partir do descritor de arquivos. Se um socket for encontrado ...
err = move_addr_to_kernel(umyaddr, addrlen, &address);
if (err >= 0) {
Isso copia os dados fornecidos do espaço do usuário para o espaço do kernel. Se não houver erro ...
err = security_socket_bind(sock,
(struct sockaddr *)&address,
addrlen);
if (!err)
Isto dá a qualquer LSM carregado (SELinux, etc.) a chance de verificar se a chamada é permitida. Se assim for ...
err = sock->ops->bind(sock,
(struct sockaddr *)
&address, addrlen);
O bind continua em outro lugar, e estamos no que diz respeito à análise do código padrão do kernel aqui.
grsec corrige net/socket.c em vários lugares; em particular, antes da verificação de segurança do LSM, ele adiciona suas próprias verificações (consulte link ; procure por SYSCALL_DEFINE3(bind ):
if (gr_handle_sock_server((struct sockaddr *)&address)) {
err = -EACCES;
goto error;
}
err = gr_search_bind(sock, (struct sockaddr_in *)&address);
if (err)
goto error;
O primeiro cheque é o que é relevante aqui; chama gr_handle_sock_server() :
gr_handle_sock_server(const struct sockaddr *sck)
{
#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER
if (grsec_enable_socket_server &&
in_group_p(grsec_socket_server_gid) &&
sck && (sck->sa_family != AF_UNIX) &&
(sck->sa_family != AF_LOCAL)) {
gr_log_noargs(GR_DONT_AUDIT, GR_BIND_MSG);
return -EACCES;
}
#endif
return 0;
}
Isso implementa a verificação "negar soquetes do servidor para agrupar". Conforme verificado nos comentários, no seu sistema grsec_enable_socket_server é 1, portanto, ao executar como grupo 1001, o if é bem-sucedido ( sck->sa_family == AF_NETLINK neste caso) e o acesso é negado.
Voltando ao código do Chromium, isso registra uma mensagem de erro e chama AbortAndForceOnline() , que apenas configura as coisas para que o navegador calcule que está on-line. Então isso não explica a falha em começar.
Antes de continuar, tentei reproduzir a falha. Para fazer isso, adaptei authbind para evitar que AF_NETLINK seja vinculado; em libauthbind.c , na função bind() adicionei um case ao primeiro switch :
case AF_NETLINK:
puts("Denying AF_NETLINK");
return -EACCES;
A execução com a biblioteca resultante reproduziu a falha:
% LD_PRELOAD=/usr/lib/authbind/libauthbind.so.1 chromium
Denying AF_NETLINK
[15858:15876:0214/160730:ERROR:address_tracker_linux.cc(154)] Could not bind NETLINK socket: Success
Denying AF_NETLINK
libudev: udev_monitor_enable_receiving: bind failed: No such file or directory
[15858:15890:0214/160730:FATAL:udev_linux.cc(29)] Check failed: 0 == ret (0 vs. -2)
zsh: abort LD_PRELOAD=/usr/lib/authbind/libauthbind.so.1 chromium
(As mensagens de erro estranhas, "Success" e "No such file directory", ocorrem porque não estou definindo errno .)
Portanto, a anulação está de fato relacionada a bind() . Verificar udev_linux.cc linha 29 mostra
int ret = udev_monitor_enable_receiving(monitor_.get());
CHECK_EQ(0, ret);
ret aqui é negativo porque udev_monitor_enable_receiving() não pode ligar um soquete de netlink, e CHECK_EQ causa uma falha de asserção aqui (veja link para a implementação). Isso produz um sinal de interrupção e o Chromium é encerrado com uma mensagem "Abortada" de algum tipo, dependendo do shell usado.