Qual é a maneira mais segura de gravar programaticamente em um arquivo com privilégios de root?

35

Um aplicativo enorme precisa, em um momento específico, executar um pequeno número de gravações em um arquivo que requer permissões de root. Não é realmente um arquivo, mas uma interface de hardware que é exposta ao Linux como um arquivo.

Para evitar dar privilégios de root ao aplicativo inteiro, eu escrevi um script bash que executa as tarefas críticas. Por exemplo, o script a seguir ativará a porta 17 da interface de hardware como saída:

echo "17" > /sys/class/gpio/export
echo "out" > /sys/class/gpio/gpio17/direction

No entanto, como suid está desativado para scripts bash no meu sistema, eu me pergunto qual é a melhor maneira de conseguir isso.

  1. Use alguma solução alternativa apresentada aqui

  2. Chame o script com sudo do aplicativo principal e edite a lista de sudoers adequadamente, para evitar a necessidade de uma senha ao chamar o script. Estou um pouco desconfortável em dar privilégios de sudo para echo .

  3. Basta escrever um programa em C, com fprintf , e configurá-lo para suid root. Codifique as strings e os nomes dos arquivos e certifique-se de que apenas o root possa editá-lo. Ou leia as seqüências de caracteres de um arquivo de texto, certificando-se de que ninguém pode editar o arquivo.

  4. Alguma outra solução que não me ocorreu e é mais segura ou mais simples do que as apresentadas acima?

por vsz 15.04.2016 / 06:28

6 respostas

33

Você não precisa conceder sudo access a echo . De facto, isso é inútil porque, e. com sudo echo foo > bar , o redirecionamento é feito como o usuário original, não como root.

Chame o script pequeno com sudo , permitindo que NOPASSWD: acesse SOMENTE esse script (e quaisquer outros scripts semelhantes) pelo (s) usuário (s) que precisam acessá-lo.

Esta é sempre a maneira melhor / mais segura de usar sudo . Isole o pequeno número de comandos que precisam de privilégios de root em seus próprios scripts separados e permita que o usuário não confiável ou parcialmente confiável execute apenas esse script como root.

Os pequenos scripts sudo -able não devem receber args (ou entrada) do usuário (ou seja, qualquer outro programa chamado deve ter opções codificadas e args) ou deve ter muito cuidado em validar quaisquer argumentos / entrada que tem que aceitar do usuário.

Seja paranóico na validação - em vez de procurar coisas 'conhecidas ruins' a serem excluídas, permitir apenas coisas 'boas' e abortar em qualquer divergência ou erro ou qualquer coisa suspeita até mesmo remotamente.

A validação deve ocorrer o mais cedo possível no script (preferencialmente antes que ele faça qualquer coisa mais como root).

Eu realmente deveria ter mencionado isso quando escrevi esta resposta pela primeira vez, mas se o seu script for um script de shell, DEVE citar corretamente all variáveis. Tenha um cuidado especial ao citar as variáveis que contêm entrada fornecida pelo usuário em qualquer modo, mas não presuma que algumas variáveis sejam seguras, COTA AS TODAS .

Isso inclui variáveis de ambiente potencialmente controladas pelo usuário (por exemplo, "$PATH" , "$HOME" , "$USER" etc. E definitivamente incluindo "$QUERY_STRING" e "HTTP_USER_AGENT" etc em um script CGI). Na verdade, apenas cite todos eles. Se você tiver que construir uma linha de comando com múltiplos argumentos, use uma matriz para construir a lista de argumentos e cite isso - "${myarray[@]}" .

Eu já disse "cite todos" com bastante frequência? lembre se. faça isso.

    
por 15.04.2016 / 06:51
16

Verifique o proprietário nos arquivos do gpio:

ls -l /sys/class/gpio/

Provavelmente, você descobrirá que eles pertencem ao grupo gpio :

-rwxrwx--- 1 root     gpio     4096 Mar  8 10:50 export
...

Nesse caso, você pode simplesmente adicionar seu usuário ao grupo gpio para conceder acesso sem sudo:

sudo usermod -aG gpio myusername

Você precisará fazer logout e fazer login novamente para que a alteração entre em vigor.

    
por 15.04.2016 / 08:34
7

