Snapping CUPS Printing Stack: Avahi support, system users/groups

@ondra, the adm group is needed so that a normal user (member of adm) has administrative accees. Otherwise root with root password would be required.
This is temporary until we have support for an lpadmin group.

none of sys or adm can currently be used anyway, snapd always runs all daemons as root regardless… whatever you define in your build or runtime options will be ignored anyway …

once user and groups support is implemented in snapd this will change, but until then adding adm or sys will just be a no-op (apart from breaking stuff via the fchown call) …

I tried to build with --with-system-groups=‘root’ instead of with --with-system-groups=‘sys adm root’ now (in cups/Makefile) and still get the bad system call.

well, it was worth a try at least … (did you also try leaving out the option completely ?)

those aren’t proper quotes. They’re different code-points to those expected by anything sane. You want, ' and not ‘ nor ’.

@lucyllewy, my Makefile has the correct quotes. Seems that the foum system or the browser is messing up something here.

1 Like

good good :slight_smile: regarding the bad system call, you should be able to figure out which syscall is being denied with snappy-debug - I see fchown is mentioned further up the thread; we really need to get the fix for “chown to myself” into snapd IMO.

Edit: I’ve opened a new thread regarding fchown to change ownership to the current user.

Perhaps strace the devmode snap using -e fchown following Stracing snap commands would shed some light on this. You might also try using the snapcraft preload part: https://github.com/sergiusens/snapcraft-preload

it does not seem to be in path
I just run some test and if you check scheduler core, there are fchown calls, which are not guarded by run time or compile time conditions, so it will call them no matter what --with-system-groups is set
Just running more tests here and might have something for @till.kamppeter

yeah, those fchown calls are utterly useless, one is called in log file, another one on run time directory

Rememboring on what CUPS generally does is trying to keep the permissions and ownerships of all its files (at least in /etc/ and /var) correct. Perhaps it does fchwon calls for that but I am not sure.

@till.kamppeter I did a bit of refactoring to your snapcraft.yaml I moved to autotools plugin, to make building mode clean and ability to tweak it from snapcraft.yaml You can see there also attempt to remove fchown and chmod calls. There still seems to be some offending syscalls, so you need to keep iterating to remove them. You had even chown in your own helper script run-cupsd :slight_smile: Don’t use cp -na and don’t call chmod there, none is really needed. If you want particular file permissions, set them at build time, as you are anyway just coping those files from SNAP to SNAP_DATA From here you should be able to get it confined

@ondra, thank you for your PR. I have merged it, built the snap and installed it. Now the bad system call is, according to audit message in syslog, 92, which is chown (see here).

/var/log/syslog:

Nov 14 16:02:15 virt-devel kernel: [20888.239489] audit: type=1326 audit(1510682535.462:179): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=5713 comm="cupsd" exe="/snap/cups/x13/sbin/cupsd" sig=31 arch=c000003e syscall=92 compat=0 ip=0x7feedda722c7 code=0x0
Nov 14 16:02:15 virt-devel cups.cupsd[5660]: Bad system call (core dumped)

At a minimum, please use scmp_sys_resolver for resolving syscalls since the numbers will vary depending on architecture. Eg:

$ scmp_sys_resolver 92
chown
$ scmp_sys_resolver chown
92

Better still is to use ‘snappy-debug’ which will resolve the syscall for you and suggest things. See ‘Debugging’ under Security policy and sandboxing for details.

@jdstrand, what exactly does the snapcraft preload part do?

It is an LD_PRELOAD library that helps ease snapcrafting. It specifically has something for chown: https://github.com/sergiusens/snapcraft-preload/blob/master/preload.cpp#L422

If you didn’t want all of these, you could also strip it down to just what you want. Honestly, since this is just to hold you over until the uid/gid work I mentioned is done, it might just be easier to patch out the offending lines in your source.

Tried to build with snapcraft preload, but unfortunately, its current GIT state does not build:

Preparing to build snapcraft-preload 
Building snapcraft-preload 
cmake /root/build_cups/parts/snapcraft-preload/src -DCMAKE_INSTALL_PREFIX=
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/build_cups/parts/snapcraft-preload/build
make -j4
Scanning dependencies of target snapcraft-preload32
Scanning dependencies of target snapcraft-preload
[ 25%] Building CXX object CMakeFiles/snapcraft-preload32.dir/preload.cpp.o
[ 50%] Building CXX object CMakeFiles/snapcraft-preload.dir/preload.cpp.o
In file included from /usr/include/dirent.h:25:0,
                 from /root/build_cups/parts/snapcraft-preload/src/preload.cpp:24:
