Skip to content

Commit

Permalink
SUIDPermissionsCheck: support new /usr/share/permissions/packages.d dir
Browse files Browse the repository at this point in the history
- use common constant to refer to /usr/share/permissions
- adjust comments to current situation
- consider the new packages.d directory as well (new chkstat from
  permissions package supports this).

Due to the generator used in `_paths_to()` this is getting a bit ugly to
combine now. We should only consider `packages.d` in the /usr dir, not
in /etc, where the name is too generic.
  • Loading branch information
mgerstner committed Feb 13, 2024
1 parent 4a699fe commit e7886eb
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 12 deletions.
3 changes: 2 additions & 1 deletion configs/openSUSE/security.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ Locations = [
FollowSymlinks = false
Locations = [
"/etc/permissions.d/",
"/usr/share/permissions/permissions.d/"
"/usr/share/permissions/permissions.d/",
"/usr/share/permissions/packages.d/"
]

[FileDigestLocation.pam]
Expand Down
28 changes: 17 additions & 11 deletions rpmlint/checks/SUIDPermissionsCheck.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import itertools
import os
import stat

import rpm
from rpmlint.checks.AbstractCheck import AbstractCheck
from rpmlint.permissions import PermissionsParser, VariablesHandler

SHARE_DIR = '/usr/share/permissions'

class SUIDPermissionsCheck(AbstractCheck):
def __init__(self, config, output):
super().__init__(config, output)
self.perms = {}

self.var_handler = VariablesHandler('/usr/share/permissions/variables.conf')
self.var_handler = VariablesHandler(f'{SHARE_DIR}/variables.conf')

for fname in self._paths_to('permissions', 'permissions.secure'):
if not os.path.exists(fname):
Expand Down Expand Up @@ -100,38 +102,42 @@ def _paths_to(*file_names):
# return the new path first.
# chkstat prefers the new paths over the old ones, so callers that only care about the
# first matching file must mimic that.
yield '/usr/share/permissions/' + name
yield '/etc/' + name
yield f'{SHARE_DIR}/{name}'
yield f'/etc/{name}'

def check(self, pkg):
if pkg.is_source:
return

permfiles = set()
# first pass, find and parse permissions.d files
# first pass, find and parse per-package drop-in files
for f in pkg.files.keys():
for prefix in self._paths_to('permissions.d/'):
for prefix in itertools.chain(
self._paths_to('permissions.d/'),
(lambda: (yield f'{SHARE_DIR}/packages.d/'))()):
if f.startswith(prefix):
if f in pkg.ghost_files:
continue

dropin_dir = prefix.rstrip('/').split('/')[-1]

# Attention: We require the FileDigestLocation config to
# mark all permissions.d paths as "blacklisted" paths.
# mark all packages.d paths as "blacklisted" paths.
# e.g. [FileDigestLocation.permissions] with Locations
# /etc/permissions.d/ and /usr/share/permissions/permissions.d/
# This ensures that an file-unauthorized error is thrown when a permissions.d
# package is not whitelisted.
# This ensures that an file-unauthorized error is thrown when an
# entry is not whitelisted.
#
# To whitelist a permissions.d file after a successful review,
# To whitelist a drop-in file after a successful review,
# the path and its digest need to be added as FileDigestCheck config
# having respective FileDigestLocation type (e.g.
# "permissions").
#
# Here we add *all* files in a package's permissions.d directory to our
# Here we add *all* files a package has in a dropin.d directory to our
# valid permissions files *without* checking if they belong
# to a whitelist as we assume it will be checked by
# FileDigestCheck and FileDigestLocation.
bn = 'permissions.d/' + f[len(prefix):].split('.')[0]
bn = f'{dropin_dir}/' + f[len(prefix):].split('.')[0]
if bn not in permfiles:
permfiles.add(bn)

Expand Down

0 comments on commit e7886eb

Please sign in to comment.