Though lintian call: error: troff: Segmentation fault

Bug #2055402 reported by Alexandre Esse
16
This bug affects 2 people
Affects Status Importance Assigned to Milestone
groff (Ubuntu)
Fix Released
High
Colin Watson
lintian (Ubuntu)
Confirmed
Undecided
Unassigned

Bug Description

groff crash when redirecting output to a file

% man --warnings -E UTF-8 -l -Tutf8 -Z /usr/share/man/man1/cat.1.gz >output
troff:<standard input>:3: fatal error: unable to flush output file: Permission denied
groff: error: troff: Segmentation fault (core dumped)
man: command exited with status 2: /usr/libexec/man-db/zsoelim | /usr/libexec/man-db/manconv -f UTF-8:ISO-8859-1 -t UTF-8//IGNORE | preconv -e UTF-8 | tbl | groff -mandoc -Z -rLL=78n -rLT=78n -wmac -Tutf8

This is typically triggered by lintian when scanning man pages

Alexandre Esse (ahresse)
description: updated
information type: Private Security → Public
Loïc Minier (lool)
no longer affects: lintian (Ubuntu)
no longer affects: ubuntu
Changed in groff (Ubuntu):
status: New → Confirmed
Alexandre Esse (ahresse)
description: updated
Loïc Minier (lool)
description: updated
Revision history for this message
Loïc Minier (lool) wrote :

This is due to the apparmor profile and the man pipeline trying to flush and stat the output file which can be anywhere in the fs

[Thu Feb 29 11:23:53 2024] audit: type=1400 audit(1709205849.791:651): apparmor="DENIED" operation="file_inherit" class="file" namespace="root//lxd-daily_<var-snap-lxd-common-lxd>" profile="man_groff" name="/tmp/output" pid=97274 comm="troff" requested_mask="w" denied_mask="w" fsuid=1001000 ouid=1001000
[Thu Feb 29 11:23:53 2024] audit: type=1400 audit(1709205849.819:652): apparmor="DENIED" operation="getattr" class="file" info="Failed name lookup - disconnected path" error=-13 namespace="root//lxd-daily_<var-snap-lxd-common-lxd>" profile="/usr/bin/man" name="apparmor/.null" pid=97274 comm="troff" requested_mask="r" denied_mask="r" fsuid=1001000 ouid=0
[Thu Feb 29 11:23:53 2024] audit: type=1400 audit(1709205849.819:653): apparmor="DENIED" operation="getattr" class="file" info="Failed name lookup - disconnected path" error=-13 namespace="root//lxd-daily_<var-snap-lxd-common-lxd>" profile="man_groff" name="apparmor/.null" pid=97274 comm="troff" requested_mask="r" denied_mask="r" fsuid=1001000 ouid=0

description: updated
Revision history for this message
Loïc Minier (lool) wrote :

I'm not sure how to properly fix this, we allow the shell to write anywhere, then file_inherit is triggered because we don't want man to write anywhere, which seems to be what we typically want to achieve with the apparmor profile.

Should we teach lintian and perhaps every other tool to use a specific directory?

Revision history for this message
Alexandre Erwin Ittner (aittner) wrote :

I got the same issue days ago when debugging a package in s390x, so it is not architecture-specific.

ubuntu@devnoble1:~/libica-noble/libica-4.3.0$ lintian -I --pedantic --tag-display-limit 0
W: libica-utils: groff-message command exited with status 2: /usr/libexec/man-db/zsoelim | /usr/libexec/man-db/manconv -f UTF-8:ISO-8859-1 -t UTF-8//IGNORE | preconv -e UTF-8 | groff -mandoc -Z -rLL=117n -rLT=117n -wmac -Tutf8 [usr/share/man/man1/icainfo-cex.1.gz:2]
W: libica-utils: groff-message command exited with status 2: /usr/libexec/man-db/zsoelim | /usr/libexec/man-db/manconv -f UTF-8:ISO-8859-1 -t UTF-8//IGNORE | preconv -e UTF-8 | groff -mandoc -Z -rLL=117n -rLT=117n -wmac -Tutf8 [usr/share/man/man1/icainfo.1.gz:2]
W: libica-utils: groff-message command exited with status 2: /usr/libexec/man-db/zsoelim | /usr/libexec/man-db/manconv -f UTF-8:ISO-8859-1 -t UTF-8//IGNORE | preconv -e UTF-8 | groff -mandoc -Z -rLL=117n -rLT=117n -wmac -Tutf8 [usr/share/man/man1/icastats.1.gz:2]
W: libica-utils: groff-message error: troff: Segmentation fault (core dumped) [usr/share/man/man1/icainfo-cex.1.gz:1]
W: libica-utils: groff-message error: troff: Segmentation fault (core dumped) [usr/share/man/man1/icainfo.1.gz:1]
W: libica-utils: groff-message error: troff: Segmentation fault (core dumped) [usr/share/man/man1/icastats.1.gz:1]
I: libica4: hardening-no-bindnow [usr/lib/s390x-linux-gnu/libica-cex.so.4.3.0]
I: libica4: hardening-no-bindnow [usr/lib/s390x-linux-gnu/libica.so.4.3.0]
I: libica4: symbols-file-missing-build-depends-package-field libica-cex.so.4 [symbols]
I: libica4: symbols-file-missing-build-depends-package-field libica.so.4 [symbols]
I: libica-utils: typo-in-manual-page paramater parameter [usr/share/man/man1/icastats.1.gz:76]
I: libica-utils: typo-in-manual-page sucessful successful [usr/share/man/man1/icastats.1.gz:126]
P: libica source: silent-on-rules-requiring-root [debian/control]
ubuntu@devnoble1:~/libica-noble/libica-4.3.0$

