Chronyd snap is unable to set time on system clock

Hi,

I’m creating snap for chrony 3.5.1.
I have successfully created snap in “devmode” and is working fine.
While switching from “Devmode” to “strict” mode it’s quite difficult.

Actually, Snap building in “strict” mode is done.
While installing it, I’m facing permission regarding time adjustment.

snapcraft.yaml is look like:

name: chronyd # you probably want to 'snapcraft register ’
base: core18 # the base snap is the execution environment for this snap
version: ‘3.5.1’ # just for humans, typically ‘1.2+git’ or ‘1.3.2’
summary: chronyd snap # 79 char long summary
description: |
Learning snapping with chronyd.

grade: stable # must be ‘stable’ to release into candidate/stable channels
confinement: strict # use ‘strict’ once you have the right plugs and slots

apps:

chronyd:
command: bin/chronyd -f $SNAP_DATA/etc/chrony.conf
daemon: forking
restart-condition: always
plugs:
- network
- network-bind
- time-control
- timeserver-control
- timezone-control

chronyc:
command: bin/chronyc

parts:
chronyd-defaults:
plugin: dump
source: conf
organize:
chrony.conf: etc/chrony.conf

chronyd:
source: https://download.tuxfamily.org/chrony/chrony-3.5.1.tar.gz
plugin: autotools
build-packages: [ asciidoctor ]
organize:
usr/local/sbin/chronyd: bin/chronyd
usr/local/bin/chronyc: bin/chronyc

snap version :

snap 2.48.2
snapd 2.48.2
series 16
ubuntu 18.04
kernel 5.4.0-58-generic

snapcraft version:

snapcraft, version 4.4.4

While installing in strict mode below error :

error: cannot perform the following tasks:

  • Start snap “chronyd” (unset) services ([start snap.chronyd.chronyd.service] failed with exit status 1: Job for snap.chronyd.chronyd.service failed because the control process exited with error code.
    See “systemctl status snap.chronyd.chronyd.service” and “journalctl -xe” for details.
    )

Journalctl -xe command o/p:

– Unit snap.chronyd.chronyd.service has begun starting up.
Jan 11 11:21:48 User chronyd[15042]: chronyd version 3.5.1 starting (+CMDMON +NTP +REFCLOCK +RTC -PRIVDROP -SCFILTER -SIGND +ASYNCDNS -SECHASH +IPV6 -DEBUG)
Jan 11 11:21:48 User kernel: kauditd_printk_skb: 2 callbacks suppressed
Jan 11 11:21:48 User kernel: audit: type=1326 audit(1610344308.783:1237): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=15042 comm=“chronyd” exe="/snap/chronyd/x1/bin/chronyd" sig=0 arch=c000003e sysc
Jan 11 11:21:48 User audit[15042]: SECCOMP auid=4294967295 uid=0 gid=0 ses=4294967295 pid=15042 comm=“chronyd” exe="/snap/chronyd/x1/bin/chronyd" sig=0 arch=c000003e syscall=159 compat=0 ip=0x7fc220709
Jan 11 11:21:48 User systemd[1]: snap.chronyd.chronyd.service: Control process exited, code=exited status=1
Jan 11 11:21:48 User chronyd.chronyd[15018]: adjtimex(0x8001) failed : Operation not permitted
Jan 11 11:21:48 User chronyd[15042]: Wrong permissions on /var/snap/chronyd/current/run
Jan 11 11:21:48 User systemd[1]: snap.chronyd.chronyd.service: Failed with result ‘exit-code’.
Jan 11 11:21:48 User chronyd[15042]: Disabled command socket /var/snap/chronyd/current/run/chrony.sock
Jan 11 11:21:48 User systemd[1]: Failed to start Service for snap application chronyd.chronyd.
– Subject: Unit snap.chronyd.chronyd.service has failed
– Defined-By: systemd
– Support: http://www.ubuntu.com/support

– Unit snap.chronyd.chronyd.service has failed.

– The result is RESULT.
Jan 11 11:21:48 User chronyd[15042]: Fatal error : adjtimex(0x8001) failed : Operation not permitted
Jan 11 11:21:48 User systemd[1]: Stopped Service for snap application chronyd.chronyd.
– Subject: Unit snap.chronyd.chronyd.service has finished shutting down
– Defined-By: systemd
– Support: http://www.ubuntu.com/support

It seems like chronyd service tries to adjust time on system clock but as strict confined snap doesn’t have permission.

snappy-debug.security scanlog o/p:

User@User:~/User/Chrony$ snappy-debug.security scanlog
INFO: Following ‘/var/log/syslog’. If have dropped messages, use:
INFO: $ sudo journalctl --output=short --follow --all | sudo snappy-debug
= Seccomp =
Time: Jan 11 11:45:43
Log: auid=4294967295 uid=0 gid=0 ses=4294967295 pid=15981 comm=“chronyd” exe="/snap/chronyd/x1/bin/chronyd" sig=0 arch=c000003e 159(adjtimex) compat=0 ip=0x7fa930a7bf57 code=0x50000
Syscall: adjtimex
Suggestion:

  • add ‘time-control’ to ‘plugs’

