Index: src/trusted/service_runtime/sys_filename.c |
diff --git a/src/trusted/service_runtime/sys_filename.c b/src/trusted/service_runtime/sys_filename.c |
index 41edc2385bf1e707f48f3337d16225ffb1a9164f..61aa888cd44dc9220892303676665d93c31ee919 100644 |
--- a/src/trusted/service_runtime/sys_filename.c |
+++ b/src/trusted/service_runtime/sys_filename.c |
@@ -44,6 +44,49 @@ static uint32_t CopyPathFromUser(struct NaClApp *nap, |
return 0; |
} |
+static uint32_t CopyHostPathFromUser(struct NaClApp *nap, |
+ char *dest, |
+ size_t num_bytes, |
+ uintptr_t src) { |
+ /* |
+ * The purpose of this function is to not only copy the path bytes from the |
+ * NaClApp, but to make sure the path is properly sanitized and has the |
+ * NaClRootFolder prefixed, if provided. |
+ * Start and see if there even is a root. |
+ */ |
+ if (NaClRootFolder == NULL) { |
+ return CopyPathFromUser(nap, dest, num_bytes, src); |
+ } |
+ /* |
+ * Make sure we have room for the trailing null byte and an actual path. |
+ */ |
+ if (NaClRootFolderLen + 1 >= num_bytes) { |
+ return -NACL_ABI_ENAMETOOLONG; |
+ } |
+ /* |
+ * Okay, add the root folder to dest (which will have a trailing slash |
+ * already), then copy the path in after. |
+ */ |
+ memcpy(dest, NaClRootFolder, NaClRootFolderLen); |
+ return CopyPathFromUser(nap, |
+ dest + NaClRootFolderLen, |
+ num_bytes - NaClRootFolderLen, |
+ src); |
+ /* |
+ * TODO(jtolds): make sure we sanitize the path we just got so it has no ".." |
+ * path elements. |
jtolds
2015/06/25 23:05:05
does this even need to happen?
Mark Seaborn
2015/06/25 23:55:09
If you don't remove ".." elements, isn't it trivia
jtolds
2015/06/26 22:07:11
currently working through these comments, but i ju
|
+ */ |
+} |
+ |
+int NaClCopyHostPathOutToUser(struct NaClApp *nap, |
+ uintptr_t dst_usr_addr, |
+ char *path) { |
+ /* |
+ * TODO(jtolds): remove NaClRootFolder prefix and fail if it doesn't match |
jtolds
2015/06/25 23:05:05
this function is only used to get the CWD. what sh
|
+ */ |
+ return NaClCopyOutToUser(nap, dst_usr_addr, path, strlen(path) + 1); |
+} |
+ |
int32_t NaClSysOpen(struct NaClAppThread *natp, |
uint32_t pathname, |
int flags, |
@@ -58,11 +101,11 @@ int32_t NaClSysOpen(struct NaClAppThread *natp, |
"0x%08"NACL_PRIx32", 0x%x, 0x%x)\n", |
(uintptr_t) natp, pathname, flags, mode); |
- if (!NaClAclBypassChecks) { |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) { |
return -NACL_ABI_EACCES; |
} |
- retval = CopyPathFromUser(nap, path, sizeof path, (uintptr_t) pathname); |
+ retval = CopyHostPathFromUser(nap, path, sizeof path, (uintptr_t) pathname); |
if (0 != retval) |
goto cleanup; |
@@ -166,11 +209,11 @@ int32_t NaClSysStat(struct NaClAppThread *natp, |
("Entered NaClSysStat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIx32"," |
" 0x%08"NACL_PRIx32")\n"), (uintptr_t) natp, pathname, nasp); |
- if (!NaClAclBypassChecks) { |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) { |
return -NACL_ABI_EACCES; |
} |
- retval = CopyPathFromUser(nap, path, sizeof path, pathname); |
+ retval = CopyHostPathFromUser(nap, path, sizeof path, pathname); |
if (0 != retval) |
goto cleanup; |
@@ -197,12 +240,12 @@ int32_t NaClSysMkdir(struct NaClAppThread *natp, |
char path[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) { |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) { |
retval = -NACL_ABI_EACCES; |
goto cleanup; |
} |
- retval = CopyPathFromUser(nap, path, sizeof path, pathname); |
+ retval = CopyHostPathFromUser(nap, path, sizeof path, pathname); |
if (0 != retval) |
goto cleanup; |
@@ -217,12 +260,12 @@ int32_t NaClSysRmdir(struct NaClAppThread *natp, |
char path[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) { |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) { |
retval = -NACL_ABI_EACCES; |
goto cleanup; |
} |
- retval = CopyPathFromUser(nap, path, sizeof path, pathname); |
+ retval = CopyHostPathFromUser(nap, path, sizeof path, pathname); |
if (0 != retval) |
goto cleanup; |
@@ -237,12 +280,12 @@ int32_t NaClSysChdir(struct NaClAppThread *natp, |
char path[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) { |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) { |
retval = -NACL_ABI_EACCES; |
goto cleanup; |
} |
- retval = CopyPathFromUser(nap, path, sizeof path, pathname); |
+ retval = CopyHostPathFromUser(nap, path, sizeof path, pathname); |
if (0 != retval) |
goto cleanup; |
@@ -258,7 +301,7 @@ int32_t NaClSysGetcwd(struct NaClAppThread *natp, |
int32_t retval = -NACL_ABI_EINVAL; |
char path[NACL_CONFIG_PATH_MAX]; |
- if (!NaClAclBypassChecks) { |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) { |
retval = -NACL_ABI_EACCES; |
goto cleanup; |
} |
@@ -270,7 +313,7 @@ int32_t NaClSysGetcwd(struct NaClAppThread *natp, |
if (retval != 0) |
goto cleanup; |
- if (!NaClCopyOutToUser(nap, buffer, &path, strlen(path) + 1)) |
+ if (!NaClCopyHostPathOutToUser(nap, buffer, &path[0])) |
retval = -NACL_ABI_EFAULT; |
cleanup: |
@@ -283,12 +326,12 @@ int32_t NaClSysUnlink(struct NaClAppThread *natp, |
char path[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) { |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) { |
retval = -NACL_ABI_EACCES; |
goto cleanup; |
} |
- retval = CopyPathFromUser(nap, path, sizeof path, pathname); |
+ retval = CopyHostPathFromUser(nap, path, sizeof path, pathname); |
if (0 != retval) |
goto cleanup; |
@@ -306,10 +349,10 @@ int32_t NaClSysTruncate(struct NaClAppThread *natp, |
int32_t retval = -NACL_ABI_EINVAL; |
nacl_abi_off_t length; |
- if (!NaClAclBypassChecks) |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) |
return -NACL_ABI_EACCES; |
- retval = CopyPathFromUser(nap, path, sizeof path, pathname); |
+ retval = CopyHostPathFromUser(nap, path, sizeof path, pathname); |
if (0 != retval) |
return retval; |
@@ -334,27 +377,51 @@ int32_t NaClSysLstat(struct NaClAppThread *natp, |
("Entered NaClSysLstat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIx32"," |
" 0x%08"NACL_PRIx32")\n"), (uintptr_t) natp, pathname, nasp); |
- if (!NaClAclBypassChecks) { |
- return -NACL_ABI_EACCES; |
- } |
+ if (NaClRootFolder != NULL) { |
+ retval = CopyHostPathFromUser(nap, path, sizeof path, pathname); |
+ if (0 != retval) |
+ return retval; |
- retval = CopyPathFromUser(nap, path, sizeof path, pathname); |
- if (0 != retval) |
+ /* |
+ * Mounted root folders don't support symlinks yet, so pretend they don't |
+ * exist, and all symlinks are actually whatever they point to. CAREFUL, |
+ * this means having symlinks that point outside of your mounted root |
Mark Seaborn
2015/06/25 23:55:09
Furthermore, note that if you have a relative syml
|
+ * folder can allow chroot jail breaking! |
+ * For this reason, symlink creation is also disabled. |
+ */ |
+ retval = NaClHostDescStat(path, &stbuf); |
+ if (0 == retval) { |
+ struct nacl_abi_stat abi_stbuf; |
+ |
+ retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf, &stbuf); |
+ if (!NaClCopyOutToUser(nap, nasp, &abi_stbuf, sizeof abi_stbuf)) { |
+ return -NACL_ABI_EFAULT; |
+ } |
+ } |
return retval; |
- /* |
- * Perform a host stat. |
- */ |
- retval = NaClHostDescLstat(path, &stbuf); |
- if (0 == retval) { |
- struct nacl_abi_stat abi_stbuf; |
+ } else if (NaClAclBypassChecks) { |
+ retval = CopyPathFromUser(nap, path, sizeof path, pathname); |
+ if (0 != retval) |
+ return retval; |
- retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf, &stbuf); |
- if (!NaClCopyOutToUser(nap, nasp, &abi_stbuf, sizeof abi_stbuf)) { |
- return -NACL_ABI_EFAULT; |
+ /* |
+ * Perform a host lstat directly |
+ */ |
+ retval = NaClHostDescLstat(path, &stbuf); |
+ if (0 == retval) { |
+ struct nacl_abi_stat abi_stbuf; |
+ |
+ retval = NaClAbiStatHostDescStatXlateCtor(&abi_stbuf, &stbuf); |
+ if (!NaClCopyOutToUser(nap, nasp, &abi_stbuf, sizeof abi_stbuf)) { |
+ return -NACL_ABI_EFAULT; |
+ } |
} |
+ return retval; |
+ |
+ } else { |
+ return -NACL_ABI_EACCES; |
} |
- return retval; |
} |
int32_t NaClSysLink(struct NaClAppThread *natp, |
@@ -365,14 +432,14 @@ int32_t NaClSysLink(struct NaClAppThread *natp, |
char newpath[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) |
return -NACL_ABI_EACCES; |
- retval = CopyPathFromUser(nap, oldpath, sizeof oldpath, oldname); |
+ retval = CopyHostPathFromUser(nap, oldpath, sizeof oldpath, oldname); |
if (0 != retval) |
return retval; |
- retval = CopyPathFromUser(nap, newpath, sizeof newpath, newname); |
+ retval = CopyHostPathFromUser(nap, newpath, sizeof newpath, newname); |
if (0 != retval) |
return retval; |
@@ -387,14 +454,14 @@ int32_t NaClSysRename(struct NaClAppThread *natp, |
char newpath[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) |
return -NACL_ABI_EACCES; |
- retval = CopyPathFromUser(nap, oldpath, sizeof oldpath, oldname); |
+ retval = CopyHostPathFromUser(nap, oldpath, sizeof oldpath, oldname); |
if (0 != retval) |
return retval; |
- retval = CopyPathFromUser(nap, newpath, sizeof newpath, newname); |
+ retval = CopyHostPathFromUser(nap, newpath, sizeof newpath, newname); |
if (0 != retval) |
return retval; |
@@ -409,6 +476,15 @@ int32_t NaClSysSymlink(struct NaClAppThread *natp, |
char newpath[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
+ if (NaClRootFolder != NULL) { |
+ /* |
+ * Mounted root folders don't support symlinks yet, so pretend they don't |
+ * exist and can't be created. See also lstat and readlink. |
+ * Could be convinced to do ENOSYS instead of EPERM. |
+ */ |
+ return -NACL_ABI_EPERM; |
+ } |
+ |
if (!NaClAclBypassChecks) |
return -NACL_ABI_EACCES; |
@@ -430,10 +506,10 @@ int32_t NaClSysChmod(struct NaClAppThread *natp, |
char pathname[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) |
return -NACL_ABI_EACCES; |
- retval = CopyPathFromUser(nap, pathname, sizeof pathname, path); |
+ retval = CopyHostPathFromUser(nap, pathname, sizeof pathname, path); |
if (0 != retval) |
return retval; |
@@ -447,7 +523,7 @@ int32_t NaClSysAccess(struct NaClAppThread *natp, |
char pathname[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) |
return -NACL_ABI_EACCES; |
/* |
@@ -457,7 +533,7 @@ int32_t NaClSysAccess(struct NaClAppThread *natp, |
&& (amode & ~(NACL_ABI_R_OK | NACL_ABI_W_OK | NACL_ABI_X_OK)) != 0) |
return -NACL_ABI_EINVAL; |
- retval = CopyPathFromUser(nap, pathname, sizeof pathname, path); |
+ retval = CopyHostPathFromUser(nap, pathname, sizeof pathname, path); |
if (0 != retval) |
return retval; |
@@ -476,6 +552,14 @@ int32_t NaClSysReadlink(struct NaClAppThread *natp, |
int32_t retval = -NACL_ABI_EINVAL; |
uint32_t result_size; |
+ if (NaClRootFolder != NULL) { |
+ /* We're going to return an error, but perhaps in this case we should |
+ * try and find out if the file even exists, so we can return ENOENT first, |
+ * and then return EINVAL otherwise? Dunno. |
+ */ |
+ return -NACL_ABI_ENOSYS; |
+ } |
+ |
if (!NaClAclBypassChecks) |
return -NACL_ABI_EACCES; |
@@ -518,10 +602,10 @@ int32_t NaClSysUtimes(struct NaClAppThread *natp, |
char pathname[NACL_CONFIG_PATH_MAX]; |
int32_t retval = -NACL_ABI_EINVAL; |
- if (!NaClAclBypassChecks) |
+ if (!NaClAclBypassChecks && NaClRootFolder == NULL) |
return -NACL_ABI_EACCES; |
- retval = CopyPathFromUser(nap, pathname, sizeof pathname, path); |
+ retval = CopyHostPathFromUser(nap, pathname, sizeof pathname, path); |
if (0 != retval) |
return retval; |