Uma solução para isso (usada particularmente na área de trabalho do Linux, mas também aplicável em outros casos) é usar D-Bus para ativar um pequeno serviço rodando como root e polkit para fazer a autorização. Isso é fundamentalmente o que o polkit foi projetado para; da sua documentação introdutória :

polkit provides an authorization API intended to be used by privileged programs (“MECHANISMS”) offering service to unprivileged programs (“CLIENTS”). See the polkit manual page for the system architecture and big picture.

Em vez de executar seu programa de ajuda, o programa grande e sem privilégios enviaria um pedido no ônibus. Seu ajudante pode estar rodando como um daemon iniciado na inicialização do sistema ou, melhor, ativado ativado conforme necessário pelo systemd . Então, esse ajudante usaria o polkit para verificar se a solicitação vinha de um local autorizado. (Ou, neste caso, se isso parecer um exagero, você poderia usar algum outro mecanismo de autenticação / autorização embutido em código).

Eu encontrei um artigo básico sobre comunicação via D-Bus , e Embora eu não tenha testado, este parece ser um exemplo básico de adicionar o polkit ao mix .

Nesta abordagem, nada precisa ser marcado como setuid.

    
por 16.04.2016 / 16:14
5

Uma maneira de fazer isso é criar um programa de raiz setuid escrito em C, que faz apenas o que é necessário e nada mais. No seu caso, ele não precisa olhar para nenhuma entrada do usuário.

#include <unistd.h>
#include <string.h>
#include <stdio.h>  // for perror(3)
// #include ...  more stuff for open(2)

static void write_str_to_file(const char*fn, const char*str) {
    int fd = open(fn, O_WRONLY)
    if (-1 == fd) {
        perror("opening device file");  // make this a CPP macro instead of function so you can use string concat to get the filename into the error msg
        exit(1);
    }
    int err = write(fd, str, strlen(str));
    // ... error check
    err = close(fd);
    // ... error check
}

int main(int argc, char**argv) {
    write_string_to_file("/sys/class/gpio/export", "17");
    write_string_to_file("/sys/class/gpio/gpio17/direction", "out");
    return 0;
}

Não há como subverter isso através de variáveis de ambiente ou qualquer coisa, porque tudo o que faz é fazer algumas chamadas de sistema.

Desvantagem: você deve verificar o valor de retorno de todas as chamadas do sistema.

De cabeça para baixo: a verificação de erros é realmente fácil: se houver algum erro, apenas perror e socorrer: saia com status diferente de zero. Se houver um erro, investigue com strace . Você não precisa deste programa para dar mensagens de erro muito legais.

    
por 16.04.2016 / 02:04
3

Bless tee em vez de echo para sudo é uma forma comum de abordar uma situação em que você precisa limitar os root perms. O redirecionamento para / dev / null é para impedir que qualquer saída vaze - o tee faz o que você deseja.

echo "17" | sudo tee /sys/class/gpio/export > /dev/null
echo "out" | sudo tee /sys/class/gpio/gpio17/direction > /dev/null
    
por 15.04.2016 / 06:57
0

Você pode criar um script que realize a tarefa desejada. Em seguida, crie uma nova conta de usuário que só possa efetuar login fornecendo uma chave usada pelo OpenSSH.

Nota: Qualquer um poderá executar esse script se tiver o arquivo de chave, portanto, certifique-se de que o arquivo de chave OpenSSH não seja legível por qualquer pessoa que você deseje impedir de executar a tarefa.

Na configuração do OpenSSH (no arquivo authorized_keys), antes de especificar a chave, especifique um comando (seguido por um espaço), conforme descrito neste texto de "exemplo":

command="myscript" keydata optionalComment

Esta opção de configuração pode restringir essa chave OpenSSH a somente executar um comando específico. Agora você tem sudo concedendo as permissões, mas a configuração do OpenSSH é a parte da solução que está realmente sendo usada para restringir / limitar o que esse usuário é capaz de fazer, para que o usuário não esteja executando outros comandos. Isso também não tem um arquivo de configuração "sudo" tão complicado, então se você usar o OpenBSD ou se o novo "doas" do OpenBSD começar a se tornar mais popular (com versões futuras do sistema operacional que você usa) , você não precisará ser desafiado por muita complexidade na configuração do sudo.

    
por 17.04.2016 / 18:43