2 คะแนน โดย GN⁺ 2023-09-28 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • Ariel Miculas ติดตามปัญหาที่ทำให้ การดีบักแบบมัลติเธรดของ gdbserver บน PowerPC32 ใช้งานไม่ได้ และพบ bug หน่วยความจำเสียหายใน Linux kernel แต่การแก้ไขสุดท้ายถูกรวมเข้าไปเป็นแพตช์แยกของ maintainer ทำให้ได้รับเครดิตเพียง Reported-by
  • เบาะแสคือเธรดอีเมลเก่าที่พูดถึงอาการเดียวกัน และคอมมิตที่ เปลี่ยนตำแหน่งของ thread_struct thread ภายใน task_struct ซึ่งนำไปสู่อาการที่บางเธรดค้างอยู่ในสถานะโปรเซสที่ผิดพลาด และทำให้ gdbserver สูญเสียการควบคุม
  • การวิเคราะห์สาเหตุใช้ pahole, ftrace และ hardware breakpoint ที่อิง DABR ของ PowerPC และยืนยันได้ว่า buffer overflow ใน ptrace_put_fpr เขียนทับฟิลด์อย่าง task_struct.__state
  • overflow เกิดจากการนำดัชนีสำหรับ element ขนาด 32 บิตไปใช้กับอาร์เรย์ 64 บิต ทำให้ gdbserver ฝั่งผู้ใช้สามารถเขียนเลยอาร์เรย์ fp_state.fpr ที่มีเพียง 32 รายการออกไปได้สูงสุดถึง 256 ไบต์
  • Michael Ellerman maintainer ของ PowerPC นำแนวทางแก้ไขของตัวเองไปใช้ และในอีเมลตอบกลับภายหลังมี คำขอโทษ ว่าเครดิตเพียง Reported-by ไม่ได้สะท้อนการมีส่วนร่วมอย่างเหมาะสม และควรได้พัฒนาแพตช์ร่วมกัน

การดีบัก gdbserver ที่เสียบน PowerPC32

  • ประมาณหนึ่งปีครึ่งก่อน Ariel Miculas ขอเวลาในบริษัทเดิมเพื่อสืบสวนปัญหาที่ขัดขวางความสามารถด้านการดีบักของโปรเจกต์
  • ปัญหาคือ gdbserver ไม่สามารถดีบักแอปพลิเคชันแบบมัลติเธรดได้อย่างถูกต้องบนสถาปัตยกรรม PowerPC32
    • การเชื่อมต่อ gdbserver หลุด และไม่สามารถควบคุมเซสชันดีบักต่อได้
    • ยังไม่แน่ชัดว่าสาเหตุอยู่ที่ toolchain, gdbserver, Linux kernel หรือแพตช์เคอร์เนลแบบ custom
  • หลังจากตรวจสอบและค้นหาข้อมูลเดิม พบ เธรดอีเมล ที่พูดถึงอาการเดียวกัน
    • เธรดนี้ยังชี้ไปยัง คอมมิต ที่ทำให้เกิดปัญหา
    • แพตช์ดังกล่าวเป็นการย้าย definition ของ thread_struct thread ที่เคยอยู่กลาง task_struct ไปไว้ท้ายสุด

เบาะแสที่ narrowed down จากสถานะเธรดไปสู่หน่วยความจำเสียหาย

  • ตามการวิเคราะห์เดิมของ Holger Brunck gdbserver จะส่ง SIGSTOP ไปยังเคอร์เนลสำหรับแต่ละเธรดและรอการตอบกลับ แต่ในสถานการณ์ที่เกิดข้อผิดพลาด เคอร์เนลตอบกลับเพียงบาง signal เท่านั้น
  • ในระดับล่าง หลังจากโต้ตอบกับ gdbserver แล้ว บางเธรดถูกวางไว้ใน สถานะโปรเซส ที่ผิดพลาด และ gdbserver ก็สูญเสียการควบคุมหลังจากนั้น
  • Ariel ใช้เวลา 3–4 วันอ่านคำอธิบายคอมมิตที่เกี่ยวกับ PowerPC และการเปลี่ยนแปลงรอบ ๆ task_struct พร้อมตรวจสอบว่าปัญหาถูกแก้ใน kernel รุ่นถัด ๆ ไปหรือไม่ แต่ไม่พบวิธีแก้
  • เขาลองเปลี่ยนตำแหน่งของ thread_struct thread เพื่อยืนยันเงื่อนไขการ reproduce และใช้ pahole ตรวจดู layout ของ task_struct
  • ใช้ ftrace ติดตามว่าเธรดของโปรเซสที่ถูกดีบักถูก schedule เมื่อใด
    • เธรดที่หยุดค้างถูก schedule เพียงครั้งเดียว ต่างจากเธรดอื่น ๆ
    • ข้อสังเกตนี้ทำให้กลับมาพิจารณาความเป็นไปได้เรื่อง หน่วยความจำเสียหาย อีกครั้ง

สาเหตุจริงที่พบด้วย hardware breakpoint

  • เขายืนยันได้ว่า PowerPC ก็มีความสามารถคล้ายกับ debug registers ของ x86 โดยใช้ DABR register
  • หลังจากศึกษาวิธีใช้ hardware breakpoint บน Linux แล้ว เขาสร้าง kernel module โดยอิงจาก คำตอบใน Stack Overflow
  • ใช้โมดูลนี้ตั้ง hardware breakpoint บนฟิลด์ task_struct.__state เพื่อติดตามว่าใครเขียนค่าเข้าไป
  • kernel module แบบ custom แสดง stack trace ของตำแหน่งที่เขียนลง task_struct.__state และหนึ่งในเส้นทางที่ผิดปกตินำไปสู่ buffer overflow ใน ptrace_put_fpr
  • ptrace_put_fpr ถูกใช้ใน POKEUSER API และ overflow นี้เขียนทับฟิลด์สำคัญใน task_struct เช่น __state
    • __state ใช้เก็บสถานะของโปรเซส
    • เคอร์เนลใช้ฟิลด์นี้ด้วยเมื่อติดตามโปรเซสที่ถูก debugger หยุดไว้

