From 8664c27096b5cac35e46f40f7fb2b0e81053a3ab Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 21 May 2024 21:52:21 +0200 Subject: [PATCH] confd: Add support for running user scripts Add a new service that, when enabled, will execute run-parts on `/cfg/user-scripts.d`. This strikes a balance between two conflicting objectives: 1. There should be no implicit way to schedule arbitrary code execution on the device, i.e. no default run-parts directory. 2. It is very useful to have a way of scheduling arbitrary code execution on the device, e.g. being able to install a debug script on a production image. With this feature, we still meet (1), since the feature has to be explicitly enabled in the startup-config; but we also fulfill (2), since we can easily enable it when needed. --- doc/ChangeLog.md | 2 ++ .../etc/finit.d/available/user-scripts.conf | 1 + src/confd/bin/bootstrap | 2 +- src/confd/src/infix-services.c | 20 ++++++++++++++++++- ...08.yang => infix-services@2024-05-21.yang} | 17 ++++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 package/skeleton-init-finit/skeleton/etc/finit.d/available/user-scripts.conf rename src/confd/yang/{infix-services@2024-04-08.yang => infix-services@2024-05-21.yang} (76%) diff --git a/doc/ChangeLog.md b/doc/ChangeLog.md index 35785726..64bd9b58 100644 --- a/doc/ChangeLog.md +++ b/doc/ChangeLog.md @@ -22,6 +22,8 @@ All notable changes to the project are documented in this file. - Update documentation for use of VETH pairs in containers - Issue #454: create bridges in `factory-config` with IGMP/MLD snooping enabled by default +- Add support for optionally running user scripts from + `/cfg/user-scripts.d` ### Fixes - Add missing LICENSE hash for factory reset tool diff --git a/package/skeleton-init-finit/skeleton/etc/finit.d/available/user-scripts.conf b/package/skeleton-init-finit/skeleton/etc/finit.d/available/user-scripts.conf new file mode 100644 index 00000000..33ebfc10 --- /dev/null +++ b/package/skeleton-init-finit/skeleton/etc/finit.d/available/user-scripts.conf @@ -0,0 +1 @@ +task [2] run-parts /cfg/user-scripts.d -- Running user startup scripts diff --git a/src/confd/bin/bootstrap b/src/confd/bin/bootstrap index 3aa453b5..97253756 100755 --- a/src/confd/bin/bootstrap +++ b/src/confd/bin/bootstrap @@ -226,7 +226,7 @@ sysrepoctl -s $SEARCH \ -i infix-dhcp-client@2024-04-12.yang -g wheel -p 0660 \ -i infix-shell-type@2023-08-21.yang -g wheel -p 0660 \ -i infix-system@2024-04-12.yang -g wheel -p 0660 \ - -i infix-services@2024-04-08.yang -g wheel -p 0660 \ + -i infix-services@2024-05-21.yang -g wheel -p 0660 \ -i ieee802-ethernet-interface@2019-06-21.yang -g wheel -p 0660 \ -i infix-ethernet-interface@2024-02-27.yang -g wheel -p 0660 \ -I "${INIT_DATA}" diff --git a/src/confd/src/infix-services.c b/src/confd/src/infix-services.c index 70ff6039..daedd412 100644 --- a/src/confd/src/infix-services.c +++ b/src/confd/src/infix-services.c @@ -25,6 +25,7 @@ SVC(web) \ SVC(ttyd) \ SVC(netbrowse) \ + SVC(userscripts) \ SVC(all) /* must be last entry */ typedef enum { @@ -52,7 +53,7 @@ struct mdns_svc { }; static const struct srx_module_requirement reqs[] = { - { .dir = YANG_PATH_, .name = "infix-services", .rev = "2024-04-08" }, + { .dir = YANG_PATH_, .name = "infix-services", .rev = "2024-05-21" }, { .dir = YANG_PATH_, .name = "ieee802-dot1ab-lldp", .rev = "2022-03-15" }, { .dir = YANG_PATH_, .name = "infix-lldp", .rev = "2023-08-23" }, { NULL } @@ -291,6 +292,21 @@ static int web_change(sr_session_ctx_t *session, uint32_t sub_id, const char *mo return put(cfg, srv); } +static int userscripts_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module, + const char *xpath, sr_event_t event, unsigned request_id, void *_confd) +{ + struct lyd_node *srv = NULL; + sr_data_t *cfg; + + cfg = get(session, event, xpath, &srv, "user-scripts", NULL); + if (!cfg) + return SR_ERR_OK; + + svc_enadis(lydx_is_enabled(srv, "enabled"), none, "user-scripts"); + + return put(cfg, srv); +} + int infix_services_init(struct confd *confd) { int rc; @@ -312,6 +328,8 @@ int infix_services_init(struct confd *confd) 0, netbrowse_change, confd, &confd->sub); REGISTER_CHANGE(confd->session, "ieee802-dot1ab-lldp", "/ieee802-dot1ab-lldp:lldp", 0, lldp_change, confd, &confd->sub); + REGISTER_CHANGE(confd->session, "infix-services", "/infix-services:user-scripts", + 0, userscripts_change, confd, &confd->sub); return SR_ERR_OK; fail: diff --git a/src/confd/yang/infix-services@2024-04-08.yang b/src/confd/yang/infix-services@2024-05-21.yang similarity index 76% rename from src/confd/yang/infix-services@2024-04-08.yang rename to src/confd/yang/infix-services@2024-05-21.yang index feec64f6..8a475333 100644 --- a/src/confd/yang/infix-services@2024-04-08.yang +++ b/src/confd/yang/infix-services@2024-05-21.yang @@ -7,6 +7,10 @@ module infix-services { contact "kernelkit@googlegroups.com"; description "Infix services, generic."; + revision 2024-05-21 { + description "Add support for user-scripts."; + reference "internal"; + } revision 2024-04-08 { description "Initial support for web services."; reference "internal"; @@ -33,6 +37,19 @@ module infix-services { } } + container user-scripts { + description "Run scripts in /cfg/user-scripts.d on system startup + + CAUTION! Anyone who can write to this directory will be able to + install a permanent backdoor on the system. This could include + a remote attacker with brief window of access."; + + leaf enabled { + description "Enable or disable user script execution"; + type boolean; + } + } + container web { description "Web services";