Scanlog is showing, need to add ‘time-control’ plugs.But i have already added it in snapcraft.yaml.

Any suggestion and help is appreciated.
Thanks in advance.

@ogra
I have seen you have helped many people in this forum.
Please guide me if you have any suggestion.

Thanks

Did you connect the time-control interface (it is not automatically connected)? Eg snap connect chronyd:time-control. You can check with snap connections chronyd.

@jdstrand

Thanks for reply… I’m eagerly waiting reply.
Actually, to connect with time-control interface it should be installed right?

But at the time of installation, it’s failing.
And throwing errors via ‘journalctl -xe’, which I have already mentioned.

Is it possible to auto-connect time-control at the time of installation?

It is not possible to connect at the time of installation at this time. If the service fails to start then the snap will fail to install. You can solve this in a number of ways. Some people will temporarily remove daemon: ... from the snap.yaml for the command (in your case, chronyd) which turns the service into a command and allow the snap to install, then after the interfaces are connected can run the command under sudo. Others choose to create a small wrapper and use snapctl is-connected <interface> (for you, snapctl is-connected time-control) and conditionally start the daemon if the interfaces are setup.

Thanks, @jdstrand I am trying to connect the time-control plug via a shell script within the same snap.
But here the problem is snap connect command get failed to execute with the failure reason: "permission denied"
Any help is really appreciated!

If I understand you correctly, a snap is not allowed to connect its own interfaces. If the snap is already in the store, you might request an auto-connection for this snap. Auto-connecting time-control for chronyd seems like a reasonable request.

1 Like

Thanks @jdstrand, Snap is not on the public store, it gets uploaded to the local brand store later.
It is under development for testing when I change the confinement to devmode it worked but once I change the confinement level to strict, it starts behaving like a stranger and it was due to time-control plug.
For a workaround, I have created a wrapper that will connect this plug before the execution of a chronyd daemon.

The wrapper contains a command “snap connect plug:slot” and it gets triggered during the snap installation and before the chronyd daemon.

But here the problem is “snap connect” command getting failed with the error “permission denied”

What should i do to execute a "snap connect/list " like a command from a shell script in snap env like as snapctl ?

Any pointer or doc is really very helpful.

you should have received a doc with your brand store that points to a way to get autoconnections granted via a store support request …

also, if you plan to pre-install chronyd in your image anyway, you can always use the gadget.yaml in your gadget snap to define auto-connections that get applied on first boot of the image …

Thank You @ogra, i got your point but currently everything are in under development.
I need to test my snap locally and i don’t have a gadget snap source for the latest SBC.

Any workaround for now?

The one which was suggested by @jdstrand earlier in this post is to make chronyd daemon as a command and execute it manually, which was working as expected.

But I need to automate this part also, here my thought is to make a shell script wrapper that will get triggered like a post-refresh hook, but this time it gets triggered pre-install of a snap.

During the implementation of this idea, I am unable to execute snap connect command from the wrapper script, it says permission denied to execute snap connect cmd from the script .

My question is how much this is feasible to implement? or you may correct my understaing here.

I appreciate your help!

-Suvhm

a snap can indeed not call snap connect unless it uses the snapd REST API via the snapd-control interface (for which you would also need to file a support request to the store team to get it granted, so it boils down to the same thing) …

as a hackish workaround you could manually put a systemd service into /etc/systemd/system and have it execute a script that calls snap connect indeed …

beyond this there are only three “legal” ways to do snap connections:

  • using snapd-control from some agent snap that does your device management (requires a support request to get snapd-control granted)
  • using a connections: entry from gadget.yaml
  • getting a snap store declaration in place via a support request

while the hack might help out for a quick test, you will anyway have to use one of the three methods in the end though .(i personally would just file a support request to get the time-control auto-connection granted for the snap)…

As always I am very thankful @ogra for your prompt reply and for clearing my basic :slight_smile:
I got your point here, for workaround also I need to connect the snapd-control interface, which also needs to be approved by the store team.

Anything are possible only when the snap gets uploaded to either a global/local brand store or access to a gadget snap.

-Suvhm

Workaround I followed for testing is,

  • I disabled all services in install hook, so as soon as snap service gets installed it gets disabled.

  • After installation gets complete, I manually connect all the interfaces

  • Enable all service using “snap enable start .”

you can do the starting from interface connection hooks instead and use the newly added install-mode: disable in your snapcraft.yaml for the daemon to have it come up disabled at install time …

here is an example of such a hook (it automatically starts the service if the interface gets connected):

if you have multiple connections to check it gets a little more complex scripting wise as you need to cross check the other interfaces from each hook, take a look at the three hooks in:

how that can work