[PATCH uci] Prevent truncation when file system is full

Reuben Dowle reuben.dowle at 4rf.com
Wed Aug 31 19:29:11 PDT 2022


Currently there is no error checking that uci write is successful. When file
system is full, the temporary file can be created, but no contents can be
written to it. This empty file is then renamed over the previous valid uci
file.

This patch adds error handling to all file write functions to prevent this.

Signed-off-by: Reuben Dowle <reuben.dowle at 4rf.com>
---
 file.c | 49 ++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 36 insertions(+), 13 deletions(-)

diff --git a/file.c b/file.c
index 93abfae..bfa4105 100644
--- a/file.c
+++ b/file.c
@@ -613,33 +613,47 @@ static void uci_export_package(struct uci_package *p, FILE *stream, bool header)
 	struct uci_element *s, *o, *i;
 
 	if (header)
-		fprintf(stream, "package %s\n", uci_escape(ctx, p->e.name));
+		if(fprintf(stream, "package %s\n", uci_escape(ctx, p->e.name)) < 0)
+			UCI_THROW(ctx, UCI_ERR_IO);
+
 	uci_foreach_element(&p->sections, s) {
 		struct uci_section *sec = uci_to_section(s);
-		fprintf(stream, "\nconfig %s", uci_escape(ctx, sec->type));
+		if(fprintf(stream, "\nconfig %s", uci_escape(ctx, sec->type)) < 0)
+			UCI_THROW(ctx, UCI_ERR_IO);
+
 		if (!sec->anonymous || (ctx->flags & UCI_FLAG_EXPORT_NAME))
-			fprintf(stream, " '%s'", uci_escape(ctx, sec->e.name));
-		fprintf(stream, "\n");
+		{
+			if(fprintf(stream, " '%s'", uci_escape(ctx, sec->e.name)) < 0)
+				UCI_THROW(ctx, UCI_ERR_IO);
+		}
+		if(fprintf(stream, "\n") < 0)
+			UCI_THROW(ctx, UCI_ERR_IO);
 		uci_foreach_element(&sec->options, o) {
 			struct uci_option *opt = uci_to_option(o);
 			switch(opt->type) {
 			case UCI_TYPE_STRING:
-				fprintf(stream, "\toption %s", uci_escape(ctx, opt->e.name));
-				fprintf(stream, " '%s'\n", uci_escape(ctx, opt->v.string));
+				if(fprintf(stream, "\toption %s", uci_escape(ctx, opt->e.name)) < 0)
+					UCI_THROW(ctx, UCI_ERR_IO);
+				if(fprintf(stream, " '%s'\n", uci_escape(ctx, opt->v.string)) < 0)
+					UCI_THROW(ctx, UCI_ERR_IO);
 				break;
 			case UCI_TYPE_LIST:
 				uci_foreach_element(&opt->v.list, i) {
-					fprintf(stream, "\tlist %s", uci_escape(ctx, opt->e.name));
-					fprintf(stream, " '%s'\n", uci_escape(ctx, i->name));
+					if(fprintf(stream, "\tlist %s", uci_escape(ctx, opt->e.name)) < 0)
+						UCI_THROW(ctx, UCI_ERR_IO);
+					if(fprintf(stream, " '%s'\n", uci_escape(ctx, i->name)) < 0)
+						UCI_THROW(ctx, UCI_ERR_IO);
 				}
 				break;
 			default:
-				fprintf(stream, "\t# unknown type for option '%s'\n", uci_escape(ctx, opt->e.name));
+				if(fprintf(stream, "\t# unknown type for option '%s'\n", uci_escape(ctx, opt->e.name)) < 0)
+					UCI_THROW(ctx, UCI_ERR_IO);
 				break;
 			}
 		}
 	}
-	fprintf(stream, "\n");
+	if(fprintf(stream, "\n") < 0)
+		UCI_THROW(ctx, UCI_ERR_IO);
 }
 
 int uci_export(struct uci_context *ctx, FILE *stream, struct uci_package *package, bool header)
@@ -649,6 +663,8 @@ int uci_export(struct uci_context *ctx, FILE *stream, struct uci_package *packag
 	UCI_HANDLE_ERR(ctx);
 	UCI_ASSERT(ctx, stream != NULL);
 
+	UCI_TRAP_SAVE(ctx, error);
+
 	if (package)
 		uci_export_package(package, stream, header);
 	else {
@@ -657,7 +673,12 @@ int uci_export(struct uci_context *ctx, FILE *stream, struct uci_package *packag
 		}
 	}
 
+	UCI_TRAP_RESTORE(ctx);
+
 	return 0;
+
+error:
+	return -1;
 }
 
 int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct uci_package **package, bool single)
@@ -800,10 +821,12 @@ static void uci_file_commit(struct uci_context *ctx, struct uci_package **packag
 	if (!f2)
 		UCI_THROW(ctx, UCI_ERR_IO);
 
-	uci_export(ctx, f2, p, false);
+	UCI_INTERNAL(uci_export, ctx, f2, p, false);
 
-	fflush(f2);
-	fsync(fileno(f2));
+	if(fflush(f2) != 0)
+		UCI_THROW(ctx, UCI_ERR_IO);
+	if(fsync(fileno(f2)) != 0)
+		UCI_THROW(ctx, UCI_ERR_IO);
 	uci_close_stream(f2);
 
 	do_rename = true;
-- 
2.37.2




More information about the openwrt-devel mailing list