Minha primeira contribuição para o kernel foi roubada
(ariel-miculas.github.io)- Ariel Miculas investigou uma falha que quebrava a depuração multithread do gdbserver em PowerPC32 e encontrou um bug de corrupção de memória no kernel Linux, mas a correção final entrou como um patch separado do mantenedor e ele recebeu apenas o crédito
Reported-by - As pistas foram uma thread antiga de e-mails sobre o mesmo sintoma e um commit que alterou a posição de
thread_struct threaddentro detask_struct, levando alguns threads a permanecerem em estados incorretos de processo e fazendo o gdbserver perder o controle - A análise da causa usou
pahole, ftrace e breakpoints de hardware baseados no DABR do PowerPC, confirmando que um buffer overflow emptrace_put_fprsobrescrevia campos comotask_struct.__state - O overflow acontecia porque um índice para elementos de 32 bits era aplicado a um array de 64 bits, permitindo que o gdbserver no lado do usuário escrevesse até 256 bytes além do array
fp_state.fpr, que só tinha 32 entradas - O mantenedor de PowerPC, Michael Ellerman, aplicou sua própria correção e depois enviou uma desculpa, reconhecendo que só o
Reported-bynão refletia adequadamente a contribuição e que o patch deveria ter sido desenvolvido em conjunto
Depuração quebrada do gdbserver no PowerPC32
- Cerca de um ano e meio atrás, Ariel Miculas pediu tempo na empresa anterior para investigar um problema que estava bloqueando a funcionalidade de depuração de um projeto
- O problema era que, na arquitetura PowerPC32, o gdbserver não conseguia depurar corretamente aplicações multithread
- A conexão do gdbserver caía e a sessão de depuração deixava de poder ser controlada
- Não estava claro se a causa estava no toolchain, no gdbserver, no kernel Linux ou em patches customizados do kernel
- Depois de pesquisar e revisar investigações anteriores, ele encontrou uma thread de e-mails sobre o mesmo sintoma
- Essa thread também apontava para o commit que causou o problema
- O patch movia a definição
thread_struct thread, que ficava no meio detask_struct, para o final da estrutura
Pistas que levaram à corrupção de memória no estado dos threads
- Segundo a análise anterior de Holger Brunck, o gdbserver enviava
SIGSTOPao kernel para cada thread e aguardava a resposta, mas na condição de erro o kernel respondia apenas a alguns sinais - Em nível mais baixo, após a interação com o gdbserver, alguns threads acabavam em um estado de processo incorreto, e então o gdbserver perdia o controle
- Ariel passou 3 a 4 dias lendo descrições de commits relacionados a PowerPC e alterações em torno de
task_struct, além de verificar se o problema havia sido resolvido em versões posteriores do kernel, mas não encontrou solução - Ele alterou a posição de
thread_struct threadpara confirmar as condições de reprodução e examinou o layout detask_structcom pahole - Também usou ftrace para rastrear quando os threads do processo depurado eram escalonados
- Os threads travados, ao contrário dos demais, eram escalonados apenas uma vez
- Essa observação fez a hipótese de corrupção de memória voltar ao foco
A causa real encontrada com breakpoints de hardware
- Ele confirmou que, assim como os debug registers no x86, o PowerPC também tinha funcionalidade semelhante por meio do registrador DABR
- Depois de pesquisar como usar breakpoints de hardware no Linux, implementou um módulo de kernel com base em uma resposta no Stack Overflow
- Com esse módulo, colocou um breakpoint de hardware no campo
task_struct.__statepara rastrear quem escrevia aquele valor - O módulo customizado mostrou stack traces dos pontos em que
task_struct.__stateera escrito, e entre eles um caminho suspeito levou a um buffer overflow emptrace_put_fpr ptrace_put_fpré usado na API POKEUSER, e o overflow sobrescrevia campos importantes detask_struct, como__state__statearmazena o estado do processo- O kernel também usa esse campo ao rastrear processos parados pelo depurador
Escrita em array que podia avançar até 256 bytes
- A causa do overflow era a aplicação de um índice projetado para um array de elementos de 32 bits em um array de elementos de 64 bits
- O índice que apontava para os FPRs era 64, e o intervalo de acesso com elementos de 64 bits era
64 * 8 = 512bytes - Na prática, o array
fp_state.fprtinha apenas 32 entradas, então a memória realmente disponível era32 * 8 = 256bytes - Como resultado, o usuário — isto é, o gdbserver — podia escrever até 256 bytes além do fim do array
Envio upstream e conflito por crédito
- Ariel considerou que a corrupção de memória capaz de sobrescrever a memória do estado do processo podia ter implicações de segurança e enviou o patch para
security@kernel.org- Como essa mailing list é privada, não era possível linkar o patch enviado originalmente
- O mantenedor de PowerPC, Michael Ellerman, entrou em contato em particular e respondeu que cuidaria do problema
- Ariel enviou dois patches de correção
- O patch original enviado à mailing list de segurança
- Outra versão do patch refletindo sugestões sobre o envio original
- O segundo patch era baseado em código existente do kernel que emulava o comportamento do PowerPC32 no PowerPC64, e esse código já tratava corretamente a indexação dos FPRs
- Michael Ellerman não aceitou nenhum dos dois patches e implementou sua própria correção
- Ariel queria que seu patch fosse aceito pelo mérito de ter corrigido o problema e como crédito por sua primeira contribuição ao kernel, e estava disposto a enviar versões seguintes incorporando feedback
- Na prática, o único crédito recebido foi a tag
Reported-by, e Ariel considerou isso injusto diante do esforço gasto em análise da causa, correção, testes, validação, incorporação de feedback interno e adaptação ao kernel mais recente- Na documentação do Linux,
Reported-byé a tag que dá crédito a quem encontra e relata um bug - Esse problema já havia sido relatado 6 anos antes
- Na documentação do Linux,
Atualização e resposta com pedido de desculpas
- Um usuário do Hacker News destacou um e-mail em que Michael Ellerman escreveu: “obrigado pelo patch, mas quero corrigir de outra forma. Você poderia testar o patch abaixo e verificar se o bug foi corrigido?”
- Esse e-mail mostra que Michael Ellerman escolheu implementar sua própria solução em vez de revisar o patch de Ariel, e pediu a Ariel que testasse essa nova correção
- Ariel encontrou o patch original que havia enviado à mailing list de segurança e encaminhou a thread para a linuxppc-dev
- A atualização posterior incluiu uma resposta com pedido de desculpas sobre a forma como os patches foram tratados
- Ela incluía a mensagem de que “deveríamos ter gasto mais tempo desenvolvendo seu patch em conjunto”
- Também reconhecia que a tag
Reported-bynão refletia adequadamente a contribuição de Ariel
1 comentários
Comentários do Hacker News
Mesmo que não aceitassem o patch inteiro, teria sido mais adequado dar crédito a Ariel Miculas
É muito provável que esse problema de segurança não tivesse sido corrigido por ninguém se ele não o tivesse encontrado e enviado uma correção
Se Michael leu o patch dele, mudou apenas parte do estilo e o enviou em seu próprio nome, não dar crédito é antiético; mesmo que o código fosse péssimo, ainda assim foi uma colaboração, e eu não teria vontade de trabalhar de novo com alguém que fizesse isso comigo
No segundo caso, pelo menos fica o
Co-Authored-By, mas só depois que alguém despejou o código do meu projeto no próprio repositório, sem histórico de commits, e chamou aquilo de “fork” é que percebi como isso pode ser uma experiência bem amarga do ponto de vista do colaboradorMesmo que o código fosse ruim, a correção refatorada que foi mesclada não existiria sem aquele código, e dizer “minha versão é melhor” pode soar bastante desdenhoso
Porém, vendo a resposta que linka a resposta real do mantenedor, a última frase não se sustenta
Mas, neste caso, o autor do post é mais próximo de um coautor daquele patch
Em termos de publicação acadêmica, é parecido com enviar um preprint a alguém, e essa pessoa publicar um artigo sobre o mesmo tema colocando você apenas nos agradecimentos, não como coautor
Aqui não se trata de publicação, mas de desenvolvimento do kernel, ainda assim a autoria continua sendo importante no currículo profissional
Feedback sobre consistência de estilo e estrutura é necessário, mas um bom mantenedor é alguém que reconhece o crédito e faz as coisas fluírem suavemente nos bastidores
Na época, quando Ted Tso ficou satisfeito com a correção do meu trabalho, ele incluiu o patch, e eu nem pedi nem recebi crédito
Meu interesse era apenas melhorar o kernel, não deixar meu nome registrado
Alguns anos depois meu nome acabou entrando na lista de contribuidores por outro trabalho, mas de um jeito ou de outro eu não me importei
Reported-by: Ariel Miculas, e isso parece corretoO patch do mantenedor é melhor
fpidx < (PT_FPSCR - PT_FPR0)put, a atribuição substituta*data = child->thread.fp_state.fpscr;usada quandofpidxestá fora do intervaloFPRINDEX, que se reduz à identidade quandoTS_FPRWIDTHé 1A mensagem de commit do patch original dizia que “no PPC32, pode-se assumir que
TS_FPRWIDTHé 1”, mas ainda assim incluíaFPRNUMBER,FPRHALFeFPRINDEXSó porque alguém encontrou uma incompatibilidade de array simples de corrigir não significa que um patch com bug deva ser aceito como está
Ainda assim, o mantenedor deveria ter reconhecido que Miculas não apenas fez uma denúncia simples, mas investigou, encontrou a causa raiz e até criou sua própria versão de uma correção simples quase igual
Reported-byé impreciso demais para transmitir a nuance de que a parte em questão investigou a fundo e identificou a causaIsso é comum em projetos com novos contribuidores, e é a forma correta de fazer
É um processo de ensinar e integrar a pessoa; se você simplesmente refaz o trabalho, desestimula a contribuição e elimina a oportunidade de aprendizado
Escrever a segunda versão é sempre mais fácil
Chamar isso de correção simples é não entender a quantidade de trabalho envolvida em corrigir bugs no desenvolvimento de software
Aqui, o próprio Michael admitiu que no início não conseguiu reproduzir o problema e só o confirmou depois
Isso mostra bem a quantidade de trabalho que o OP dedicou à depuração e correção, e não é certo tomar esse trabalho para si
No texto original, ele disse que queria que o patch fosse aceito para receber crédito e se tornar contribuidor do kernel, e que estava disposto a enviar versões posteriores incorporando o feedback
O mantenedor poderia ter feito checkout do código do OP, aplicado as mudanças que queria e gasto uns 2 minutos necessários para fazer o commit como coautor
Assim, a melhor correção seria mesclada e o trabalho de outra pessoa também seria reconhecido
Especialmente porque o OP expressou claramente que queria receber crédito, essa teria sido a melhor opção
Dito isso, esses mantenedores de repositórios parecem frequentemente deixar passar as cortesias sociais, então não chega a surpreender
PRs muitas vezes não são aceitos por vários motivos, mas não me importo
Envio PRs para deixar o código público, não para gastar tempo tornando-o “bom” o suficiente para ser mesclado
Eu simplesmente o disponibilizo; se alguém gostar o bastante, essa pessoa cuida do processo
Alguns foram mesclados como estavam, outros foram ajustados um pouco pelo dono do repositório e então mesclados
Não escrevo código open source por glória ou popularidade, mas porque gosto
Sinto falta dos anos 80 e 90
O kernel Linux não é uma recompensa e, embora eu tenha empatia pelo OP, é correto que a comunidade prefira uma solução mais fácil de manter do que a versão vinda dele
Portanto, o mantenedor estava dentro do seu escopo de autoridade
Ainda assim, dar crédito à pessoa que contribuiu com a correção é algo muito fácil
No Node.js, damos crédito nas notas de lançamento e, quando pegamos parte do trabalho de um PR e o modificamos, tentamos adicionar
Co-Authored-By:Quando você faz manutenção por muito tempo, o crédito passa a importar menos para você, então é fácil esquecer que, para novos contribuidores, isso é muito importante
Em um caso como este, em que compartilhar o crédito era importante para o OP e também merecido, a falta de mais cuidado foi uma perda tanto para o OP quanto para aquela área do Linux
Não é assim que um projeto que depende do esforço da comunidade se sustenta
Eu achava que um projeto tão grande e respeitado quanto o kernel Linux teria pessoas capazes de cuidar do melhor interesse do projeto e, ao mesmo tempo, respeitar novos contribuidores
Ninguém está dizendo que uma solução inferior deva ser aceita só porque vem de um novo contribuidor
O caminho correto é revisar o patch, explicar o que está errado e por quê, sugerir como reescrevê-lo e, se necessário, escrever essa parte em conjunto e se tornar coautor
É assim que se cria um fluxo de contribuidores que continuarão interessados
Reported-ByA documentação do kernel define
Suggested-bycomo uma das convenções de tagsA tag
Suggested-by:indica que a ideia do patch foi sugerida por aquela pessoa e garante crédito por essa ideiaEla diz, em especial, que a tag não deve ser adicionada sem a permissão de quem sugeriu a ideia, caso ela não tenha sido publicada em um fórum público
Também afirma que, ao dar crédito de boa-fé a quem relatou a ideia, aumenta-se a chance de essa pessoa voltar a ajudar no futuro
Nesta situação,
Suggested-bytalvez tivesse sido mais apropriadaEla transmite melhor a ideia de que a pessoa encontrou a solução para o problema, mas, por não estar familiarizada com o projeto, a sintaxe exata do patch não foi mantida
Referência: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
Um está em um
ifdeffora doif, e o outro está dentro da instruçãoif; ou seja, não é uma diferença técnica, mas uma diferença de estiloSe for isso, o autor fez muito mais do que simplesmente “sugerir” uma ideia de patch
Ele depurou o problema e escreveu o patch inteiro, que foi aceito com apenas uma pequena alteração
1: https://news.ycombinator.com/item?id=37672558
Em questões de segurança, velocidade e precisão são mais importantes que formalidades, e os mantenedores do kernel agiram corretamente ao dar crédito com
Reported-bySuggested-byteria sido um pouco melhor, mas não é o que o OP queria; o OP parece ter desejado o rótulo de “contribuidor do kernel” com base em um patch muito pequenoVendo algumas reações nesta thread, espero que certas pessoas não gerenciem desenvolvedores júnior ou intermediários
Se há um júnior empolgado na equipe e ele abriu um PR que ajuda em algum issue, mas cuja qualidade é insuficiente, a pior resposta é repreendê-lo dizendo que “não está bom o bastante”, jogar o código fora e reescrever você mesmo
Isso desanima a pessoa, desperdiça o tempo dela e o seu, impede que ela aprenda qualquer coisa, faz com que na próxima vez ela não consiga melhorar nem contribuir de forma significativa, e ainda a torna relutante em pedir ajuda ou contribuir por iniciativa própria
Mesmo que ela tenha se metido em uma área de código complexa, há formas melhores de interagir
Há a expectativa de que o júnior da equipe fique por um tempo, e como suas competências básicas já foram verificadas em certa medida na entrevista, dá para confiar no seu potencial de crescimento
Uma pessoa aleatória na internet não tem obrigação de continuar por perto, e a maioria dessas correções “drive-by” não fica
Não se sabe que capacidade essa pessoa realmente tem, nem como ela reagirá a pedidos de alteração
Uma das coisas mais frustrantes do ponto de vista de gestão é alguém colocar uma pessoa aleatória na minha linha de reporte e me tornar responsável pelo desempenho dela
Agora imagine alguém na internet, com um forte senso de entitlement, passar alguns dias produzindo uma correção de baixa qualidade e eu ter que orientá-la como se fosse seu gerente; essa analogia não faz sentido
Eu costumava me perguntar por que havia tanto alvoroço por causa de PRs indesejados ao hospedar um projeto no GitHub, mas agora entendo
Ser acusado de “mau gerente que desanima e faz os outros perderem tempo” por não querer lidar com PRs aleatórios é um excesso de entitlement
Ex.: https://news.ycombinator.com/item?id=25940799
Tornar-se profissional também é aprender a separar a si mesmo do próprio trabalho e entender que o colega não está tentando sabotá-lo com algum plano malicioso
Todo mundo já teve um projeto de meses cancelado e já recebeu comentários duros em code review
Aceitar isso e aprender com a situação faz parte de ser profissional
Claro que pessoas diretas e grosseiras também precisam aprender que esse comportamento estraga muitos relacionamentos
Não somos artistas, somos profissionais
Se um engenheiro civil júnior projetou uma ponte com falhas estruturais e o sênior disse “desculpe, mas isso está difícil de salvar agora, vou ter que refazer tudo”, o sênior não fez nada de errado
Eu não gostaria de dirigir por uma ponte precária só para preservar o orgulho do júnior
Comentários de pessoas que não parecem ter muita experiência mantendo grandes projetos open source parecem ver os mantenedores como especialmente cruéis
Quando se mantém um projeto open source pequeno, aceitar PRs de pessoas aleatórias dá bastante trabalho e muitas vezes leva mais tempo do que fazer diretamente
O tempo gasto revisando o código com cuidado, comunicando-se com o colaborador para corrigir problemas e alinhando-o à qualidade esperada e às convenções é grande
Um júnior no trabalho já passou por entrevista, mas aqui é um desconhecido aleatório pedindo uma alteração
Quando um PR é rejeitado, é frustrante, mas entendo os dois lados
Ao olhar a conversa do mantenedor, ele não parece especialmente maldoso ou rude
Quase parece uma thread ruim da LKML
A pessoa literalmente fez 95% do trabalho, e está sendo criticada por querer que esse mérito seja reconhecido
Não entendo por quê
Comparando os dois patches, há uma diferença clara
A contribuição no artigo linkado altera o comportamento dos dois ramos do
if...else, enquanto a contribuição final altera apenas o caminho dentro do ramoifO mantenedor deve ter tido um motivo para mudar o código
Ainda assim, como a correção em si foi praticamente 100% copiada, teria sido adequado dar crédito ao autor do patch original
O resultado original não tem
flush_fp_to_threadna arquitetura PPC32, nem a condiçãoelseO patch final chama
flush_fp_to_thread(child);, trata conformeCONFIG_PPC32dentro da verificação de intervalo defpidxe, se estiver fora do intervalo, atribuifpscrPortanto, há uma diferença real entre as duas soluções
Não posso dizer qual delas está correta ou é melhor, mas é claro que os resultados são diferentes
Isso também pode indicar falta de familiaridade com C
A manutenção de uma grande base de código é metade apagar incêndios e metade evitar colisões de nomes
Aquele patch era bem diferente, e eu deveria tê-lo guardado em algum lugar para poder mostrar
Isso é uma parte normal das contribuições ao kernel
Muitas vezes, a forma mais concisa de comunicar o problema é um patch, então você envia um patch, e a expectativa deveria ser a de que eles não vão usar aquele patch
De cabeça, isso aconteceu comigo pelo menos três vezes [1][2][3]
Sinceramente, nunca nem pensei em ficar bravo, porque meu objetivo principal era corrigir o bug, e fiquei feliz que isso aconteceu
Meu conselho sincero ao OP é: é melhor apagar esse post do blog. Você vai se arrepender depois
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
[3] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
Fiquei bem surpreso ao ver o nome da outra pessoa
Isso acontece o tempo todo em projetos open source e, no fim, só desanima novas contribuições
No ano passado, peguei uma issue que estava aberta havia anos, criei um PR, corrigi também os testes e ainda fiz um trabalho separado para corrigir problemas de build
O mantenedor só pegou o PR que corrigia os problemas de build e simplesmente ignorou a issue original
Não há nenhuma chance de eu voltar a gastar tempo contribuindo para aquele projeto
Você abre um PR e recebe comentários pedindo mudanças
Alguns dias depois, quando tem tempo para corrigir, ele já foi fechado por outro PR feito por alguém que contribui com frequência
Ao olhar esse PR, ele é quase igual ao meu código, com só um nome de variável alterado, e é aprovado imediatamente pelo critério de revisão entre “amigos”
Quando você olha o perfil dessa pessoa, quase todas as contribuições são cópias do código de outras pessoas
Tento ajudar a organizar para que se encaixe no restante da base de código, e essa é a parte mais difícil
Porque a maioria dos desenvolvedores quer simplesmente empurrar sua correção, em vez de primeiro aprender as convenções do projeto
Ainda assim, se o código estiver mais ou menos certo e for algo que eu possa aceitar, depois gastar uns 15 minutos ajustando e adicionar mais alguns testes, eu aceito
Este caso também parece uma situação dessas, e era isso que o mantenedor deveria ter feito
O contribuidor receberia crédito, e o mantenedor só precisaria gastar alguns minutos fazendo a limpeza necessária para ser aceito upstream; todos ficariam felizes
Dizer “minha versão é melhor” é muito arrogante e pouco profissional, seja ela de fato melhor ou não
Se, seis anos depois de a issue ter sido reportada, você ainda não a tinha corrigido, deveria reconhecer que, sem a contribuição daquela pessoa, a sua correção também não existiria
Ver a “solução” e depois pegar a correção é, na prática, algo muito próximo de roubo
As pessoas levam para o lado pessoal quando seu código não é aceito ou é reescrito, mas deixam passar que escrever código é uma parte pequena de manter um projeto
Eu normalmente olho os relatórios de bug e os merge requests para estimar como um patch será tratado
Em projetos que não parecem bons para contribuir, simplesmente desisti de muitas correções de bugs, e o kernel Linux de 2003 foi um exemplo disso
Alguns projetos são simplesmente assim; é melhor não se envolver, e geralmente é perda de tempo
Agora, depois da revolução da IA, licenças open source estão sendo violadas amplamente, então desde então não enviei mais código open source e também não enviarei no futuro
É realmente difícil entender a toxicidade aqui
Coisas do tipo “você não deveria fazer isso por reconhecimento, estrelas, recompensas, currículo etc.” parecem loucura
As pessoas que dizem isso têm emprego? Se têm, para serem coerentes deveriam trabalhar totalmente de graça
Salário também é uma forma de reconhecimento por uma contribuição
Pessoalmente, mesmo que a solução final tenha ficado diferente da proposta, se ela se baseou na descoberta da solução original, adicionar um coautor é algo muito pequeno
O autor tem motivos válidos para reclamar disso, e esta não será a primeira nem a última vez que alguém sente que sua contribuição não foi reconhecida
Mesmo que o patch em si fosse inferior, o esforço de depuração certamente não foi
No emprego, empregador e empregado fazem um acordo de trabalhar em troca de remuneração
Se você entra sem aviso em uma empresa qualquer e começa a fazer um trabalho que ninguém pediu, poucas pessoas diriam que você tem direito a remuneração
Uma analogia mais precisa para o que aconteceu com o OP é essa
Uma resposta do tipo “desculpe, mas a minha versão é melhor. Se você quer se tornar um contribuidor do kernel Linux, aqui está uma issue que você pode corrigir” é uma ótima forma de fazer alguém nunca mais querer ajudar e ainda desanimar outras pessoas
O mantenedor disse que não conseguiu reproduzir o crash com
gdbserver, mas que havia um caso de teste demonstrando o bug, então confirmou e testou a correção, e escreveu: “Obrigado pelo patch, mas eu queria corrigir de outro jeito. Você pode tentar o patch abaixo e confirmar se o bug foi corrigido?”https://lists.ozlabs.org/pipermail/linuxppc-dev/2022-June/24...
Também houve outros comentários de revisão que não foram mencionados
Diziam que não estava claro qual seria a vantagem de uma macro apenas para PPC32, que
#ifdefdeve ser evitado sempre que possível e que o patch do Michael era mais fácil de entenderhttps://lists.ozlabs.org/pipermail/linuxppc-dev/2022-June/24...
O OP está colocando palavras na boca da outra pessoa e ficando irritado com isso, o que não é uma boa estratégia, especialmente em comunicação por texto
O OP faz a conversa parecer grosseira, mas, na prática, ela não foi