shithub: ext4srv

Download patch

ref: 3d71a606cc2643a720a79752c7dbcebd816dcebc
parent: 22b296500a2ba685943388ff28c7d8b8f42cbeb5
author: Sigrid Solveig Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sat Nov 14 19:24:05 EST 2020

fix truncation permission check; fix writing beyond file end

--- a/ext4srv.c
+++ b/ext4srv.c
@@ -6,6 +6,8 @@
 #include "group.h"
 #include "common.h"
 
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
 int mainstacksize = 65536;
 
 typedef struct Aux Aux;
@@ -29,7 +31,7 @@
 };
 
 static Opts opts;
-
+static u8int zero[65536];
 static char Eperm[] = "permission denied";
 
 static char *
@@ -103,6 +105,8 @@
 	default:
 		return 0;
 	}
+	if(p & OTRUNC)
+		p |= AWRITE;
 
 	if((s = fullpath(a)) == nil)
 		return -1;
@@ -343,6 +347,7 @@
 		goto ext4errorrm;
 	ext4_owner_set(s, a->uid, ext4_inode_get_gid(&inode));
 
+	free(a->path);
 	a->path = strdup(strchr(s+1, '/')+1);
 	free(s);
 	r->ofcall.iounit = 0;
@@ -445,25 +450,24 @@
 rread(Req *r)
 {
 	ulong n;
+	int res;
 	Aux *a;
 
 	a = r->fid->aux;
 	if(a->type == Adir && a->dir != nil){
 		dirread9p(r, dirgen, a);
-		respond(r, nil);
-		return;
 	}else if(a->type == Afile && a->file != nil){
-		ext4_fseek(a->file, r->ifcall.offset, 0);
-		if(ext4_fread(a->file, r->ofcall.data, r->ifcall.count, &n) != 0){
-			respond(r, "i/o error");
-		}else{
-			r->ofcall.count = n;
-			respond(r, nil);
+		if(ext4_fseek(a->file, r->ifcall.offset, SEEK_SET) != 0)
+			n = 0;
+		else if((res = ext4_fread(a->file, r->ofcall.data, r->ifcall.count, &n)) != 0){
+			respond(r, errno2s(res));
+			return;
 		}
-		return;
+
+		r->ofcall.count = n;
 	}
 
-	respond(r, "eh?");
+	respond(r, nil);
 }
 
 static void
@@ -476,19 +480,25 @@
 	a = r->fid->aux;
 	if(a->type == Adir){
 		respond(r, "can't write to dir");
-		return;
 	}else if(a->type == Afile){
-		ext4_fseek(a->file, r->ifcall.offset, SEEK_SET);
-		if((res = ext4_fwrite(a->file, r->ifcall.data, r->ifcall.count, &n)) != 0)
-			respond(r, errno2s(res));
-		else{
-			r->ofcall.count = n;
-			respond(r, nil);
+		while(ext4_fsize(a->file) < r->ifcall.offset){
+			ext4_fseek(a->file, 0, SEEK_END);
+			if((res = ext4_fwrite(a->file, zero, MIN(r->ifcall.offset-ext4_fsize(a->file), sizeof(zero)), &n)) != 0)
+				goto ext4error;
 		}
-		return;
+		if((res = ext4_fseek(a->file, r->ifcall.offset, SEEK_SET)) != 0)
+			goto ext4error;
+		if((res = ext4_fwrite(a->file, r->ifcall.data, r->ifcall.count, &n)) != 0)
+			goto ext4error;
+
+		r->ofcall.count = n;
+		respond(r, nil);
 	}
 
-	respond(r, "eh?");
+	return;
+
+ext4error:
+	respond(r, errno2s(res));
 }
 
 static void
@@ -758,20 +768,14 @@
 	Aux *a, *c;
 
 	a = oldfid->aux;
-	switch(a->type){
-	case Afile:
-	case Adir:
-		if((c = calloc(1, sizeof(*c))) == nil)
-			return "memory";
-		memmove(c, a, sizeof(*c));
-		c->path = strdup(a->path);
-		c->file = nil;
-		c->dir = nil;
-		break;
 
-	default:
-		return "unknown aux type";
-	}
+	if((c = calloc(1, sizeof(*c))) == nil)
+		return "memory";
+	memmove(c, a, sizeof(*c));
+	c->path = strdup(a->path);
+	c->file = nil;
+	c->dir = nil;
+
 	incref(c->p);
 	newfid->aux = c;
 
@@ -798,12 +802,9 @@
 			ext4_fclose(a->file);
 			free(a->file);
 		}
-	}else{
-		/* that would be a BUG */
-		return;
 	}
 
-	if(decref(a->p) == 0)
+	if(decref(a->p) < 1)
 		closepart(a->p);
 	free(a->path);
 	free(a);