The existing code failed to set the uci cursor save directory to the current
session path, causing the apply routine to either fail or to merge settings
from unrelated neighboring sessions, potentially leaking data.
Solve the issue by switching the uci cursor save directory to the session
directory before performing the actual apply actions.
Additionally set the save directory path to "/dev/null" during rollback, to
avoid merging unrelated system wide uci changes when restoring configs from
the snapshot directory.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
+static int
+rpc_uci_apply_access(const char *sid, glob_t *gl)
+{
+ struct stat s;
+ int i, c = 0;
+
+ if (gl->gl_pathc < 3)
+ return UBUS_STATUS_NO_DATA;
+
+ for (i = 0; i < gl->gl_pathc; i++) {
+ char *config = basename(gl->gl_pathv[i]);
+
+ if (*config == '.')
+ continue;
+ if (stat(gl->gl_pathv[i], &s) || !s.st_size)
+ continue;
+ if (!rpc_session_access(sid, "uci", config, "write"))
+ return UBUS_STATUS_PERMISSION_DENIED;
+ c++;
+ }
+
+ if (!c)
+ return UBUS_STATUS_NO_DATA;
+
+ return 0;
+}
+
-rpc_uci_do_rollback(struct ubus_context *ctx, const char *sid, glob_t *gl)
+rpc_uci_do_rollback(struct ubus_context *ctx, glob_t *gl)
- if (sid) {
- snprintf(tmp, sizeof(tmp), RPC_UCI_SAVEDIR_PREFIX "%s/", sid);
+ /* Test apply permission to see if the initiator session still exists.
+ * If it does, restore the delta files as well, else just restore the
+ * main configuration files. */
+ deny = apply_sid[0]
+ ? rpc_uci_apply_access(apply_sid, gl) : UBUS_STATUS_NOT_FOUND;
+
+ if (!deny) {
+ snprintf(tmp, sizeof(tmp), RPC_UCI_SAVEDIR_PREFIX "%s/", apply_sid);
+ /* avoid merging unrelated uci changes when restoring old configs */
+ rpc_uci_replace_savedir("/dev/null");
+
for (i = 0; i < gl->gl_pathc; i++) {
char *config = basename(gl->gl_pathv[i]);
for (i = 0; i < gl->gl_pathc; i++) {
char *config = basename(gl->gl_pathv[i]);
rpc_uci_copy_file(RPC_SNAPSHOT_FILES, RPC_UCI_DIR, config);
rpc_uci_apply_config(ctx, config);
rpc_uci_copy_file(RPC_SNAPSHOT_FILES, RPC_UCI_DIR, config);
rpc_uci_apply_config(ctx, config);
- if (sid)
- rpc_uci_copy_file(RPC_SNAPSHOT_DELTA, tmp, config);
+
+ if (deny)
+ continue;
+
+ rpc_uci_copy_file(RPC_SNAPSHOT_DELTA, tmp, config);
}
rpc_uci_purge_dir(RPC_SNAPSHOT_FILES);
}
rpc_uci_purge_dir(RPC_SNAPSHOT_FILES);
if (glob(tmp, GLOB_PERIOD, NULL, &gl) < 0)
return;
if (glob(tmp, GLOB_PERIOD, NULL, &gl) < 0)
return;
- rpc_uci_do_rollback(apply_ctx, NULL, &gl);
-}
-
-static int
-rpc_uci_apply_access(const char *sid, glob_t *gl)
-{
- struct stat s;
- int i, c = 0;
-
- if (gl->gl_pathc < 3)
- return UBUS_STATUS_NO_DATA;
-
- for (i = 0; i < gl->gl_pathc; i++) {
- char *config = basename(gl->gl_pathv[i]);
-
- if (*config == '.')
- continue;
- if (stat(gl->gl_pathv[i], &s) || !s.st_size)
- continue;
- if (!rpc_session_access(sid, "uci", config, "write"))
- return UBUS_STATUS_PERMISSION_DENIED;
- c++;
- }
-
- if (!c)
- return UBUS_STATUS_NO_DATA;
-
- return 0;
+ rpc_uci_do_rollback(apply_ctx, &gl);
rpc_uci_purge_dir(RPC_SNAPSHOT_DELTA);
if (!apply_sid[0]) {
rpc_uci_purge_dir(RPC_SNAPSHOT_DELTA);
if (!apply_sid[0]) {
+ rpc_uci_set_savedir(tb[RPC_T_SESSION]);
+
mkdir(RPC_SNAPSHOT_FILES, 0700);
mkdir(RPC_SNAPSHOT_DELTA, 0700);
mkdir(RPC_SNAPSHOT_FILES, 0700);
mkdir(RPC_SNAPSHOT_DELTA, 0700);
if (glob(tmp, GLOB_PERIOD, NULL, &gl) < 0)
return UBUS_STATUS_NOT_FOUND;
if (glob(tmp, GLOB_PERIOD, NULL, &gl) < 0)
return UBUS_STATUS_NOT_FOUND;
- rpc_uci_do_rollback(ctx, sid, &gl);
+ rpc_uci_do_rollback(ctx, &gl);