การเขียนอาร์เรย์ที่สามารถล้ำออกไปได้ถึง 256 ไบต์

  • สาเหตุของ overflow อยู่ที่การนำดัชนีที่ออกแบบมาสำหรับอาร์เรย์ element ขนาด 32 บิตไปใช้กับ อาร์เรย์ element ขนาด 64 บิต
  • ดัชนีที่ชี้ไปยัง FPR มี 64 ค่า และช่วงการเข้าถึงเมื่อคิดตาม element 64 บิตคือ 64 * 8 = 512 ไบต์
  • แต่ในความเป็นจริง อาร์เรย์ fp_state.fpr มีเพียง 32 entries และหน่วยความจำที่ใช้ได้คือ 32 * 8 = 256 ไบต์
  • ผลคือผู้ใช้ หรือก็คือ gdbserver สามารถเขียนเลยท้ายอาร์เรย์ออกไปได้สูงสุดถึง 256 ไบต์

การส่ง upstream และข้อขัดแย้งเรื่องเครดิต

  • Ariel เห็นว่าปัญหาหน่วยความจำเสียหายที่สามารถเขียนทับหน่วยความจำสถานะโปรเซสได้อาจมีผลกระทบด้านความปลอดภัย จึงส่งแพตช์ไปที่ security@kernel.org
    • mailing list นี้เป็นแบบไม่สาธารณะ จึงไม่สามารถลิงก์แพตช์ที่ส่งครั้งแรกได้
  • Michael Ellerman maintainer ของ PowerPC ติดต่อกลับเป็นการส่วนตัวและบอกว่าจะจัดการปัญหานี้
  • Ariel ส่งแพตช์แก้ไข 2 แบบ
  • แพตช์ที่สองอิงจากโค้ดเคอร์เนลเดิมที่จำลองพฤติกรรม PowerPC32 บน PowerPC64 และโค้ดนั้นจัดการการ indexing ของ FPR ได้อย่างถูกต้อง
  • Michael Ellerman ไม่รับแพตช์ทั้งสอง แต่ implement แนวทางแก้ไขของตัวเอง
  • Ariel อยากให้แพตช์ของตนเองถูกยอมรับ เพื่อให้ได้รับเครดิตในฐานะผู้แก้ปัญหานี้และในฐานะผู้มีส่วนร่วมกับเคอร์เนลครั้งแรก และเขาก็พร้อมส่งเวอร์ชันถัดไปหลังปรับตาม feedback
  • เครดิตที่ได้รับจริงมีเพียงแท็ก Reported-by และ Ariel รู้สึกว่าไม่ยุติธรรมเมื่อเทียบกับความพยายามที่ลงไปในการวิเคราะห์สาเหตุ แก้ไข ทดสอบ ตรวจสอบ รับ feedback ภายในบริษัท และปรับใช้กับเคอร์เนลล่าสุด
    • ตามเอกสารของ Linux Reported-by เป็นแท็กที่ให้เครดิตแก่ผู้พบและรายงาน bug
    • ปัญหานี้เคยถูกรายงานมาแล้วเมื่อ 6 ปีก่อน

อัปเดตและอีเมลขอโทษตอบกลับ

  • ผู้ใช้ Hacker News ชี้ให้เห็น อีเมล ที่ Michael Ellerman เขียนว่า “ขอบคุณสำหรับแพตช์ แต่ผมอยากแก้ด้วยวิธีที่ต่างออกไป คุณช่วยลองทดสอบแพตช์ด้านล่างเพื่อยืนยันว่า bug ถูกแก้แล้วได้ไหม”
  • อีเมลนี้แสดงให้เห็นว่า Michael Ellerman เลือก implement เองแทนที่จะ review แพตช์ของ Ariel และขอให้ Ariel ทดสอบแพตช์นั้น
  • Ariel หาแพตช์เดิมที่เคยส่งไปยัง mailing list ด้านความปลอดภัย แล้ว forward เธรดอีเมล ไปยัง linuxppc-dev
  • ในอัปเดตภายหลังมีอีเมลตอบกลับที่ขอโทษเรื่องวิธีจัดการแพตช์
    • มีข้อความว่า “ผมน่าจะใช้เวลากับการพัฒนาแพตช์ของคุณร่วมกันมากกว่านี้”
    • ยังระบุด้วยว่าแท็ก Reported-by ไม่ได้สะท้อนการมีส่วนร่วมของ Ariel อย่างเหมาะสม

