(wip) Safely wrap memory access from File.
Previously we had a lot of places where &uxn.ram[addr] was being used without checking that addr+length < 65536. In cases where that value is exceeded, the reads/writes should wrap back around to the beginning of memory. After this change, most of the accesses have been made safe. Two places that are not (yet) converted: 1. file_init: We already truncate reads past the end of ram. While this does is technically incorrect it will avoid memory corruption or crashing. 2. file_read_dir: The code here still uses snprintf formatting.
This commit is contained in:
parent
df51651789
commit
7fcd7ad635
|
@ -195,7 +195,20 @@ file_init(UxnFile *c, char *filename, size_t max_len, int override_sandbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
static Uint16
|
||||||
file_read(UxnFile *c, void *dest, int len)
|
file_read_file(Uint16 addr, int len, FILE *f)
|
||||||
|
{
|
||||||
|
int total = addr + len;
|
||||||
|
if (total < 0x10000) {
|
||||||
|
return fread(&uxn.ram[addr], 1, len, f);
|
||||||
|
} else {
|
||||||
|
size_t n1 = fread(&uxn.ram[addr], 1, 0x10000 - addr, f);
|
||||||
|
size_t n2 = fread(&uxn.ram[0], 1, total - 0x10000, f);
|
||||||
|
return n1 + n2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Uint16
|
||||||
|
file_read(UxnFile *c, Uint16 addr, int len)
|
||||||
{
|
{
|
||||||
if(c->outside_sandbox) return 0;
|
if(c->outside_sandbox) return 0;
|
||||||
if(c->state != FILE_READ && c->state != DIR_READ) {
|
if(c->state != FILE_READ && c->state != DIR_READ) {
|
||||||
|
@ -206,9 +219,9 @@ file_read(UxnFile *c, void *dest, int len)
|
||||||
c->state = FILE_READ;
|
c->state = FILE_READ;
|
||||||
}
|
}
|
||||||
if(c->state == FILE_READ)
|
if(c->state == FILE_READ)
|
||||||
return fread(dest, 1, len, c->f);
|
return file_read_file(addr, len, c->f);
|
||||||
if(c->state == DIR_READ)
|
if(c->state == DIR_READ)
|
||||||
return file_read_dir(c, dest, len);
|
return file_read_dir(c, (char *)&uxn.ram[addr], len);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +258,21 @@ ensure_parent_dirs(char *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
static Uint16
|
||||||
file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags)
|
file_write_file(Uint16 addr, int len, FILE *f)
|
||||||
|
{
|
||||||
|
int total = addr + len;
|
||||||
|
if (total < 0x10000) {
|
||||||
|
Uint16 n = fwrite(&uxn.ram[addr], 1, len, f);
|
||||||
|
return fflush(f) == 0 ? n : 0;
|
||||||
|
} else {
|
||||||
|
Uint16 n1 = fwrite(&uxn.ram[addr], 1, 0x10000 - addr, f);
|
||||||
|
Uint16 n2 = fwrite(&uxn.ram[0], 1, total - 0x10000, f);
|
||||||
|
return fflush(f) == 0 ? n1 + n2 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Uint16
|
||||||
|
file_write(UxnFile *c, Uint16 addr, Uint16 len, Uint8 flags)
|
||||||
{
|
{
|
||||||
Uint16 ret = 0;
|
Uint16 ret = 0;
|
||||||
if(c->outside_sandbox) return 0;
|
if(c->outside_sandbox) return 0;
|
||||||
|
@ -258,8 +285,7 @@ file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags)
|
||||||
c->state = FILE_WRITE;
|
c->state = FILE_WRITE;
|
||||||
}
|
}
|
||||||
if(c->state == FILE_WRITE) {
|
if(c->state == FILE_WRITE) {
|
||||||
if((ret = fwrite(src, 1, len, c->f)) > 0 && fflush(c->f) != 0)
|
ret = file_write_file(addr, len, c->f);
|
||||||
ret = 0;
|
|
||||||
}
|
}
|
||||||
if (c->state == DIR_WRITE) {
|
if (c->state == DIR_WRITE) {
|
||||||
ret = dir_exists(c->current_filename);
|
ret = dir_exists(c->current_filename);
|
||||||
|
@ -268,38 +294,38 @@ file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
static Uint16
|
||||||
stat_fill(Uint8 *dest, Uint16 len, char c)
|
stat_fill(Uint16 addr, Uint16 len, char c)
|
||||||
{
|
{
|
||||||
Uint16 i;
|
Uint16 i;
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
*(dest++) = c;
|
uxn.ram[(addr + i) & 0xffff] = c;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
static Uint16
|
||||||
stat_size(Uint8 *dest, Uint16 len, off_t size)
|
stat_size(Uint16 addr, Uint16 len, off_t size)
|
||||||
{
|
{
|
||||||
Uint16 i;
|
Uint16 i;
|
||||||
dest += len - 1;
|
for (i = 1; i <= len; i++) {
|
||||||
for (i = 0; i < len; i++) {
|
char c = '0' + (Uint8)(size & 0xf);
|
||||||
*(dest--) = '0' + (Uint8)(size & 0xf);
|
uxn.ram[(addr + len - i) & 0xffff] = c;
|
||||||
size = size >> 4;
|
size = size >> 4;
|
||||||
}
|
}
|
||||||
return size == 0 ? len : stat_fill(dest, len, '?');
|
return size == 0 ? len : stat_fill(addr, len, '?');
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
static Uint16
|
||||||
file_stat(UxnFile *c, void *dest, Uint16 len)
|
file_stat(UxnFile *c, Uint16 addr, Uint16 len)
|
||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if(c->outside_sandbox)
|
if(c->outside_sandbox)
|
||||||
return 0;
|
return 0;
|
||||||
else if(stat(c->current_filename, &st))
|
else if(stat(c->current_filename, &st))
|
||||||
return stat_fill(dest, len, '!');
|
return stat_fill(addr, len, '!');
|
||||||
else if(S_ISDIR(st.st_mode))
|
else if(S_ISDIR(st.st_mode))
|
||||||
return stat_fill(dest, len, '-');
|
return stat_fill(addr, len, '-');
|
||||||
else
|
else
|
||||||
return stat_size(dest, len, st.st_size);
|
return stat_size(addr, len, st.st_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Uint16
|
static Uint16
|
||||||
|
@ -320,7 +346,7 @@ file_deo(Uint8 port)
|
||||||
len = PEEK2(&uxn.dev[0xaa]);
|
len = PEEK2(&uxn.dev[0xaa]);
|
||||||
if(len > 0x10000 - addr)
|
if(len > 0x10000 - addr)
|
||||||
len = 0x10000 - addr;
|
len = 0x10000 - addr;
|
||||||
res = file_stat(&uxn_file[0], &uxn.ram[addr], len);
|
res = file_stat(&uxn_file[0], addr, len);
|
||||||
POKE2(&uxn.dev[0xa2], res);
|
POKE2(&uxn.dev[0xa2], res);
|
||||||
break;
|
break;
|
||||||
case 0xa6:
|
case 0xa6:
|
||||||
|
@ -337,7 +363,7 @@ file_deo(Uint8 port)
|
||||||
len = PEEK2(&uxn.dev[0xaa]);
|
len = PEEK2(&uxn.dev[0xaa]);
|
||||||
if(len > 0x10000 - addr)
|
if(len > 0x10000 - addr)
|
||||||
len = 0x10000 - addr;
|
len = 0x10000 - addr;
|
||||||
res = file_read(&uxn_file[0], &uxn.ram[addr], len);
|
res = file_read(&uxn_file[0], addr, len);
|
||||||
POKE2(&uxn.dev[0xa2], res);
|
POKE2(&uxn.dev[0xa2], res);
|
||||||
break;
|
break;
|
||||||
case 0xaf:
|
case 0xaf:
|
||||||
|
@ -345,7 +371,7 @@ file_deo(Uint8 port)
|
||||||
len = PEEK2(&uxn.dev[0xaa]);
|
len = PEEK2(&uxn.dev[0xaa]);
|
||||||
if(len > 0x10000 - addr)
|
if(len > 0x10000 - addr)
|
||||||
len = 0x10000 - addr;
|
len = 0x10000 - addr;
|
||||||
res = file_write(&uxn_file[0], &uxn.ram[addr], len, uxn.dev[0xa7]);
|
res = file_write(&uxn_file[0], addr, len, uxn.dev[0xa7]);
|
||||||
POKE2(&uxn.dev[0xa2], res);
|
POKE2(&uxn.dev[0xa2], res);
|
||||||
break;
|
break;
|
||||||
/* File 2 */
|
/* File 2 */
|
||||||
|
@ -354,7 +380,7 @@ file_deo(Uint8 port)
|
||||||
len = PEEK2(&uxn.dev[0xba]);
|
len = PEEK2(&uxn.dev[0xba]);
|
||||||
if(len > 0x10000 - addr)
|
if(len > 0x10000 - addr)
|
||||||
len = 0x10000 - addr;
|
len = 0x10000 - addr;
|
||||||
res = file_stat(&uxn_file[1], &uxn.ram[addr], len);
|
res = file_stat(&uxn_file[1], addr, len);
|
||||||
POKE2(&uxn.dev[0xb2], res);
|
POKE2(&uxn.dev[0xb2], res);
|
||||||
break;
|
break;
|
||||||
case 0xb6:
|
case 0xb6:
|
||||||
|
@ -371,7 +397,7 @@ file_deo(Uint8 port)
|
||||||
len = PEEK2(&uxn.dev[0xba]);
|
len = PEEK2(&uxn.dev[0xba]);
|
||||||
if(len > 0x10000 - addr)
|
if(len > 0x10000 - addr)
|
||||||
len = 0x10000 - addr;
|
len = 0x10000 - addr;
|
||||||
res = file_read(&uxn_file[1], &uxn.ram[addr], len);
|
res = file_read(&uxn_file[1], addr, len);
|
||||||
POKE2(&uxn.dev[0xb2], res);
|
POKE2(&uxn.dev[0xb2], res);
|
||||||
break;
|
break;
|
||||||
case 0xbf:
|
case 0xbf:
|
||||||
|
@ -379,7 +405,7 @@ file_deo(Uint8 port)
|
||||||
len = PEEK2(&uxn.dev[0xba]);
|
len = PEEK2(&uxn.dev[0xba]);
|
||||||
if(len > 0x10000 - addr)
|
if(len > 0x10000 - addr)
|
||||||
len = 0x10000 - addr;
|
len = 0x10000 - addr;
|
||||||
res = file_write(&uxn_file[1], &uxn.ram[addr], len, uxn.dev[0xb7]);
|
res = file_write(&uxn_file[1], addr, len, uxn.dev[0xb7]);
|
||||||
POKE2(&uxn.dev[0xb2], res);
|
POKE2(&uxn.dev[0xb2], res);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue