Me robaron mi primera contribución al kernel
(ariel-miculas.github.io)- Ariel Miculas rastreó un problema que rompía la depuración multihilo de gdbserver en PowerPC32 y encontró un bug de corrupción de memoria en el kernel de Linux, pero la corrección final entró como un parche aparte del mantenedor y solo recibió crédito
Reported-by - La pista fue un hilo de correo anterior sobre el mismo síntoma y un commit que movió
thread_struct threaddentro detask_struct; esto dejaba a algunos hilos en un estado de proceso incorrecto y hacía que gdbserver perdiera el control - Para analizar la causa se usaron
pahole, ftrace y breakpoints de hardware basados en PowerPC DABR, confirmando que un desbordamiento de búfer enptrace_put_fprsobrescribía campos comotask_struct.__state - El desbordamiento ocurría al aplicar a un arreglo de 64 bits un índice pensado para elementos de 32 bits, y como el arreglo
fp_state.fprsolo tenía 32 entradas, el gdbserver del lado de usuario podía escribir hasta 256 bytes más allá del final - El mantenedor de PowerPC, Michael Ellerman, aplicó su propia solución, y una respuesta posterior incluyó una disculpa reconociendo que
Reported-byno reflejaba correctamente la contribución y que debieron haber desarrollado el parche junto con Ariel
Depuración rota de gdbserver en PowerPC32
- Hace alrededor de un año y medio, Ariel Miculas pidió tiempo en su empresa anterior para investigar un problema que bloqueaba la funcionalidad de depuración de un proyecto
- El problema era que gdbserver no podía depurar correctamente aplicaciones multihilo en la arquitectura PowerPC32
- La conexión de gdbserver se cortaba y ya no se podía seguir controlando la sesión de depuración
- No estaba claro si la causa estaba en el toolchain, gdbserver, el kernel de Linux o parches personalizados del kernel
- Tras revisar investigaciones previas y buscar información, encontró un hilo de correo que trataba el mismo síntoma
- Ese hilo también apuntaba al commit que provocó el problema
- Ese parche movía la definición
thread_struct thread, que estaba en medio detask_struct, hacia el final
Pistas que lo acotaron a corrupción de memoria en el estado del hilo
- Según el análisis previo de Holger Brunck, gdbserver enviaba
SIGSTOPal kernel para cada hilo y esperaba una respuesta, pero en la situación de error el kernel solo respondía a algunas señales - A bajo nivel, después de interactuar con gdbserver, algunos hilos quedaban en un estado de proceso incorrecto, y gdbserver perdía el control a partir de ahí
- Ariel pasó 3 o 4 días leyendo descripciones de commits relacionados con PowerPC y cambios alrededor de
task_struct, además de comprobar si el problema se había resuelto en versiones posteriores del kernel, pero no encontró la solución - Fue cambiando la posición de
thread_struct threadpara verificar las condiciones de reproducción y examinó el layout detask_structcon pahole - También rastreó con ftrace cuándo se planificaban los hilos del proceso bajo depuración
- Los hilos detenidos, a diferencia de los demás, solo se planificaban una vez
- Esa observación volvió a poner sobre la mesa la posibilidad de corrupción de memoria
La causa real encontrada con breakpoints de hardware
- Confirmó que, igual que los debug registers de x86, PowerPC también tenía una función similar mediante el registro DABR
- Después de investigar cómo usar breakpoints de hardware en Linux, implementó un módulo del kernel basándose en esta respuesta de Stack Overflow
- Con ese módulo colocó un breakpoint de hardware sobre el campo
task_struct.__statepara rastrear quién escribía ese valor - El módulo personalizado mostraba el stack trace de las escrituras a
task_struct.__state, y entre ellas apareció una ruta sospechosa que llevaba a un desbordamiento de búfer enptrace_put_fpr ptrace_put_fprse usa en la API POKEUSER, y el desbordamiento sobrescribía campos importantes detask_struct, como__state__stateguarda el estado del proceso- El kernel también usa ese campo al seguir procesos detenidos por el depurador
Una escritura en arreglo que podía pasarse hasta 256 bytes
- La causa del desbordamiento era que se aplicaba a un arreglo de elementos de 64 bits un índice diseñado para escribir en un arreglo de elementos de 32 bits
- El índice que apuntaba a los FPR era 64, y el rango de acceso en elementos de 64 bits era
64 * 8 = 512bytes - Pero el arreglo real
fp_state.fprsolo tenía 32 entradas, así que la memoria utilizable era32 * 8 = 256bytes - Como resultado, el usuario, es decir gdbserver, podía escribir hasta 256 bytes más allá del final del arreglo
Envío upstream y conflicto por el crédito
- Ariel envió el parche a
security@kernel.orgporque consideró que el problema de corrupción de memoria, capaz de sobrescribir memoria de estado de proceso, podía tener implicaciones de seguridad- Como esa lista de correo es privada, no podía enlazar el parche original enviado allí
- El mantenedor de PowerPC, Michael Ellerman, le respondió por privado diciendo que se encargaría del problema
- Ariel envió dos parches de corrección
- El parche original enviado a la lista de seguridad
- Otra versión del parche que incorporaba sugerencias sobre el envío original
- El segundo parche se basaba en código existente del kernel que emulaba el comportamiento de PowerPC32 en PowerPC64, y ese código ya manejaba correctamente el indexado de FPR
- Michael Ellerman no aceptó ninguno de los dos parches e implementó su propia corrección
- Ariel quería que se aceptara su parche para recibir reconocimiento por corregir el problema y como crédito por su primera contribución al kernel, y estaba dispuesto a enviar versiones posteriores incorporando feedback
- En la práctica, el único crédito que recibió fue la etiqueta
Reported-by, y Ariel sintió que eso era injusto frente al esfuerzo invertido en análisis de causa raíz, corrección, pruebas, validación, incorporación de feedback interno y adaptación al kernel más reciente- Según la documentación de Linux,
Reported-byes la etiqueta que da crédito a quien encontró y reportó el bug - Ese problema ya había sido reportado seis años antes
- Según la documentación de Linux,
Actualización y respuesta con disculpa
- Un usuario de Hacker News señaló un correo donde Michael Ellerman escribió: “gracias por el parche, pero quiero corregirlo de otra forma. ¿Podrías probar el siguiente parche y confirmar si arregla el bug?”
- Ese correo muestra que Michael Ellerman optó por implementar su propia solución en vez de revisar el parche de Ariel, y le pidió a Ariel que probara ese parche
- Ariel encontró el parche original que había enviado a la lista de seguridad y reenvió el hilo a linuxppc-dev
- Una actualización posterior incluyó una respuesta de disculpa sobre cómo se manejó el parche
- Incluía la frase de que “debí haber dedicado más tiempo a desarrollar tu parche junto contigo”
- También reconocía que la etiqueta
Reported-byno reflejaba correctamente la contribución de Ariel
1 comentarios
Opiniones en Hacker News
Aunque no se aceptara el parche completo, habría sido más apropiado darle crédito a Ariel Miculas.
Es muy probable que nadie hubiera corregido este problema de seguridad si él no lo hubiera encontrado y enviado una propuesta de corrección.
Si Michael leyó su parche, solo cambió algunos aspectos de estilo y luego lo presentó con su propio nombre, no darle crédito es poco ético; e incluso si el código hubiera sido pésimo, seguía siendo una colaboración, así que si a uno le hicieran eso, no querría volver a trabajar juntos.
En el segundo caso al menos queda
Co-Authored-By, pero cuando alguien volcó el código de mi proyecto en su propio repositorio sin historial de commits y lo “forkeó”, recién entendí que para quien contribuye es una experiencia bastante amarga.Aunque el código fuera malo, la corrección refactorizada que terminó fusionada no habría existido sin ese código, y decir “mi versión es mejor” puede sentirse bastante despectivo.
Sin embargo, al ver una respuesta que enlaza la respuesta real del mantenedor, la última frase no se sostiene.
Pero en este caso el autor del post se parece más a un coautor de ese parche.
En términos de publicación académica, es parecido a enviarle un preprint a alguien y que esa persona publique un artículo sobre el mismo tema, pero solo te ponga en los agradecimientos y no como coautor.
Aquí no se trata de publicación académica sino de desarrollo del kernel, pero la atribución de autoría sigue siendo importante en un currículum profesional.
La retroalimentación sobre estilo y consistencia estructural es necesaria, pero un gran mantenedor es quien reconoce el crédito y hace que las cosas fluyan sin fricción detrás de escena.
En ese momento, cuando Ted Tso quedó conforme con la exactitud de mi trabajo, incorporó el parche, y yo ni pedí ni recibí crédito.
Lo único que me importaba era mejorar el kernel; no me interesaba dejar mi nombre.
Años después mi nombre terminó entrando en la lista de contribuidores por otro trabajo, pero de cualquier manera no me importaba.
Reported-by: Ariel Miculas, y parece correcto.El parche del mantenedor es mejor.
fpidx < (PT_FPSCR - PT_FPR0).putno se pierde la asignación alternativa*data = child->thread.fp_state.fpscr;, que se usa cuandofpidxestá fuera de rango.FPRINDEX, innecesario porque se reduce a la identidad cuandoTS_FPRWIDTHes 1.El mensaje del commit del parche original decía que “en PPC32 se puede asumir que
TS_FPRWIDTHes 1”, pero aun así incluíaFPRNUMBER,FPRHALFyFPRINDEX.El hecho de haber encontrado una inconsistencia de arreglo que se puede corregir fácilmente no significa que haya que aceptar tal cual un parche con errores.
Aun así, el mantenedor debió reconocer que Miculas no solo hizo un reporte simple, sino que investigó, encontró la causa raíz e incluso preparó su propia versión de una corrección sencilla casi igual.
Reported-byno transmite bien el matiz de que la persona investigó a fondo e identificó la causa.Eso es lo que se suele hacer con nuevos contribuidores en un proyecto, y es la forma correcta.
Es un proceso de enseñar a la persona y ayudarla a adaptarse; si simplemente rehaces el trabajo, le quitas motivación para contribuir y también la oportunidad de aprender.
Escribir la segunda versión siempre es más fácil.
Llamar a esto una corrección simple es no entender la cantidad de trabajo que implica corregir bugs en desarrollo de software.
Aquí Michael también reconoció que al principio no pudo reproducirlo y que solo después lo confirmó.
Eso muestra bien la cantidad de trabajo que el OP dedicó a la depuración y la corrección, y no está bien apropiarse de ese trabajo.
En el texto original decía que quería que se aceptara el parche, recibir crédito y convertirse en contribuidor del kernel, y que estaba dispuesto a enviar versiones posteriores incorporando la retroalimentación.
El mantenedor podría haber hecho checkout del código del OP, aplicar los cambios que quisiera y dedicar los aproximadamente 2 minutos necesarios para commitearlo como coautor.
Así se fusiona la mejor corrección y también se reconoce el trabajo de otra persona.
En especial porque el OP expresó claramente que quería recibir crédito, eso habría sido lo mejor.
Dicho eso, no me sorprende; parece que estos mantenedores de repositorios a menudo pasan por alto las cortesías sociales.
Muchas veces los PR no se aceptan por distintos motivos, pero no me importa.
Envío el PR para dejar el código público, y no dedico tiempo a hacerlo lo suficientemente “bueno” como para que lo fusionen.
Lo entrego tal cual, y si a alguien le gusta lo suficiente, que esa persona se encargue del proceso.
Algunos se fusionaron tal cual, y en otros el dueño del repositorio hizo pequeños arreglos y luego los fusionó.
No escribo código open source por gloria ni popularidad, sino porque me gusta.
Extraño los años 80 y 90.
El kernel de Linux no es una recompensa, y aunque empatizo con el OP, es correcto que la comunidad prefiera una solución más fácil de mantener que la versión que llegó desde fuera
Así que el mantenedor estaba dentro de su ámbito de autoridad
Aun así, es muy fácil dar crédito a la persona que contribuyó a la corrección
En Node.js damos crédito en las notas de lanzamiento, y cuando tomamos parte del trabajo de un PR y lo modificamos, intentamos agregar
Co-Authored-By:Cuando llevas mucho tiempo manteniendo un proyecto, el crédito se vuelve menos importante para ti, así que es fácil olvidar que para los nuevos contribuidores puede ser muy importante
En un caso como este, en el que compartir el crédito era importante para el OP y además correspondía, no haber sido más cuidadosos fue una pérdida tanto para el OP como para esa área de Linux
No es una forma sostenible para un proyecto que depende del esfuerzo de la comunidad
Yo pensaba que en un proyecto tan grande y respetado como el kernel de Linux habría personas capaces de cuidar lo mejor para el proyecto y, al mismo tiempo, respetar a los nuevos contribuidores
Nadie está diciendo que haya que aceptar una solución que no sea la mejor solo porque viene de un contribuidor nuevo
La forma correcta es revisar el parche, explicar qué está mal y por qué, sugerir cómo reescribirlo y, si hace falta, escribir esa parte juntos para convertirse en coautores
Así se genera un flujo de contribuidores que seguirán interesados en el futuro
Reported-ByLa documentación del kernel define
Suggested-bycomo una de las convenciones de etiquetasLa etiqueta
Suggested-by:indica que esa persona sugirió la idea del parche, y garantiza el crédito por esa ideaEn particular, dice que si la idea no fue publicada en un foro público, no debe agregarse sin el permiso de quien la propuso
También señala que, si se da crédito de buena fe a quien aporta una idea, aumenta la posibilidad de que vuelva a ayudar en el futuro
En esta situación,
Suggested-bypodría haber sido más apropiadoTransmite mejor la idea de que encontró la solución al problema, pero que, por no estar familiarizado con el proyecto, no se mantuvo la sintaxis exacta del parche
Referencia: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...
Uno está en un
ifdeffuera delif, y el otro está dentro de la sentenciaif; es decir, no es una diferencia técnica sino una diferencia de estiloSi eso es así, el autor hizo mucho más que simplemente “sugerir” la idea del parche
Depuró el problema y escribió el parche completo, y terminó siendo aceptado con un único cambio pequeño
1: https://news.ycombinator.com/item?id=37672558
En temas de seguridad, la velocidad y la precisión son más importantes que el formato, y los mantenedores del kernel manejaron el caso correctamente al dar crédito con
Reported-bySuggested-byhabría sido un poco mejor, pero no es lo que el OP quería; el OP parece haber querido la marca de “contribuidor del kernel” sobre la base de un parche muy pequeñoAl ver algunas reacciones en este hilo, espero que algunos, en particular, no gestionen desarrolladores junior o de nivel intermedio.
Si en el equipo hay un junior entusiasta que envía un PR que ayuda con algún issue pero cuya calidad es insuficiente, la peor respuesta es regañarlo diciendo que “no es lo bastante bueno”, tirar su código y reescribirlo uno mismo.
Le bajas la moral, haces que esa persona y tú pierdan el tiempo, impides que aprenda algo, y haces que la próxima vez no pueda mejorar ni contribuir de forma significativa, además de que se vuelva reacia a pedir ayuda o a contribuir por iniciativa propia.
Incluso si se metió en un área de código compleja, hay mejores formas de interactuar.
Con el junior del equipo existe la expectativa de que se quede un tiempo, y como pasó por entrevistas ya se verificó en cierta medida su competencia básica, así que se puede confiar en su potencial de crecimiento.
Una persona cualquiera de internet no tiene obligación de quedarse, y la mayoría de estas correcciones “drive-by” no permanecen.
No sabes qué capacidades tiene realmente esa persona ni cómo reaccionará a las solicitudes de cambios.
Una de las cosas más frustrantes desde el punto de vista de gestión es que alguien meta a una persona cualquiera en mi línea de reporte y me haga responsable de su desempeño.
Ahora imagina que alguien de internet, con un fuerte sentido de derecho adquirido, dedicó unos días a producir una corrección de baja calidad y que yo debería orientarlo como si fuera su gerente; la analogía no tiene sentido.
Antes me preguntaba por qué había tanto lío con los PR no solicitados cuando uno aloja un proyecto en GitHub, pero ahora lo entiendo.
Si no quieres lidiar con PR aleatorios, que te acusen de ser “un mal gerente que desmoraliza y hace perder el tiempo” es un sentido de derecho exagerado.
Ej.: https://news.ycombinator.com/item?id=25940799
Convertirse en profesional también implica aprender a separar la propia persona del trabajo producido, y entender que los colegas no tienen un plan malicioso para sabotearte.
A todos alguna vez nos cancelaron un proyecto en el que trabajamos durante meses, y todos recibimos comentarios duros en revisiones de código.
Aceptarlo y aprender de ello es parte de ser profesional.
Por supuesto, las personas directas y groseras también tienen que aprender que esa actitud arruina muchas relaciones.
No somos artistas, somos profesionales.
Si un ingeniero civil junior diseñó un puente con fallas estructurales y un senior dijo “lo siento, pero esto ya es difícil de rescatar, tendremos que rehacerlo todo”, el senior no hizo nada malo.
No quiero conducir por un puente endeble solo para proteger el orgullo del junior.
Parece que los comentarios de gente sin mucha experiencia manteniendo grandes proyectos open source ven al mantenedor como especialmente duro.
Si mantienes un proyecto open source pequeño, recibir PR de personas cualquiera implica mucho trabajo y a menudo toma más tiempo que hacerlo tú mismo.
Requiere mucho tiempo revisar el código con cuidado, comunicarse con el contribuidor para corregir problemas y ajustarse a la calidad esperada y a las convenciones.
Un junior en el trabajo ya pasó por entrevistas, pero aquí se trata de un desconocido cualquiera que pide un cambio.
Que te rechacen un PR duele, pero entiendo las posturas de ambos lados.
Al ver la conversación del mantenedor, no parece particularmente malintencionado ni grosero.
Se siente casi como uno de los malos hilos de LKML.
Esa persona hizo literalmente el 95% del trabajo, y la están criticando por querer que se le reconozca el mérito.
No entiendo por qué.
Al comparar los dos parches, se ve una diferencia clara.
La contribución del artículo enlazado cambia el comportamiento de ambas ramas de
if...else, pero la contribución final solo cambia la ruta dentro de la ramaif.El mantenedor seguramente tuvo una razón para cambiar el código.
Aun así, la corrección real fue copiada casi al 100%, así que lo apropiado habría sido darle crédito al autor del parche original.
El resultado original no tiene
flush_fp_to_threadni la condiciónelseen la arquitectura PPC32.El parche final llama a
flush_fp_to_thread(child);, luego maneja el caso segúnCONFIG_PPC32dentro de la verificación de rango defpidx, y si está fuera de rango asignafpscr.Por eso hay una diferencia real entre las dos soluciones.
No puedo decir cuál es correcta o mejor, pero es claro que los resultados son distintos.
Podría indicar falta de dominio de C.
Mantener una gran base de código es mitad apagar incendios y mitad evitar colisiones de nombres.
Ese parche era bastante distinto, y debí haberlo guardado en algún lugar para poder mostrarlo.
Esto es una parte normal de contribuir al kernel
Muchas veces la forma más concisa de comunicar el problema es un parche, por eso uno envía un parche, y la expectativa debería ser que no van a usar ese parche
Pensándolo rápido, esto me pasó al menos tres veces [1][2][3]
Sinceramente, nunca se me ocurrió enojarme, porque mi objetivo principal era corregir el bug y me alegró que se corrigiera
Mi recomendación honesta para el OP es que borre esta entrada del blog. Se va a arrepentir después
[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...
Me sorprendió bastante ver el nombre de la otra persona
En los proyectos de código abierto esto pasa todo el tiempo, y al final solo desalienta más contribuciones
El año pasado tomé un issue que llevaba años abierto, armé un PR, arreglé también el código de pruebas e incluso hice un trabajo separado para corregir problemas de build
El mantenedor solo tomó el PR que corregía los problemas de build e ignoró sin más el issue original
No hay ninguna posibilidad de que vuelva a dedicar tiempo a contribuir a ese proyecto
Abres un PR y recibes comentarios pidiendo cambios
Unos días después, cuando tienes tiempo para corregirlos, ya está cerrado por otro PR de alguien que contribuye seguido
Al ver ese PR, es casi igual a mi código, solo cambió el nombre de una variable, y se aprueba de inmediato bajo un criterio de revisión de “amigos”
Si ves el perfil de esa persona, casi todas sus contribuciones son código copiado de otros
Intento ayudar a ordenarlo para que encaje con el resto del codebase, pero eso es lo más difícil
Porque la mayoría de los desarrolladores quiere simplemente meter su arreglo en lugar de aprender primero las convenciones del proyecto
Aun así, si el código está más o menos bien y después de hacer merge yo puedo pulirlo unos 15 minutos y agregar un poco más de pruebas, lo acepto
Este caso también parece una situación así, y el mantenedor debería haber actuado de esa manera
El contribuidor recibe crédito, y el mantenedor solo dedica unos minutos a la limpieza necesaria para que sea aceptable upstream; todos habrían quedado contentos
Decir “mi versión es mejor” es muy arrogante y poco profesional, sea realmente mejor o no
Si no pudiste arreglarlo durante 6 años desde que se reportó el issue por primera vez, tienes que reconocer que, sin la contribución de esa persona, tu arreglo tampoco habría existido
Ver la “solución” y luego tomar ese arreglo es, en la práctica, casi robar
La gente se lo toma personal cuando su código no es aceptado o es reescrito, pero pierde de vista que escribir código es una parte pequeña de mantener un proyecto
Yo normalmente reviso los reportes de bugs y las solicitudes de merge para estimar cómo se va a tratar un parche
En proyectos que no parecen buenos para contribuir, simplemente abandoné muchos arreglos de bugs, y el kernel de Linux de 2003 fue un ejemplo de eso
Algunos proyectos simplemente son así; es mejor no meterse, y por lo general es una pérdida de tiempo
Ahora, después de la revolución de la IA, las licencias de código abierto se están violando ampliamente, así que desde entonces no he enviado código open source y no lo haré en el futuro
Me cuesta mucho entender la toxicidad de acá
Decir cosas como “no deberías hacerlo por reconocimiento, estrellas, recompensas o currículum” suena a locura
¿La gente que dice eso tiene trabajo? Si lo tiene, para ser coherentes deberían trabajar totalmente gratis
El salario también es una forma de reconocimiento por una contribución
Personalmente, aunque la solución final haya cambiado respecto de la propuesta, si se basó en el descubrimiento de la solución original, agregar a la persona como coautora es algo mínimo
El autor tiene una razón válida para quejarse de esto, y no será la primera ni la última vez que alguien sienta que su contribución no fue reconocida
Aunque el parche en sí fuera inferior, el esfuerzo de debugging de ninguna manera lo fue
En un empleo, el empleador y el empleado acuerdan que se trabaja a cambio de una compensación
Si entras sin avisar a una empresa y empiezas a hacer un trabajo que nadie pidió, casi nadie diría que tienes derecho a recibir una compensación
Esa es una analogía más precisa de lo que le ocurrió al OP
Una respuesta del tipo “lo siento, pero mi versión es mejor. Si quieres convertirte en colaborador del kernel de Linux, aquí hay un issue que puedes arreglar” es una excelente forma de hacer que alguien no vuelva a ayudar nunca más y de desmotivar también a otras personas
El mantenedor dijo que no pudo reproducir el crash con
gdbserver, pero que había un caso de prueba que mostraba el bug, así que lo verificó e hizo una prueba de la corrección, y escribió: “gracias por el parche, pero quería arreglarlo de otra manera. ¿Puedes probar el parche de abajo y confirmar si el bug se corrige?”https://lists.ozlabs.org/pipermail/linuxppc-dev/2022-June/24...
También hubo otros comentarios de revisión que no se mencionaron
Decían que no veía qué ventaja tenía una macro solo para PPC32, que los
#ifdefdeberían evitarse siempre que sea posible, y que el parche de Michael era más fácil de entenderhttps://lists.ozlabs.org/pipermail/linuxppc-dev/2022-June/24...
El OP está poniendo palabras en boca de la otra persona y enojándose por eso, y no es una buena estrategia, sobre todo en la comunicación por texto
El OP hace que la conversación parezca descortés, pero en realidad no lo fue