/usr/include/features.h:367:25: fatal error: sys/cdefs.h: No such file or directory
compilation terminated.
CMakeFiles/snapcraft-preload32.dir/build.make:62: recipe for target 'CMakeFiles/snapcraft-preload32.dir/preload.cpp.o' failed
make[2]: *** [CMakeFiles/snapcraft-preload32.dir/preload.cpp.o] Error 1
CMakeFiles/Makefile2:104: recipe for target 'CMakeFiles/snapcraft-preload32.dir/all' failed
make[1]: *** [CMakeFiles/snapcraft-preload32.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
[ 75%] Linking CXX shared library libsnapcraft-preload.so
[ 75%] Built target snapcraft-preload
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2
Traceback (most recent call last):
  File "/usr/bin/snapcraft", line 9, in <module>
    load_entry_point('snapcraft==2.34', 'console_scripts', 'snapcraft')()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 542, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2569, in load_entry_point
    return ep.load()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2229, in load
    return self.resolve()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2235, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/usr/lib/python3/dist-packages/snapcraft/cli/__main__.py", line 19, in <module>
    run(prog_name='snapcraft')
  File "/usr/lib/python3/dist-packages/click/core.py", line 716, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/core.py", line 696, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1060, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3/dist-packages/click/core.py", line 889, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3/dist-packages/click/core.py", line 534, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/snapcraft/cli/lifecycle.py", line 132, in snap
    project_options, directory=directory, output=output)
  File "/usr/lib/python3/dist-packages/snapcraft/internal/lifecycle.py", line 349, in snap
    execute('prime', project_options)
  File "/usr/lib/python3/dist-packages/snapcraft/internal/lifecycle.py", line 130, in execute
    _Executor(config, project_options).run(step, part_names)
  File "/usr/lib/python3/dist-packages/snapcraft/internal/lifecycle.py", line 225, in run
    self._run_step(step, part, part_names)
  File "/usr/lib/python3/dist-packages/snapcraft/internal/lifecycle.py", line 262, in _run_step
    getattr(part, step)()
  File "/usr/lib/python3/dist-packages/snapcraft/internal/pluginhandler/__init__.py", line 330, in build
    self.plugin.build()
  File "/usr/lib/python3/dist-packages/snapcraft/plugins/cmake.py", line 82, in build
    self.make(env=env)
  File "/usr/lib/python3/dist-packages/snapcraft/plugins/make.py", line 107, in make
    self.run(command + ['-j{}'.format(self.parallel_build_count)], env=env)
  File "/usr/lib/python3/dist-packages/snapcraft/_baseplugin.py", line 202, in run
    return common.run(cmd, cwd=cwd, **kwargs)
  File "/usr/lib/python3/dist-packages/snapcraft/internal/common.py", line 63, in run
    subprocess.check_call(['/bin/sh', f.name] + cmd, **kwargs)
  File "/usr/lib/python3.5/subprocess.py", line 581, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['/bin/sh', '/tmp/tmplrnqj0qe', 'make', '-j4']' returned non-zero exit status 2
Stopping local:snapcraft-gently-finer-yeti
Traceback (most recent call last):
  File "/usr/bin/snapcraft", line 11, in <module>
    load_entry_point('snapcraft==2.34+17.10', 'console_scripts', 'snapcraft')()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 564, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2662, in load_entry_point
    return ep.load()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2316, in load
    return self.resolve()
  File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 2322, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/usr/lib/python3/dist-packages/snapcraft/cli/__main__.py", line 19, in <module>
    run(prog_name='snapcraft')
  File "/usr/lib/python3/dist-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/usr/lib/python3/dist-packages/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/usr/lib/python3/dist-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/lib/python3/dist-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/lib/python3/dist-packages/snapcraft/cli/lifecycle.py", line 188, in cleanbuild
    lifecycle.cleanbuild(project_options, remote)
  File "/usr/lib/python3/dist-packages/snapcraft/internal/lifecycle.py", line 326, in cleanbuild
    metadata=config.get_metadata(), remote=remote).execute()
  File "/usr/lib/python3/dist-packages/snapcraft/internal/lxd.py", line 164, in execute
    raise e
  File "/usr/lib/python3/dist-packages/snapcraft/internal/lxd.py", line 158, in execute
    self._container_run(command, cwd=self._project_folder)
  File "/usr/lib/python3/dist-packages/snapcraft/internal/lxd.py", line 113, in _container_run
    check_call(['lxc', 'exec', self._container_name, '--'] + cmd)
  File "/usr/lib/python3.6/subprocess.py", line 291, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['lxc', 'exec', 'local:snapcraft-gently-finer-yeti', '--', 'sh', '-c', 'cd /root/build_cups; snapcraft snap --output cups_0.1.0_amd64.snap']' returned non-zero exit status 1.

@till.kamppeter check my new pull request. I added you to snapcraft.yaml lines to comment all (f)chmod and (f)chown calls in cupsd. This is a bit brutal way to do things, but it does the job :slight_smile: Now if you install snap, it will run confined. There are still two denials, but those come on dbus targeted to avahi, where we need to review it and if this is genuine, we should probably update avahi-observe interface to pass this through.

audit: type=1107 audit(1510705184.258:5868): pid=1397 uid=107 auid=4294967295 ses=4294967295 msg='apparmor="DENIED" operation="dbus_method_call" bus="system" path="/" interface="org.freedesktop.DBus.Peer" member="Ping" mask="send" name="org.freedesktop.Avahi" pid=18475 label="snap.cups.cupsd" peer_pid=1413 peer_label="unconfined"

@jdstrand what do you think about this denial, shall we pass this call through?

@ondra, thank you very much. I have merged your pull request and built and installed the new snap. Now the snap’s cupsd starts and keeps running, but neither the print queues shared by the snap are discovered by the system nor the system’s queues by the snap. Seems to be problems with Avahi or D-Bus here (CUPS and cups-browsed communicate with avahi-daemon via D-Bus).

After running

sudo snap connect cups:avahi-control

and rebooting the virtual machine the auto discovery of the shared printers works again, in both directions. So after manually connecting Avahi the CUPS/Avahi/D-Bus/cups-browsed realm seems to fully work with a confined snap.

Can I reach the same goal also without rebooting the VM? How do I restart daemons within a snap?

We also need a way to connect the Avahi interface automatically.