1 ความคิดเห็น

 
GN⁺ 2023-09-28
ความคิดเห็นจาก Hacker News
  • แม้จะไม่รับแพตช์ทั้งหมด ก็ควรให้ เครดิตแก่ Ariel Miculas มากกว่า
    ปัญหาความปลอดภัยนี้มีโอกาสสูงว่าจะไม่มีใครแก้ หากเขาไม่ค้นพบและส่งแนวทางแก้ไขไป
    ถ้า Michael อ่านแพตช์ของเขาแล้วแค่เปลี่ยนสไตล์บางส่วน ก่อนส่งในชื่อตัวเอง การไม่ให้เครดิตก็ถือว่าไร้จริยธรรม และต่อให้โค้ดแย่แค่ไหน มันก็ยังเป็นการร่วมมือกันอยู่ดี ถ้าโดนแบบนั้นก็คงไม่อยากทำงานร่วมกันอีก

    • เมื่อก่อนเคยคิดว่าเป็นเรื่องโอเคที่จะเอางานของคนอื่นมาเขียนใหม่ทั้งหมดในแบรนช์ของตัวเองแล้ว merge หรือเขียนใหม่เป็น commit ใหม่ใน GitHub PR
      แบบหลังอย่างน้อยยังเหลือ Co-Authored-By ไว้ แต่หลังจากมีคนเอาโค้ดโปรเจกต์ของฉันไป dump ลง repository ของตัวเองโดยไม่มีประวัติ commit แล้วเรียกว่า “fork” ถึงได้รู้ว่าในฐานะผู้มีส่วนร่วม มันเป็นประสบการณ์ที่ค่อนข้างขมขื่น
      ต่อให้โค้ดนั้นแย่ การแก้ไขที่ถูก refactor แล้วและถูก merge เข้าไปก็คงไม่มีอยู่ถ้าไม่มีโค้ดนั้น และคำว่า “เวอร์ชันของฉันดีกว่า” อาจฟังดูเหมือนดูแคลนมาก
      แต่พอเห็นคำตอบที่ลิงก์ไปยังคำตอบจริงของ maintainer แล้ว ประโยคสุดท้ายนั้นก็ใช้ไม่ได้
    • เห็นด้วย maintainer อาจบอกได้ว่าเพราะคุณภาพ จึงจะเขียนโค้ดที่จะเข้า kernel เอง ซึ่งตัวมันเองก็เข้าใจได้
      แต่ในกรณีนี้ ผู้เขียนใกล้เคียงกับการเป็น ผู้เขียนร่วม ของแพตช์นั้น
      ถ้าเทียบกับงานตีพิมพ์ทางวิชาการ ก็เหมือนส่ง preprint ให้ใครสักคน แล้วคนนั้นไปตีพิมพ์บทความในหัวข้อเดียวกัน โดยใส่ชื่อไว้แค่ในคำขอบคุณ แต่ไม่ใส่เป็นผู้เขียนร่วม
      ที่นี่ไม่ใช่งานตีพิมพ์แต่เป็นการพัฒนา kernel แต่การระบุชื่อผู้เขียนยังสำคัญต่อประวัติวิชาชีพอยู่ดี
    • ผมมองว่าบทบาทของ maintainer ที่มีประสบการณ์คือการเป็น ผู้ช่วยสนับสนุน ที่ช่วยให้ contribution ของคนอื่นเข้าไปได้อย่างเรียบร้อยที่สุด
      feedback เรื่องสไตล์และความสอดคล้องของโครงสร้างเป็นสิ่งจำเป็น แต่ maintainer ที่ยอดเยี่ยมคือคนที่ยอมรับเครดิตของผู้อื่นและทำให้งานไหลลื่นอยู่เบื้องหลัง
    • ตอนส่งแพตช์ชุดแรก ๆ ไปยัง Linux kernel ยังเป็นช่วงก่อนที่จะส่งแบบกึ่งอัตโนมัติผ่าน LKML ได้ จึงต้องคุยกับ maintainer ระหว่างดำเนินการ
      ตอนนั้นเมื่อ Ted Tso พอใจกับความถูกต้องของงานของผม เขาก็ใส่แพตช์เข้าไป และผมก็ไม่ได้เรียกร้องหรือได้รับเครดิต
      สิ่งที่ผมสนใจมีเพียงการปรับปรุง kernel ไม่ได้สนใจการทิ้งชื่อไว้
      หลายปีต่อมาชื่อผมไปอยู่ในรายชื่อ contributors จากงานอื่น แต่ไม่ว่าทางไหนผมก็ไม่ได้ใส่ใจ
    • เขาได้รับเครดิตแล้ว ใน commit มี Reported-by: Ariel Miculas อยู่ และดูถูกต้องดี
  • แพตช์ของ maintainer ดีกว่า

    1. ไม่เสียการตรวจ fpidx < (PT_FPSCR - PT_FPR0) ในกรณี 32-bit
    2. ไม่เสียการกำหนดค่าแทน *data = child->thread.fp_state.fpscr; ที่ใช้เมื่อ fpidx อยู่นอกช่วงในฟังก์ชัน put
    3. เลี่ยง macro FPRINDEX ที่ไม่จำเป็น ซึ่งลดรูปเป็น identity เมื่อ TS_FPRWIDTH เป็น 1
      commit message ของแพตช์เดิมบอกว่า “ใน PPC32 สามารถสมมติได้ว่า TS_FPRWIDTH เป็น 1” แต่ก็ยังใส่ FPRNUMBER, FPRHALF, FPRINDEX เข้ามา
      แค่พบ array mismatch ที่แก้ได้ ไม่ได้แปลว่าต้องรับ แพตช์ที่มีบั๊ก เข้าไปตามเดิม
      อย่างไรก็ตาม maintainer ควรยอมรับว่า Miculas ไม่ได้แค่รายงานเฉย ๆ แต่ได้ตรวจสอบจนพบ สาเหตุราก และยังทำเวอร์ชันแก้ไขแบบง่ายที่แทบเหมือนกันของตัวเองด้วย
      Reported-by ไม่แม่นยำพอที่จะสื่อ nuance ว่าบุคคลนั้นตรวจสอบอย่างละเอียดและระบุสาเหตุได้แล้ว
    • เห็นด้วยว่างานของ maintainer ดีกว่า แต่ก็สามารถทำ code review กับแพตช์แล้วขอให้อัปเดตได้
      สำหรับผู้มีส่วนร่วมรายใหม่ โปรเจกต์ต่าง ๆ มักทำแบบนั้น และนั่นคือวิธีที่ถูกต้อง
      มันเป็นกระบวนการสอนคนและช่วยให้เขาปรับตัว แต่ถ้าไปทำงานใหม่เองเสียเลย ก็ทำลายแรงจูงใจในการ contribute และตัดโอกาสในการเรียนรู้ไปด้วย
    • การ debug นั้นยาก และบางครั้งยากมาก การเขียน patch แก้ไขใน codebase ที่คุ้นเคยเป็นเรื่องค่อนข้างเล็กน้อย โดยเฉพาะถ้ามีเวอร์ชันที่แก้ได้ของการแก้ไขก่อนหน้าเป็นแนวทาง
      การเขียนเวอร์ชันที่สองย่อมง่ายกว่าเสมอ
      การเรียกสิ่งนี้ว่าเป็นการแก้ง่าย ๆ แสดงว่าไม่เข้าใจปริมาณงานที่ต้องใช้ในการแก้บั๊กในการพัฒนาซอฟต์แวร์
      ในที่นี้ Michael เองก็ยอมรับว่าตอนแรก reproduce ไม่ได้ และเพิ่งยืนยันได้ภายหลัง
      นี่แสดงให้เห็นชัดถึงปริมาณงานที่ OP ทุ่มให้กับ การ debug และการแก้ไข และการขโมยงานนั้นไปไม่ใช่เรื่องถูกต้อง
    • คำพูดที่ว่า “แค่พบ array mismatch ที่แก้ได้ ไม่ได้แปลว่าต้องรับแพตช์ที่มีบั๊กเข้าไปตามเดิม” เป็นการบิดคำพูดของคนอื่น
      ในต้นฉบับบอกว่าเขาอยากให้แพตช์ได้รับการยอมรับ ได้เครดิต และกลายเป็น contributor ของ kernel และยินดีส่งเวอร์ชันถัดไปตาม feedback
    • ไม่มีใครบอกว่าต้องรับแพตช์เดิมเข้าไปตามนั้น
      maintainer แค่ checkout โค้ดของ OP แล้วแก้ตามที่ต้องการ จากนั้นใช้เวลาประมาณ 2 นาทีเพื่อ commit ในฐานะ ผู้เขียนร่วม ก็พอ
      แบบนั้นการแก้ไขที่ดีที่สุดจะถูก merge และงานของคนอื่นก็ได้รับการยอมรับ
      โดยเฉพาะเมื่อ OP แสดงชัดเจนว่าอยากได้รับเครดิต นั่นจึงเป็นทางเลือกที่ดีที่สุด
      แต่ดูเหมือน maintainer ของ repository แบบนี้มักพลาดเรื่องมารยาททางสังคมอยู่บ่อย ๆ จึงไม่น่าแปลกใจ
    • ผมส่งแพตช์และ PR จำนวนมากไปยังโอเพนซอร์สหลายโครงการ และส่วนใหญ่ก็เพื่อแก้ปัญหาที่ผมเจอเอง
      PR มักไม่ถูกรับด้วยหลายเหตุผล แต่ผมไม่ใส่ใจ
      ผมส่ง PR เพื่อให้โค้ดเผยแพร่อยู่ตรงนั้น และไม่ได้ใช้เวลาทำให้มัน “ดี” พอที่จะ merge
      แค่ส่งไว้ตามนั้น ถ้าใครชอบพอ คนนั้นก็จัดการขั้นตอนต่อเอง
      บางอันถูก merge ตามเดิม บางอันเจ้าของ repository แก้นิดหน่อยแล้ว merge
      ผมไม่ได้เขียนโค้ดโอเพนซอร์สเพราะเกียรติยศหรือความนิยม แต่ทำเพราะชอบ
      คิดถึงยุค 80 และ 90
  • เคอร์เนล Linux ไม่ใช่รางวัล และแม้จะเห็นใจ OP แต่ชุมชนควรเลือกแนวทางแก้ปัญหาที่ดูแลรักษาได้ง่ายกว่าจากเวอร์ชันที่ชุมชนเสนอ
    ดังนั้น maintainer จึงยังอยู่ในขอบเขตอำนาจของตน
    แต่การให้ เครดิต แก่ผู้ที่มีส่วนร่วมในการแก้ไขนั้นทำได้ง่ายมาก
    ใน Node.js เราให้เครดิตใน release notes และเมื่อหยิบบางส่วนของงานจาก PR มาปรับแก้ เราก็พยายามเพิ่ม Co-Authored-By:
    เมื่อดูแลรักษามานาน เครดิตอาจสำคัญกับตัวเองน้อยลง จึงลืมได้ง่ายว่าสิ่งนี้สำคัญมากสำหรับผู้ร่วมให้ข้อมูลรายใหม่
    ในกรณีนี้ การที่ไม่ใส่ใจมากพอในการแบ่งปันเครดิต ทั้งที่มันสำคัญกับ OP และสมควรได้รับ ถือเป็นความสูญเสียทั้งต่อ OP และต่อส่วนงาน Linux นั้น

    • ถ้าทุ่มเทแรงกายแรงใจมากมายให้โปรเจกต์เพื่อปรับแก้ contribution แล้วท้ายที่สุดได้ยินว่า “เวอร์ชันของฉันดีกว่า ไปได้แล้ว” ก็คงโกรธแน่
      นั่นไม่ใช่วิธีที่โปรเจกต์ซึ่งพึ่งพาความพยายามของชุมชนจะยืนยาวได้
      ผมเคยคิดว่าโปรเจกต์ที่ใหญ่และได้รับความเคารพอย่างเคอร์เนล Linux น่าจะมีคนที่รู้จักดูแลผลประโยชน์สูงสุดของโปรเจกต์ พร้อมกับเคารพผู้ร่วมให้ข้อมูลรายใหม่ด้วย
      คงไม่มีใครเสนอให้รับแนวทางแก้ปัญหาที่ไม่ดีที่สุดเพียงเพราะเป็นผู้ร่วมให้ข้อมูลรายใหม่
      วิธีที่ถูกต้องคือรีวิวแพตช์ อธิบายว่าอะไรเป็นปัญหาและเพราะอะไร แนะนำว่าควรเขียนใหม่อย่างไร และถ้าจำเป็นก็ร่วมเขียนส่วนนั้นด้วยกันจนกลายเป็น ผู้เขียนร่วม
      แบบนั้นจึงจะเกิดกระแสผู้ร่วมให้ข้อมูลที่สนใจต่อไปในอนาคต
    • คำว่า “เคอร์เนล Linux ไม่ใช่รางวัล” ดูจะถูกต้องในความหมายที่แย่ที่สุดเมื่อดูจากบทความนี้
    • ดูเหมือนเขาจะได้รับเครดิตผ่านแท็ก Reported-By
  • ในเอกสารของเคอร์เนลมีการกำหนด Suggested-by ไว้เป็นหนึ่งในธรรมเนียมการใช้แท็ก
    แท็ก Suggested-by: ระบุว่าบุคคลนั้นเป็นผู้เสนอไอเดียของแพตช์ และรับประกันเครดิตสำหรับไอเดียนั้น
    โดยเฉพาะถ้าไอเดียนั้นไม่ได้ถูกโพสต์ในฟอรัมสาธารณะ ก็ระบุว่าไม่ควรเพิ่มแท็กนี้โดยไม่ได้รับอนุญาตจากผู้เสนอ
    ยังเขียนไว้ด้วยว่า หากให้เครดิตแก่ผู้แจ้งไอเดียอย่างจริงใจ พวกเขาก็มีแนวโน้มจะกลับมาช่วยอีกในอนาคต
    ในสถานการณ์นี้ Suggested-by อาจเหมาะสมกว่า
    มันสื่อได้ดีกว่าว่าเขาพบแนวทางแก้ปัญหาแล้ว แต่เพราะไม่คุ้นเคยกับโปรเจกต์ จึงไม่ได้คงไวยากรณ์ที่ถูกต้องของแพตช์ไว้
    อ้างอิง: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/lin...

    • ผมไม่ได้ลองเทียบแพตช์ทั้งสอง แต่ตามคอมเมนต์ด้านล่าง [1] ระบุว่าความแตกต่างเพียงอย่างเดียวระหว่างแพตช์ที่ถูกรับกับแพตช์ที่ถูกเสนอคือจุดที่แก้ไข
      ฝั่งหนึ่งอยู่ใน ifdef นอก if ส่วนอีกฝั่งอยู่ในคำสั่ง if ด้านในเท่านั้น และเป็น ความต่างด้านสไตล์ ไม่ใช่ความต่างทางเทคนิค
      ถ้าเป็นเช่นนั้น ผู้เขียนก็ทำไปมากกว่าการแค่ “เสนอ” ไอเดียแพตช์มาก
      เขาดีบัก issue และเขียนแพตช์ทั้งหมดแล้ว เพียงแต่แพตช์ที่ถูกรับมีการเปลี่ยนแปลงเล็กน้อยหนึ่งจุด
      1: https://news.ycombinator.com/item?id=37672558
    • วิธีนั้นก็เป็นไปได้ แต่ดูเหมือนจะเหมาะกับกรณีที่ไม่ใช่ issue ด้านความปลอดภัยมากกว่า
      สำหรับ issue ด้านความปลอดภัย ความเร็วและความถูกต้องสำคัญกว่ารูปแบบ และ maintainer ของเคอร์เนลก็จัดการได้ถูกต้องแล้วในแง่ที่ให้เครดิตด้วย Reported-by
      Suggested-by อาจดีกว่าเล็กน้อยก็จริง แต่ไม่ใช่สิ่งที่ OP ต้องการ และดูเหมือน OP ต้องการป้ายว่าเป็น “ผู้ร่วมให้ข้อมูลเคอร์เนล” จากแพตช์เล็กมากชิ้นหนึ่ง
  • เมื่อดูปฏิกิริยาบางส่วนในเธรดนี้แล้ว ก็หวังว่าบางคนจะไม่ต้องไปบริหารนักพัฒนาระดับจูเนียร์หรือระดับกลางเป็นพิเศษ
    ถ้าในทีมมีจูเนียร์ที่กระตือรือร้น และส่ง PR ที่ช่วยแก้บางประเด็นได้แต่คุณภาพยังไม่ถึง การดุว่า “ยังดีไม่พอ” แล้วทิ้งโค้ดไปเขียนใหม่เอง คือการรับมือที่แย่ที่สุด
    มันบั่นทอนกำลังใจ ทำให้ทั้งเขาและคุณเสียเวลา ไม่ได้เรียนรู้อะไร ทำให้ครั้งหน้าปรับปรุงหรือมีส่วนร่วมอย่างมีความหมายไม่ได้ และยังทำให้ไม่อยากขอความช่วยเหลือหรือมีส่วนร่วมโดยสมัครใจด้วย
    ต่อให้เขากระโดดเข้าไปในส่วนโค้ดที่ซับซ้อน ก็ยังมีวิธีปฏิสัมพันธ์ที่ดีกว่านี้

    • การบริหารและโค้ชจูเนียร์ในบริษัทหรือทีม กับการที่คนสุ่ม ๆ บนอินเทอร์เน็ตส่งแพตช์เล็ก ๆ เข้ามานั้นต่างกัน
      จูเนียร์ในทีมมีความคาดหวังว่าจะอยู่ไปอีกระยะหนึ่ง และผ่านการสัมภาษณ์จนตรวจสอบทักษะพื้นฐานได้ในระดับหนึ่งแล้ว จึงเชื่อถือศักยภาพในการเติบโตได้
      คนสุ่ม ๆ บนอินเทอร์เน็ตไม่มีพันธะว่าต้องอยู่ต่อ และการแก้แบบ “แวะมายิงแล้วไป” แบบนี้ส่วนใหญ่ก็ไม่อยู่ต่อ
      เราไม่รู้ว่าคนนั้นมีความสามารถจริง ๆ แค่ไหน หรือจะตอบสนองต่อคำขอให้แก้อย่างไร
      หนึ่งในเรื่องที่น่าหงุดหงิดที่สุดจากมุมมองการจัดการ คือการที่ใครสักคนเอาคนสุ่ม ๆ มาใส่ไว้ในสายงานที่ผมต้องดูแล แล้วทำให้ผมต้องรับผิดชอบผลงานของคนนั้น
      ทีนี้ลองนึกภาพว่ามีคนบนอินเทอร์เน็ตที่รู้สึกว่าตัวเองมีสิทธิ์เรียกร้อง ใช้เวลาหลายวันทำการแก้ไขคุณภาพต่ำขึ้นมา แล้วผมควรต้องโค้ชเขาเหมือนเป็นผู้จัดการของเขา อุปมานี้จึงไม่สมเหตุสมผล
      เมื่อก่อนเคยสงสัยว่าทำไมการโฮสต์โปรเจกต์บน GitHub แล้วมี PR ที่ไม่ต้องการถึงกลายเป็นเรื่องวุ่นวาย แต่ตอนนี้เข้าใจแล้ว
      การที่ถ้าไม่อยากรับมือกับ PR แบบสุ่ม ๆ แล้วถูกตำหนิว่าเป็น “ผู้จัดการแย่ ๆ ที่บั่นทอนกำลังใจและทำให้คนอื่นเสียเวลา” นั้นเป็นความรู้สึกว่าตัวเองมีสิทธิ์เรียกร้องที่เกินไป
      ตัวอย่าง: https://news.ycombinator.com/item?id=25940799
    • ถ้าจูเนียร์ที่กระตือรือร้นเกินไปใช้เวลาหนึ่งสัปดาห์แก้งานที่ไม่ใช่ลำดับความสำคัญและไม่ใช่งานที่ได้รับมอบหมาย ก็เรียกไปคุยแยกได้ว่า “เรื่องนี้พักไว้ก่อน แล้วค่อยมาดูกันทีหลัง ตอนนี้ X เป็นลำดับความสำคัญ เราจึงใช้เวลากับเรื่องนี้ไม่ได้”
      การเป็นมืออาชีพส่วนหนึ่งคือการเรียนรู้ที่จะแยกตัวเองออกจากผลงาน และเข้าใจว่าเพื่อนร่วมงานไม่ได้มีแผนร้ายจะขัดขวางเรา
      ทุกคนเคยมีโปรเจกต์ที่ทำมาหลายเดือนถูกยกเลิก และเคยได้รับคอมเมนต์แรง ๆ ใน code review
      การยอมรับและเรียนรู้จากเรื่องแบบนั้นเป็นหน้าที่ของมืออาชีพ
      แน่นอนว่าคนที่พูดตรงและหยาบคายก็ต้องเรียนรู้เหมือนกันว่าท่าทีแบบนั้นทำลายความสัมพันธ์จำนวนมาก
      เราไม่ใช่ศิลปิน แต่เป็นมืออาชีพ
      ถ้าวิศวกรโยธาจูเนียร์ออกแบบสะพานที่มีข้อบกพร่องด้านโครงสร้าง แล้วซีเนียร์บอกว่า “ขอโทษนะ แต่นี่คงกู้ยากแล้ว ต้องทำใหม่ทั้งหมด” ซีเนียร์ก็ไม่ได้ผิด
      เราคงไม่อยากขับรถบนสะพานที่เปราะบางเพียงเพื่อรักษาอัตตาของจูเนียร์
      คอมเมนต์ที่ดูเหมือนไม่ค่อยมีประสบการณ์ดูแลโปรเจกต์โอเพนซอร์สขนาดใหญ่ มักมอง maintainer ว่าโหดร้ายเป็นพิเศษ
      ถ้าเคยดูแลโปรเจกต์โอเพนซอร์สเล็ก ๆ จะรู้ว่าการรับ PR จากคนสุ่ม ๆ เป็นงานเยอะ และบ่อยครั้งใช้เวลามากกว่าทำเอง
      เวลาที่ต้องใช้ไปกับการรีวิวโค้ดอย่างละเอียด สื่อสารกับผู้ร่วมพัฒนาเพื่อแก้ปัญหา และทำให้คุณภาพกับธรรมเนียมสอดคล้องกับที่คาดหวังนั้นสูงมาก
      จูเนียร์ในที่ทำงานผ่านการสัมภาษณ์มาแล้ว แต่ในกรณีนี้คือคนแปลกหน้าแบบสุ่ม ๆ ที่ขอให้เปลี่ยนแปลง
      เมื่อ PR ถูกปฏิเสธก็ย่อมเสียใจ แต่เข้าใจมุมมองของทั้งสองฝ่าย
      เมื่อดูบทสนทนาของ maintainer แล้ว ก็ไม่ได้ดูใจร้ายหรือหยาบคายเป็นพิเศษ
    • ควรลองอ่านใหม่อีกครั้ง ดูไม่เหมือนว่าเรื่องนั้นเกิดขึ้นจริง ๆ และอย่างน้อยก็อาจเป็นการเรียบเรียงใหม่ตามอารมณ์ของฝ่ายใดฝ่ายหนึ่ง
    • น่าผิดหวังจริง ๆ ที่เธรดนี้มีคอมเมนต์แรง ๆ เยอะมาก
      แทบให้ความรู้สึกเหมือนเธรดแย่ ๆ ใน LKML
      คนนั้นทำ 95% ของงาน อย่างแท้จริง แต่กลับถูกวิจารณ์ว่าอยากได้รับการยอมรับในเครดิตนั้น
      ไม่เข้าใจเลยว่าทำไมถึงเป็นแบบนั้น
    • เธรดนี้เหมือนสายล่อฟ้าที่เผยให้เห็นความสัมพันธ์ระหว่างบุคคลที่ย่ำแย่ และเมื่อคิดถึงช่วงอายุของผู้อ่าน HN แล้วก็ค่อนข้างน่าอาย
  • เมื่อเทียบแพตช์ทั้งสอง จะเห็นความต่างชัดเจน
    การมีส่วนร่วมในบทความที่ลิงก์ไว้เปลี่ยนพฤติกรรมของทั้งสองกิ่งของ if...else แต่การมีส่วนร่วมสุดท้ายเปลี่ยนเฉพาะพาธในกิ่ง if
    maintainer น่าจะมีเหตุผลที่เปลี่ยนโค้ด
    ถึงอย่างนั้น การแก้ไขจริงก็แทบถูกคัดลอกมาเกือบ 100% ดังนั้นการให้ เครดิต แก่ผู้เขียนแพตช์ต้นฉบับจึงเหมาะสม

    • แพตช์ต้นฉบับในบทสนทนาทางอีเมลข้างบนก็เหมือนกัน
      ผลลัพธ์เดิมคือบนสถาปัตยกรรม PPC32 ไม่มีทั้ง flush_fp_to_thread และไม่มีเงื่อนไข else
      แพตช์สุดท้ายเรียก flush_fp_to_thread(child); แล้วจัดการตามว่าเป็น CONFIG_PPC32 หรือไม่ภายในการตรวจสอบช่วงของ fpidx จากนั้นถ้าอยู่นอกช่วงก็ใส่ค่าให้ fpscr
      ดังนั้นจึงมีความแตกต่างจริงระหว่างสองวิธีแก้
      บอกไม่ได้ว่าฝั่งไหนถูกหรือดีกว่า แต่ชัดเจนว่าผลลัพธ์ต่างกัน
    • ในฐานะคนที่ใช้ C มานาน ถ้ามีโค้ดที่เต็มไปด้วยมาโครแบบกำหนดเองเข้ามา ก็คงต้องระมัดระวัง
      มันอาจบ่งบอกถึงความไม่ชำนาญใน C
      การดูแล codebase ขนาดใหญ่ ครึ่งหนึ่งคือการดับไฟ และอีกครึ่งหนึ่งคือ การหลีกเลี่ยงการชนกันของชื่อ
    • ผมเป็นผู้เขียนบทความ น่าเสียดายที่แพตช์ต้นฉบับที่ผมส่งไปถูกส่งเฉพาะใน mailing list ด้านความปลอดภัยของเคอร์เนล Linux เท่านั้น จึงลิงก์ให้ไม่ได้
      แพตช์นั้นค่อนข้างต่างกัน และผมน่าจะเก็บไว้ที่ไหนสักแห่งเพื่อให้เอามาแสดงได้
  • นี่เป็นส่วนหนึ่งที่พบได้ทั่วไปของการมีส่วนร่วมกับเคอร์เนล
    หลายครั้งวิธีที่กระชับที่สุดในการสื่อสารปัญหาคือแพตช์ จึงส่งแพตช์ไป และควรตั้งความคาดหวังไว้ทางที่ว่าเขาอาจไม่ใช้แพตช์นั้น
    แค่นึกออกก็มีเรื่องแบบนี้เกิดกับผมอย่างน้อยสามครั้ง [1][2][3]
    พูดตรง ๆ ผมไม่เคยคิดจะโกรธเลย เพราะเป้าหมายหลักของผมคือการแก้บั๊ก และผมก็ดีใจที่มันถูกแก้
    ถ้าจะให้คำแนะนำ OP อย่างจริงใจ ผมว่าควรลบบล็อกโพสต์นี้เสีย คุณจะเสียใจภายหลัง
    [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...

    • การเปิดชื่ออีกฝ่ายแล้วโยนเขาให้โดนรุมดูแย่มากจริง ๆ
      ผมค่อนข้างตกใจเมื่อเห็นชื่อของอีกคน
  • ในโปรเจกต์โอเพนซอร์ส เรื่องแบบนี้เกิดขึ้นตลอด และสุดท้ายก็แค่ทำให้หมดแรงอยากมีส่วนร่วมเพิ่ม
    ปีที่แล้วผมรับอิสชูที่เปิดค้างมาหลายปีมาทำ สร้าง PR แก้โค้ดทดสอบ และยังทำงานแยกเพื่อแก้ปัญหาบิลด์ด้วย
    ผู้ดูแลเอาไปเฉพาะ PR ที่แก้ปัญหาบิลด์ ส่วนอิสชูเดิมก็ปล่อยผ่านไปเฉย ๆ
    ไม่มีทางเลยที่ผมจะกลับไปใช้เวลาเพื่อมีส่วนร่วมกับโปรเจกต์นั้นอีก

    • บางคนมี เรซูเม่ GitHub ทั้งหมดที่ประกอบจากการมีส่วนร่วมแบบคัดลอกแปะ
      เปิด PR แล้วได้รับคอมเมนต์ขอให้แก้ไข
      พออีกไม่กี่วันต่อมามีเวลาจะแก้ กลับพบว่าถูกปิดไปแล้วโดย PR อื่นจากคนที่มีส่วนร่วมบ่อย
      พอดู PR นั้น โค้ดแทบจะเหมือนของผม เปลี่ยนแค่ชื่อตัวแปรตัวเดียว และได้รับการอนุมัติทันทีตามมาตรฐานรีวิวแบบ “เพื่อนกัน”
      พอดูโปรไฟล์ของคนนั้น ก็พบว่าแทบทุกการมีส่วนร่วมคือการคัดลอกโค้ดของคนอื่น
    • ในฐานะผู้ดูแลโปรเจกต์เล็ก ๆ ผมดีใจเมื่อมีคนช่วยส่งโค้ดหรือเทสต์เข้ามา
      ผมพยายามช่วยจัดให้เข้ากับส่วนที่เหลือของ codebase ซึ่งนี่แหละเป็นส่วนที่ยากที่สุด
      เพราะนักพัฒนาส่วนใหญ่อยากยัดสิ่งที่ตัวเองแก้เข้าไปเลย มากกว่าจะเรียนรู้ธรรมเนียมของโปรเจกต์ก่อน
      ถึงอย่างนั้น ถ้าโค้ดโดยรวมถูกทาง และหลัง merge แล้วผมใช้เวลาปรับอีกประมาณ 15 นาทีพร้อมเพิ่มเทสต์อีกนิดหน่อยก็พอ ผมก็รับ
      กรณีนี้ก็ดูเหมือนสถานการณ์แบบนั้น และผู้ดูแลควรทำแบบนั้น
      ผู้มีส่วนร่วมได้เครดิต ส่วนผู้ดูแลก็ใช้เวลาไม่กี่นาทีเก็บงานเท่าที่จำเป็นให้พอ upstream รับได้ ทุกฝ่ายก็น่าจะพอใจ
      คำพูดว่า “เวอร์ชันของผมดีกว่า” นั้นฟังดูหยิ่งและไม่เป็นมืออาชีพมาก ไม่ว่ามันจะดีกว่าจริงหรือไม่ก็ตาม
      ถ้าแก้ไม่ได้มา 6 ปีนับจากที่มีรายงานอิสชูครั้งแรก ก็ควรยอมรับว่าหากไม่มีการมีส่วนร่วมของคนนั้น การแก้ของคุณก็คงไม่เกิดขึ้นเช่นกัน
      การเห็น “แนวทางแก้” แล้วเอาการแก้นั้นไปใช้ แทบจะใกล้เคียงกับการขโมยอยู่แล้ว
    • จากประสบการณ์ของผม สิ่งที่โปรเจกต์โค้ดต้องการจากการมีส่วนร่วมคือรายงานบั๊กและไอเดียปรับปรุง ไม่ใช่โค้ดของคุณเสมอไป
      ผู้คนมักมองเป็นเรื่องส่วนตัวเมื่อโค้ดของตัวเองไม่ถูกรับ หรือถูกเขียนใหม่ แต่พลาดไปว่าการเขียนโค้ดเป็นเพียงส่วนเล็ก ๆ ของการดำเนินโปรเจกต์
    • เป็นปัญหาที่พบได้บ่อย
      ปกติผมจะดูรายงานบั๊กและ merge request เพื่อประเมินว่าแพตช์จะถูกปฏิบัติอย่างไร
      ในโปรเจกต์ที่ดูไม่น่ามีส่วนร่วมด้วย ผมก็ปล่อยการแก้บั๊กจำนวนมากไป และเคอร์เนล Linux เมื่อปี 2003 ก็เป็นตัวอย่างหนึ่ง
      บางโปรเจกต์ก็เป็นแบบนั้นเอง ไม่เข้าไปยุ่งจะดีกว่า และส่วนใหญ่ก็เสียเวลาเปล่า
      ตอนนี้หลังการปฏิวัติ AI มีการละเมิดไลเซนส์โอเพนซอร์สอย่างกว้างขวาง ตั้งแต่นั้นมาผมจึงไม่ได้ส่งโค้ดโอเพนซอร์สอีก และต่อไปก็จะไม่ส่ง
  • ผมเข้าใจความเป็นพิษในที่นี้ได้ยากจริง ๆ
    คำพูดทำนองว่า “ไม่ควรทำเพื่อการยอมรับ ดาว รางวัล หรือเรซูเม่” ฟังดูบ้าบอมาก
    คนที่พูดแบบนั้นมีงานทำกันไหม? ถ้ามี เพื่อให้สอดคล้องกันก็ควรทำงานฟรีล้วน ๆ
    เงินเดือนก็เป็น รูปแบบหนึ่งของการยอมรับ ต่อการมีส่วนร่วมเช่นกัน
    ส่วนตัวแล้ว แม้วิธีแก้สุดท้ายจะต่างจากที่เสนอไป แต่ถ้ามันต่อยอดจากการค้นพบวิธีแก้เดิม การเพิ่มผู้ร่วมเขียนก็เป็นเรื่องเล็กมาก
    ผู้เขียนมีเหตุผลที่สมควรจะบ่นเรื่องนี้ และนี่คงไม่ใช่ครั้งแรกหรือครั้งสุดท้ายที่ใครสักคนรู้สึกว่าการมีส่วนร่วมของตนไม่ได้รับการยอมรับ

    • ผู้คนทำเหมือนเราเป็น หุ่นยนต์เขียนโค้ด ที่ไม่ต้องการการยอมรับใด ๆ ต่อผลงานที่เราทำได้ดี
      ต่อให้ตัวแพตช์ด้อยกว่า แต่ความพยายามในการดีบักไม่ได้ด้อยเลย
    • สถานการณ์นี้ต่างจากความสัมพันธ์การจ้างงาน
      ในการจ้างงาน นายจ้างกับลูกจ้างตกลงกันว่าจะทำงานแลกกับค่าตอบแทน
      ถ้าคุณเดินเข้าไปในบริษัทหนึ่งโดยไม่บอกล่วงหน้า แล้วเริ่มทำงานที่ไม่มีใครขอให้ทำ แทบไม่มีใครจะอ้างว่าตนมีสิทธิได้รับค่าตอบแทน
      อุปมาที่ตรงกับสิ่งที่เกิดขึ้นกับ OP มากกว่าคือแบบนี้
    • การให้เครดิตผู้เขียนเดิมและเสนอว่าตัวเองเป็น บรรณาธิการ น่าจะยุติธรรมกว่า
  • การตอบโต้ในทำนองว่า “ขอโทษนะ แต่เวอร์ชันของฉันดีกว่า ถ้าอยากเป็นผู้มีส่วนร่วมในเคอร์เนล Linux ก็มี issue นี้ที่คุณไปแก้ได้” เป็นวิธีที่ยอดเยี่ยมในการทำให้ใครสักคนไม่อยากช่วยอีก และยังบั่นทอนแรงจูงใจของคนอื่น ๆ ด้วย

    • ถ้อยคำจริง ๆ ไม่ได้เป็นแบบนั้น
      ผู้ดูแลบอกว่าไม่สามารถ reproduce crash ด้วย gdbserver ได้ แต่มี test case ที่แสดงบั๊กอยู่ จึงตรวจสอบและทดสอบการแก้ไขแล้ว และเขียนว่า “ขอบคุณสำหรับ patch แต่ผมอยากแก้มันด้วยวิธีที่ต่างออกไป ช่วยลอง patch ด้านล่างแล้วดูให้หน่อยได้ไหมว่าบั๊กได้รับการแก้หรือยัง?”
      https://lists.ozlabs.org/pipermail/linuxppc-dev/2022-June/24...
      ยังมีคอมเมนต์ review อื่น ๆ ที่ไม่ได้ถูกกล่าวถึงด้วย
      เนื้อหาคือไม่แน่ใจว่ามีข้อดีอะไรกับ macro ที่มีไว้สำหรับ PPC32 เท่านั้น, ควรหลีกเลี่ยง #ifdef ให้มากที่สุดเท่าที่ทำได้ และ patch ของ Michael เข้าใจง่ายกว่า
      https://lists.ozlabs.org/pipermail/linuxppc-dev/2022-June/24...
    • ผู้ดูแลไม่ได้พูดแบบนั้นจริง ๆ
      OP กำลังยัดคำพูดใส่ปากอีกฝ่ายแล้วโกรธกับมัน ซึ่งไม่ใช่กลยุทธ์ที่ดี โดยเฉพาะในการสื่อสารผ่านข้อความ
    • โดยเฉพาะถ้า OP เขียนไว้ว่า issue นี้ถูกรายงานเมื่อ 6 ปีก่อนแล้วถูกเพิกเฉย พฤติกรรมของผู้ดูแลก็ถือว่าแย่พอสมควร
    • จริง ๆ แล้วมันไม่ได้เกิดขึ้นแบบนั้นเลย
      OP ทำให้บทสนทนาดูเหมือนหยาบคาย แต่ความจริงไม่ใช่อย่างนั้น
    • ยิ่งกว่านั้น จะมีอะไรรับประกันได้ว่าคราวหน้าผู้ดูแลจะไม่พูดว่า “เวอร์ชันของฉันดีกว่า” อีก แล้วชี้ไปยังบั๊กอื่นอีก?