mirror of
https://github.com/clearlinux/graphene.git
synced 2026-09-05 21:31:36 +00:00
[LibOS] Fix absolute path handling in *at() syscalls
As per linux man-pages, dirfd can be ignored if an absolute path is provided when invoking *at() calls. But in Graphene many of the *at() calls require a valid dirfd even when an absolute path is provided. If not, the call fails. This commit fixes the issue by ignoring dirfd if absolute filepath is provided.
This commit is contained in:
committed by
Michał Kowalczyk
parent
186690efef
commit
cadcb2a6ee
@@ -18,24 +18,7 @@
|
||||
#include "shim_thread.h"
|
||||
|
||||
int shim_do_access(const char* file, mode_t mode) {
|
||||
if (!file)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_user_string(file))
|
||||
return -EFAULT;
|
||||
|
||||
struct shim_dentry* dent = NULL;
|
||||
int ret = 0;
|
||||
|
||||
lock(&dcache_lock);
|
||||
|
||||
ret = __path_lookupat(NULL, file, LOOKUP_ACCESS | LOOKUP_FOLLOW, &dent, 0, NULL, false);
|
||||
if (!ret)
|
||||
ret = __permission(dent, mode);
|
||||
|
||||
unlock(&dcache_lock);
|
||||
|
||||
return ret;
|
||||
return shim_do_faccessat(AT_FDCWD, file, mode);
|
||||
}
|
||||
|
||||
int shim_do_faccessat(int dfd, const char* filename, mode_t mode) {
|
||||
@@ -49,7 +32,7 @@ int shim_do_faccessat(int dfd, const char* filename, mode_t mode) {
|
||||
struct shim_dentry* dent = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
if (*filename != '/' && (ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
return ret;
|
||||
|
||||
lock(&dcache_lock);
|
||||
@@ -63,6 +46,7 @@ int shim_do_faccessat(int dfd, const char* filename, mode_t mode) {
|
||||
out:
|
||||
unlock(&dcache_lock);
|
||||
|
||||
put_dentry(dir);
|
||||
if (dir)
|
||||
put_dentry(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -26,34 +26,7 @@
|
||||
/* The kernel would look up the parent directory, and remove the child from the inode. But we are
|
||||
* working with the PAL, so we open the file, truncate and close it. */
|
||||
int shim_do_unlink(const char* file) {
|
||||
if (!file)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_user_string(file))
|
||||
return -EFAULT;
|
||||
|
||||
struct shim_dentry* dent = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = path_lookupat(NULL, file, LOOKUP_OPEN, &dent, NULL)) < 0)
|
||||
return ret;
|
||||
|
||||
if (!dent->parent)
|
||||
return -EACCES;
|
||||
|
||||
if (dent->state & DENTRY_ISDIRECTORY)
|
||||
return -EISDIR;
|
||||
|
||||
if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->unlink) {
|
||||
if ((ret = dent->fs->d_ops->unlink(dent->parent, dent)) < 0)
|
||||
return ret;
|
||||
} else {
|
||||
dent->state |= DENTRY_PERSIST;
|
||||
}
|
||||
|
||||
dent->state |= DENTRY_NEGATIVE;
|
||||
put_dentry(dent);
|
||||
return 0;
|
||||
return shim_do_unlinkat(AT_FDCWD, file, 0);
|
||||
}
|
||||
|
||||
int shim_do_unlinkat(int dfd, const char* pathname, int flag) {
|
||||
@@ -70,7 +43,7 @@ int shim_do_unlinkat(int dfd, const char* pathname, int flag) {
|
||||
struct shim_dentry* dent = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
if (*pathname != '/' && (ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = path_lookupat(dir, pathname, LOOKUP_OPEN, &dent, NULL)) < 0)
|
||||
@@ -103,12 +76,13 @@ int shim_do_unlinkat(int dfd, const char* pathname, int flag) {
|
||||
out_dent:
|
||||
put_dentry(dent);
|
||||
out:
|
||||
put_dentry(dir);
|
||||
if (dir)
|
||||
put_dentry(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int shim_do_mkdir(const char* pathname, int mode) {
|
||||
return open_namei(NULL, NULL, pathname, O_CREAT | O_EXCL | O_DIRECTORY, mode, NULL);
|
||||
return shim_do_mkdirat(AT_FDCWD, pathname, mode);
|
||||
}
|
||||
|
||||
int shim_do_mkdirat(int dfd, const char* pathname, int mode) {
|
||||
@@ -121,12 +95,13 @@ int shim_do_mkdirat(int dfd, const char* pathname, int mode) {
|
||||
struct shim_dentry* dir = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
if (*pathname != '/' && (ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
return ret;
|
||||
|
||||
ret = open_namei(NULL, dir, pathname, O_CREAT | O_EXCL | O_DIRECTORY, mode, NULL);
|
||||
|
||||
put_dentry(dir);
|
||||
if (dir)
|
||||
put_dentry(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -177,29 +152,7 @@ mode_t shim_do_umask(mode_t mask) {
|
||||
}
|
||||
|
||||
int shim_do_chmod(const char* path, mode_t mode) {
|
||||
struct shim_dentry* dent = NULL;
|
||||
int ret = 0;
|
||||
|
||||
/* This isn't documented, but that's what Linux does. */
|
||||
mode &= 07777;
|
||||
|
||||
if (test_user_string(path))
|
||||
return -EFAULT;
|
||||
|
||||
if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
|
||||
return ret;
|
||||
|
||||
if (dent->fs && dent->fs->d_ops && dent->fs->d_ops->chmod) {
|
||||
if ((ret = dent->fs->d_ops->chmod(dent, mode)) < 0)
|
||||
goto out;
|
||||
} else {
|
||||
dent->state |= DENTRY_PERSIST;
|
||||
}
|
||||
|
||||
dent->mode = mode;
|
||||
out:
|
||||
put_dentry(dent);
|
||||
return ret;
|
||||
return shim_do_fchmodat(AT_FDCWD, path, mode);
|
||||
}
|
||||
|
||||
int shim_do_fchmodat(int dfd, const char* filename, mode_t mode) {
|
||||
@@ -216,7 +169,7 @@ int shim_do_fchmodat(int dfd, const char* filename, mode_t mode) {
|
||||
struct shim_dentry* dent = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
if (*filename != '/' && (ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent, NULL)) < 0)
|
||||
@@ -233,7 +186,8 @@ int shim_do_fchmodat(int dfd, const char* filename, mode_t mode) {
|
||||
out_dent:
|
||||
put_dentry(dent);
|
||||
out:
|
||||
put_dentry(dir);
|
||||
if (dir)
|
||||
put_dentry(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -262,23 +216,7 @@ out:
|
||||
}
|
||||
|
||||
int shim_do_chown(const char* path, uid_t uid, gid_t gid) {
|
||||
struct shim_dentry* dent = NULL;
|
||||
int ret = 0;
|
||||
__UNUSED(uid);
|
||||
__UNUSED(gid);
|
||||
|
||||
if (!path)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_user_string(path))
|
||||
return -EFAULT;
|
||||
|
||||
if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
|
||||
return ret;
|
||||
|
||||
/* XXX: do nothing now */
|
||||
put_dentry(dent);
|
||||
return ret;
|
||||
return shim_do_fchownat(AT_FDCWD, path, uid, gid, 0);
|
||||
}
|
||||
|
||||
int shim_do_fchownat(int dfd, const char* filename, uid_t uid, gid_t gid, int flags) {
|
||||
@@ -296,7 +234,7 @@ int shim_do_fchownat(int dfd, const char* filename, uid_t uid, gid_t gid, int fl
|
||||
struct shim_dentry* dent = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
if (*filename != '/' && (ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = path_lookupat(dir, filename, LOOKUP_OPEN, &dent, NULL)) < 0)
|
||||
@@ -305,7 +243,8 @@ int shim_do_fchownat(int dfd, const char* filename, uid_t uid, gid_t gid, int fl
|
||||
/* XXX: do nothing now */
|
||||
put_dentry(dent);
|
||||
out:
|
||||
put_dentry(dir);
|
||||
if (dir)
|
||||
put_dentry(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -621,7 +560,7 @@ int shim_do_renameat(int olddirfd, const char* oldpath, int newdirfd, const char
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if ((ret = get_dirfd_dentry(olddirfd, &old_dir_dent)) < 0) {
|
||||
if (*oldpath != '/' && (ret = get_dirfd_dentry(olddirfd, &old_dir_dent)) < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -634,7 +573,7 @@ int shim_do_renameat(int olddirfd, const char* oldpath, int newdirfd, const char
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((ret = get_dirfd_dentry(newdirfd, &new_dir_dent)) < 0) {
|
||||
if (*newpath != '/' && (ret = get_dirfd_dentry(newdirfd, &new_dir_dent)) < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,30 +88,7 @@ size_t shim_do_write(int fd, const void* buf, size_t count) {
|
||||
}
|
||||
|
||||
int shim_do_open(const char* file, int flags, mode_t mode) {
|
||||
if (!file || test_user_string(file))
|
||||
return -EFAULT;
|
||||
|
||||
if (!(flags & O_CREAT)) {
|
||||
/* `mode` should be ignored if O_CREAT is not specified, according to man */
|
||||
mode = 0;
|
||||
} else {
|
||||
/* This isn't documented, but that's what Linux does. */
|
||||
mode &= 07777;
|
||||
}
|
||||
|
||||
struct shim_handle* hdl = get_new_handle();
|
||||
if (!hdl)
|
||||
return -ENOMEM;
|
||||
|
||||
int ret = 0;
|
||||
ret = open_namei(hdl, NULL, file, flags, mode, NULL);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = set_new_fd_handle(hdl, flags & O_CLOEXEC ? FD_CLOEXEC : 0, NULL);
|
||||
out:
|
||||
put_handle(hdl);
|
||||
return ret;
|
||||
return shim_do_openat(AT_FDCWD, file, flags, mode);
|
||||
}
|
||||
|
||||
int shim_do_creat(const char* path, mode_t mode) {
|
||||
@@ -133,7 +110,7 @@ int shim_do_openat(int dfd, const char* filename, int flags, int mode) {
|
||||
struct shim_dentry* dir = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if ((ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
if (*filename != '/' && (ret = get_dirfd_dentry(dfd, &dir)) < 0)
|
||||
return ret;
|
||||
|
||||
struct shim_handle* hdl = get_new_handle();
|
||||
@@ -151,7 +128,8 @@ int shim_do_openat(int dfd, const char* filename, int flags, int mode) {
|
||||
out_hdl:
|
||||
put_handle(hdl);
|
||||
out:
|
||||
put_dentry(dir);
|
||||
if (dir)
|
||||
put_dentry(dir);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -274,10 +274,8 @@ int shim_do_mknodat(int dirfd, const char* pathname, mode_t mode, dev_t dev) {
|
||||
struct shim_dentry* dir = NULL;
|
||||
struct shim_dentry* dent = NULL;
|
||||
|
||||
ret = get_dirfd_dentry(dirfd, &dir);
|
||||
if (ret < 0) {
|
||||
if (*pathname != '/' && (ret = get_dirfd_dentry(dirfd, &dir)) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = path_lookupat(dir, pathname, LOOKUP_CREATE, &dent, NULL);
|
||||
if (ret < 0 && ret != -ENOENT) {
|
||||
|
||||
@@ -91,6 +91,7 @@ out:
|
||||
}
|
||||
|
||||
int shim_do_readlinkat(int dirfd, const char* file, char* buf, int bufsize) {
|
||||
int ret;
|
||||
if (!file || test_user_string(file))
|
||||
return -EFAULT;
|
||||
|
||||
@@ -102,10 +103,9 @@ int shim_do_readlinkat(int dirfd, const char* file, char* buf, int bufsize) {
|
||||
|
||||
struct shim_dentry* dent = NULL;
|
||||
struct shim_dentry* dir = NULL;
|
||||
int ret = get_dirfd_dentry(dirfd, &dir);
|
||||
if (ret < 0) {
|
||||
|
||||
if (*file != '/' && (ret = get_dirfd_dentry(dirfd, &dir)) < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
struct shim_qstr qstr = QSTR_INIT;
|
||||
|
||||
|
||||
@@ -1942,9 +1942,6 @@ skip = yes
|
||||
[rename13]
|
||||
skip = yes
|
||||
|
||||
[rename14]
|
||||
skip = yes
|
||||
|
||||
[renameat01]
|
||||
skip = yes
|
||||
|
||||
|
||||
Reference in New Issue
Block a user