The apparmor profile issue was a nice catch, I was getting some trouble to reproduce it in a minimal fashion, but that was because I was leaving the pipeline just output to stdout.

Should we patch lintian to only write this to /tmp ?

Revision history for this message
Seth Arnold (seth-arnold) wrote :

Loïc, it's possible the 'fix' (really a work-around) is to add `flags=(attach_disconnected)` to the profile in question. (I'm guessing that would be enough to prevent AppArmor from replacing the file.)

In your logs it looks like it's already trying to use /tmp/output. This might be unsafe, depending upon the specific sequence of systemcalls used and the settings of:

/proc/sys/fs/protected_fifos
/proc/sys/fs/protected_hardlinks
/proc/sys/fs/protected_regular
/proc/sys/fs/protected_symlinks

Thanks

Revision history for this message
John Johansen (jjohansen) wrote :

So the answer, is most likely not great atm.

Option 1: unconfined
If you are coming from an unconfined bash/lintian then object delegation will take care of this for you (more on that below). However since you are seeing file_inherit messages that isn't the case. And you would need to change confinement such that bash/lintian is unconfined for this option to work atm.

Option 2: confined
In this case you are currently limited to AppArmor acting as an ambient authority system, which basic means every confinement domain (profile) needs to enumerate all available accesses.

As proposed by Loïc in comment #2 if you don't want to give man read access to the entire system you need to teach lintian to write to a specific location that is shared by both profiles.

We do have 2 improvements that are in progress that are NOT currently available, but we should start planning for them from an interface perspective for snap. Both of the following features will require a new apparmor userspace (not a problem as snap vendors apparmor) and a newer kernel.

I. Controlled Object Delegation (hopefully 24.10 time frame)
this is available today, via unconfined. Unconfined allows delegating its objects to any confined application. Unfortunately this currently is not available to confined applications.

With controlled delegation, you add a rule to the source's profile (eg. lintian) that specifies which files open (fd objects) can be delegated to who (target profile eg. man). The target profile (man)
will the access that descriptor under the source's (lintian's) authority. If a target tries to pass the descriptor off via SCM/dbus etc or inheritance, the descriptor will get revalidated against the new target, and denied if there isn't a rule allowing it in the original source (lintian).

II. object labeling - again not available today, nor as good a fit for this situation. It is also further out than object delegation from landing.

- this solution limits target location fstype
- this solution only works if the source is creating or modifying the file or the files type, and may cause revocation of the file to other applications, even if not sharing a file descriptor
- requires rules in both profiles, however they can be more abstract (even excluding location entirely) than the solution required today.

The source (lintian/bash) marks the file being passed by setting its object label. The target (man) must have access to the object type that the file is tagged with via a rule in its profile. The object can then be passed/inherited and the inheritance check will let it through.

Revision history for this message
Loïc Minier (lool) wrote :

@Seth: I was only using /tmp/output to not write to the current dir; the typical case is lintian creating a safe tmpdir.

Changed in lintian (Ubuntu):
status: New → Confirmed
no longer affects: groff (Ubuntu)
Revision history for this message
Loïc Minier (lool) wrote :

Thanks John!

I've changed the bug tasks back to lintian as it sounds like the most reasonable short-term option would be to patch lintian to pick a predictable directory and update the apparmor profiles; later, we will have new apparmor to deal with this situation more elegantly

Revision history for this message
Colin Watson (cjwatson) wrote :

I would like to add a small correction here regarding the intent of man-db's AppArmor policy. The intent is _not_ to confine where the man program itself can write, as is noted in the policy itself:

  # Allow basically anything in terms of file system access, subject to DAC.
  # The purpose of this profile isn't to confine man itself (that might be
  # nice in the future, but is tricky since it's quite configurable), but to
  # confine the processes it calls that parse untrusted data.
  /** mrixwlk,

However, the man_groff sub-profile is more constrained, and that's used for the groff-related subprocesses that man forks. That's what's triggering denials here.

In some ways I wonder if that means that the problem is a leaky abstraction of sorts. We're trying to confine man's groff-related subprocesses, but we pass through FDs to them. One possibility might be to have groff write to a pipe instead in this situation and stream it through man to the output file. Slightly less efficient, but it might not be too unreasonable.

Revision history for this message
Colin Watson (cjwatson) wrote :

Adding a groff task to fix the segfault even in the face of whatever we decide to do about the profile (see https://savannah.gnu.org/bugs/index.php?65427).

Changed in groff (Ubuntu):
importance: Undecided → High
assignee: nobody → Colin Watson (cjwatson)
status: New → In Progress
Colin Watson (cjwatson)
Changed in groff (Ubuntu):
status: In Progress → Fix Committed
Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package groff - 1.23.0-5

---------------
groff (1.23.0-5) unstable; urgency=medium

  * Guard putc/fputc calls with a null pointer check (LP: #2055402).
  * tmac/s.tmac: Stop treating excess arguments as erroneous.

 -- Colin Watson <email address hidden> Thu, 04 Jul 2024 08:52:43 +0100

Changed in groff (Ubuntu):
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.