Public bug reported:

apport decides whether a crash report has already been shown to the user only 
by comparing timestamps:                                                        
                                                                        
                                                                                
                                                                                
                                                                      
    # apport/fileutils.py                                                       
                                                                                
                                                                      
    def seen_report(report):                                                    
                                                                                
                                                                      
        st = os.stat(report)                                                    
                                                                                
                                                                      
        return (st.st_atime > st.st_mtime) or (st.st_size == 0)                 
                                                                                
                                                                      
                                                                                
                                                                                
                                                                      
On a relatime filesystem (the Ubuntu default), the first read of a freshly 
written file by                                                                 
                                                                           
*any* process sets atime > mtime. So any program that reads new files in 
/var/crash marks every                                                          
                                                                             
report as "seen" before the user is asked: antivirus/EDR agents, backup tools, 
file indexers,                                                                  
                                                                       
audit tools, or an admin running `head`. The crash dialog then never appears, 
and nothing is                                                                  
                                                                        
logged. Crash reporting is disabled without anyone noticing.                    
                                                                                
                                                                      
                                                                                
                                                                                
                                                                      
On the affected machine, a third-party security agent scans every new file. As 
a result the crash                                                              
                                                                       
dialog never appeared, although reports kept accumulating in /var/crash.        
                                                                                
                                                                      
                                                                                
                                                                                
                                                                      
### Evidence (bpftrace on openat of /var/crash/*, times relative to the crash)  
                                                                                
                                                                      
    t+0 ms     apport creates the report for a crashed coreutils binary         
                                                                                
                                                                      
    t+980 ms   report fully written (mtime)                                     
                                                                                
                                                                      
    t+1211 ms  root-owned security-agent process opens it O_RDONLY              
                                                                                
                                                                      
               -> atime of the report is now later than mtime -> "seen"         
                                                                                
                                                                      
                                                                                
                                                                                
                                                                      
User journal for the same crash:                                                
                                                                                
                                                                      
                                                                                
                                                                                
                                                                      
    update-notifier-crash: yes        <- apport-checkreports ran before the 
scan: report is new                                                             
                                                                          
    (apport-gtk starts, run_crashes() -> get_new_reports() returns nothing, 
exits 0, no dialog)                                                             
                                                                          
                                                                                
                                                                                
                                                                      
### Minimal reproducer (no third-party software needed)                         
                                                                                
                                                                      
    import os, shutil, apport.fileutils as fu                                   
                                                                                
                                                                      
    src = "/var/crash/<any existing>.crash"; dst = 
"/var/crash/_atime_demo.1000.crash"                                             
                                                                                
                   
    shutil.copyfile(src, dst)                       # a fresh report            
                                                                                
                                                                      
    print(fu.seen_report(dst), dst in fu.get_new_reports())   # False True      
                                                                                
                                                                      
    open(dst, "rb").read(1)                         # one byte, by any process  
                                                                                
                                                                      
    print(fu.seen_report(dst), dst in fu.get_new_reports())   # True False      
                                                                                
                                                                      
    os.unlink(dst)                                                              
                                                                                
                                                                      
                                                                                
                                                                                
                                                                      
Output on 26.04.1 (apport 2.34.1-0ubuntu0.1):                                   
                                                                                
                                                                      
                                                                                
                                                                                
                                                                      
    before read: seen=False in get_new_reports=True                             
                                                                                
                                                                      
    after 1-byte read: seen=True in get_new_reports=False   (38.5 ms total)     
                                                                                
                                                                      
                                                                                
                                                                                
                                                                      
End to end: crash any packaged program while something reads new files in 
/var/crash.                                                                     
                                                                            
update-notifier-crash.path fires, apport-checkreports may still see the report 
as new, but by                                                                  
                                                                       
the time apport-gtk calls get_new_reports() it is "seen", so no dialog is 
shown. Opening the same                                                         
                                                                            
report explicitly with `apport-gtk -c <file>` works, which shows the report 
itself is fine.                                                                 
                                                                          
                                                                                
                                                                                
                                                                      
### Expected                                                                    
                                                                                
                                                                      
The "already presented to the user" state should not depend on whether some 
unrelated process has                                                           
                                                                          
read the file. For example, apport could record it explicitly when the UI 
presents a report (a                                                            
                                                                            
`.seen` stamp or an xattr, like the existing `.upload`/`.uploaded` stamps), 
instead of inferring it                                                         
                                                                          
from atime. That would also fix the noatime case from bug #85809.    

                                                                     
### Environment                                                                 
                                                                                
                                                                      
- Ubuntu 26.04.1 LTS, kernel 7.0.0-34-generic, root filesystem mounted 
`relatime` (default)                                                            
                                                                               
- apport / apport-gtk 2.34.1-0ubuntu0.1, update-notifier 3.207.2                
                                                                                
                                                                      
- Crash path: systemd-coredump → apport-coredump-hook → apport 
--from-systemd-coredump                                                         
                                                                                
       
- KDE Plasma 6.6.6 (update-notifier-crash.path user unit active; 
update-notifier autostart has NotShowIn=KDE)                                    
                                                                                
     
- Real-world trigger: a security agent that scans newly created files; the 
reproducer above needs no third-party software

** Affects: apport (Ubuntu)
     Importance: Undecided
         Status: New

** Affects: update-notifier (Ubuntu)
     Importance: Undecided
         Status: New

** Attachment added: "apport-atime-demo.py"
   
https://bugs.launchpad.net/bugs/2169793/+attachment/6006667/+files/apport-atime-demo.py

** Also affects: update-notifier (Ubuntu)
   Importance: Undecided
       Status: New

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2169793

Title:
  Crash dialogs silently never appear when another process reads new
  reports in /var/crash (seen_report() relies on atime)

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/apport/+bug/2169793/+subscriptions


-- 
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to