linux: add missing conversions for compat.linux.use_emul_path handling

This commit is contained in:
Mateusz Guzik 2020-10-26 18:02:52 +00:00
parent d681c51d36
commit 1024de70f9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=367065
2 changed files with 114 additions and 44 deletions

View File

@ -109,14 +109,13 @@ linux_creat(struct thread *td, struct linux_creat_args *args)
int error;
if (!LUSECONVPATH(td)) {
error = kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE,
O_WRONLY | O_CREAT | O_TRUNC, args->mode);
} else {
LCONVPATHEXIST(td, args->path, &path);
error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
O_WRONLY | O_CREAT | O_TRUNC, args->mode);
LFREEPATH(path);
return (kern_openat(td, AT_FDCWD, args->path, UIO_USERSPACE,
O_WRONLY | O_CREAT | O_TRUNC, args->mode));
}
LCONVPATHEXIST(td, args->path, &path);
error = kern_openat(td, AT_FDCWD, path, UIO_SYSSPACE,
O_WRONLY | O_CREAT | O_TRUNC, args->mode);
LFREEPATH(path);
return (error);
}
#endif
@ -627,30 +626,41 @@ linux_unlink(struct thread *td, struct linux_unlink_args *args)
}
#endif
int
linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
static int
linux_unlinkat_impl(struct thread *td, enum uio_seg pathseg, const char *path,
int dfd, struct linux_unlinkat_args *args)
{
char *path;
int error, dfd;
struct stat st;
if (args->flag & ~LINUX_AT_REMOVEDIR)
return (EINVAL);
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
int error;
if (args->flag & LINUX_AT_REMOVEDIR)
error = kern_frmdirat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0);
error = kern_frmdirat(td, dfd, path, FD_NONE, pathseg, 0);
else
error = kern_funlinkat(td, dfd, path, FD_NONE, UIO_SYSSPACE, 0,
0);
error = kern_funlinkat(td, dfd, path, FD_NONE, pathseg, 0, 0);
if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
/* Introduce POSIX noncompliant behaviour of Linux */
if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
UIO_SYSSPACE, &st, NULL) == 0 && S_ISDIR(st.st_mode))
error = EISDIR;
}
return (error);
}
int
linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
{
char *path;
int error, dfd;
if (args->flag & ~LINUX_AT_REMOVEDIR)
return (EINVAL);
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
if (!LUSECONVPATH(td)) {
return (linux_unlinkat_impl(td, UIO_USERSPACE, args->pathname,
dfd, args));
}
LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
error = linux_unlinkat_impl(td, UIO_SYSSPACE, path, dfd, args);
LFREEPATH(path);
return (error);
}
@ -660,8 +670,10 @@ linux_chdir(struct thread *td, struct linux_chdir_args *args)
char *path;
int error;
if (!LUSECONVPATH(td)) {
return (kern_chdir(td, args->path, UIO_USERSPACE));
}
LCONVPATHEXIST(td, args->path, &path);
error = kern_chdir(td, path, UIO_SYSSPACE);
LFREEPATH(path);
return (error);
@ -674,10 +686,12 @@ linux_chmod(struct thread *td, struct linux_chmod_args *args)
char *path;
int error;
if (!LUSECONVPATH(td)) {
return (kern_fchmodat(td, AT_FDCWD, args->path, UIO_USERSPACE,
args->mode, 0));
}
LCONVPATHEXIST(td, args->path, &path);
error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE,
args->mode, 0);
error = kern_fchmodat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode, 0);
LFREEPATH(path);
return (error);
}
@ -690,8 +704,11 @@ linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
int error, dfd;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
if (!LUSECONVPATH(td)) {
return (kern_fchmodat(td, dfd, args->filename, UIO_USERSPACE,
args->mode, 0));
}
LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
LFREEPATH(path);
return (error);
@ -704,8 +721,10 @@ linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
char *path;
int error;
if (!LUSECONVPATH(td)) {
return (kern_mkdirat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->mode));
}
LCONVPATHCREAT(td, args->path, &path);
error = kern_mkdirat(td, AT_FDCWD, path, UIO_SYSSPACE, args->mode);
LFREEPATH(path);
return (error);
@ -719,8 +738,10 @@ linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
int error, dfd;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
if (!LUSECONVPATH(td)) {
return (kern_mkdirat(td, dfd, args->pathname, UIO_USERSPACE, args->mode));
}
LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
LFREEPATH(path);
return (error);
@ -733,8 +754,11 @@ linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
char *path;
int error;
if (!LUSECONVPATH(td)) {
return (kern_frmdirat(td, AT_FDCWD, args->path, FD_NONE,
UIO_USERSPACE, 0));
}
LCONVPATHEXIST(td, args->path, &path);
error = kern_frmdirat(td, AT_FDCWD, path, FD_NONE, UIO_SYSSPACE, 0);
LFREEPATH(path);
return (error);
@ -746,6 +770,10 @@ linux_rename(struct thread *td, struct linux_rename_args *args)
char *from, *to;
int error;
if (!LUSECONVPATH(td)) {
return (kern_renameat(td, AT_FDCWD, args->from, AT_FDCWD,
args->to, UIO_USERSPACE));
}
LCONVPATHEXIST(td, args->from, &from);
/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
@ -753,7 +781,6 @@ linux_rename(struct thread *td, struct linux_rename_args *args)
LFREEPATH(from);
return (error);
}
error = kern_renameat(td, AT_FDCWD, from, AT_FDCWD, to, UIO_SYSSPACE);
LFREEPATH(from);
LFREEPATH(to);
@ -796,6 +823,10 @@ linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
if (!LUSECONVPATH(td)) {
return (kern_renameat(td, olddfd, args->oldname, newdfd,
args->newname, UIO_USERSPACE));
}
LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
@ -803,7 +834,6 @@ linux_renameat2(struct thread *td, struct linux_renameat2_args *args)
LFREEPATH(from);
return (error);
}
error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
LFREEPATH(from);
LFREEPATH(to);
@ -817,6 +847,10 @@ linux_symlink(struct thread *td, struct linux_symlink_args *args)
char *path, *to;
int error;
if (!LUSECONVPATH(td)) {
return (kern_symlinkat(td, args->path, AT_FDCWD, args->to,
UIO_USERSPACE));
}
LCONVPATHEXIST(td, args->path, &path);
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
@ -824,7 +858,6 @@ linux_symlink(struct thread *td, struct linux_symlink_args *args)
LFREEPATH(path);
return (error);
}
error = kern_symlinkat(td, path, AT_FDCWD, to, UIO_SYSSPACE);
LFREEPATH(path);
LFREEPATH(to);
@ -839,6 +872,10 @@ linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
int error, dfd;
dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
if (!LUSECONVPATH(td)) {
return (kern_symlinkat(td, args->oldname, dfd, args->newname,
UIO_USERSPACE));
}
LCONVPATHEXIST(td, args->oldname, &path);
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
@ -846,7 +883,6 @@ linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
LFREEPATH(path);
return (error);
}
error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
LFREEPATH(path);
LFREEPATH(to);
@ -860,8 +896,11 @@ linux_readlink(struct thread *td, struct linux_readlink_args *args)
char *name;
int error;
if (!LUSECONVPATH(td)) {
return (kern_readlinkat(td, AT_FDCWD, args->name, UIO_USERSPACE,
args->buf, UIO_USERSPACE, args->count));
}
LCONVPATHEXIST(td, args->name, &name);
error = kern_readlinkat(td, AT_FDCWD, name, UIO_SYSSPACE,
args->buf, UIO_USERSPACE, args->count);
LFREEPATH(name);
@ -876,8 +915,11 @@ linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
int error, dfd;
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
if (!LUSECONVPATH(td)) {
return (kern_readlinkat(td, dfd, args->path, UIO_USERSPACE,
args->buf, UIO_USERSPACE, args->bufsiz));
}
LCONVPATHEXIST_AT(td, args->path, &name, dfd);
error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
UIO_USERSPACE, args->bufsiz);
LFREEPATH(name);
@ -890,6 +932,9 @@ linux_truncate(struct thread *td, struct linux_truncate_args *args)
char *path;
int error;
if (!LUSECONVPATH(td)) {
return (kern_truncate(td, args->path, UIO_USERSPACE, args->length));
}
LCONVPATHEXIST(td, args->path, &path);
error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
LFREEPATH(path);
@ -910,6 +955,9 @@ linux_truncate64(struct thread *td, struct linux_truncate64_args *args)
length = args->length;
#endif
if (!LUSECONVPATH(td)) {
return (kern_truncate(td, args->path, UIO_USERSPACE, length));
}
LCONVPATHEXIST(td, args->path, &path);
error = kern_truncate(td, path, UIO_SYSSPACE, length);
LFREEPATH(path);
@ -947,6 +995,10 @@ linux_link(struct thread *td, struct linux_link_args *args)
char *path, *to;
int error;
if (!LUSECONVPATH(td)) {
return (kern_linkat(td, AT_FDCWD, AT_FDCWD, args->path, args->to,
UIO_USERSPACE, FOLLOW));
}
LCONVPATHEXIST(td, args->path, &path);
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
@ -954,7 +1006,6 @@ linux_link(struct thread *td, struct linux_link_args *args)
LFREEPATH(path);
return (error);
}
error = kern_linkat(td, AT_FDCWD, AT_FDCWD, path, to, UIO_SYSSPACE,
FOLLOW);
LFREEPATH(path);
@ -974,6 +1025,12 @@ linux_linkat(struct thread *td, struct linux_linkat_args *args)
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
FOLLOW;
if (!LUSECONVPATH(td)) {
return (kern_linkat(td, olddfd, newdfd, args->oldname,
args->newname, UIO_USERSPACE, follow));
}
LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
@ -981,9 +1038,6 @@ linux_linkat(struct thread *td, struct linux_linkat_args *args)
LFREEPATH(path);
return (error);
}
follow = (args->flag & LINUX_AT_SYMLINK_FOLLOW) == 0 ? NOFOLLOW :
FOLLOW;
error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, follow);
LFREEPATH(path);
LFREEPATH(to);
@ -1526,8 +1580,11 @@ linux_chown(struct thread *td, struct linux_chown_args *args)
char *path;
int error;
if (!LUSECONVPATH(td)) {
return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE,
args->uid, args->gid, 0));
}
LCONVPATHEXIST(td, args->path, &path);
error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
args->gid, 0);
LFREEPATH(path);
@ -1545,10 +1602,13 @@ linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
return (EINVAL);
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
AT_SYMLINK_NOFOLLOW;
if (!LUSECONVPATH(td)) {
return (kern_fchownat(td, dfd, args->filename, UIO_USERSPACE,
args->uid, args->gid, flag));
}
LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
flag);
LFREEPATH(path);
@ -1562,10 +1622,13 @@ linux_lchown(struct thread *td, struct linux_lchown_args *args)
char *path;
int error;
if (!LUSECONVPATH(td)) {
return (kern_fchownat(td, AT_FDCWD, args->path, UIO_USERSPACE, args->uid,
args->gid, AT_SYMLINK_NOFOLLOW));
}
LCONVPATHEXIST(td, args->path, &path);
error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid,
args->gid, AT_SYMLINK_NOFOLLOW);
error = kern_fchownat(td, AT_FDCWD, path, UIO_SYSSPACE, args->uid, args->gid,
AT_SYMLINK_NOFOLLOW);
LFREEPATH(path);
return (error);
}

View File

@ -874,6 +874,13 @@ linux_utimensat(struct thread *td, struct linux_utimensat_args *args)
return (0);
}
if (!LUSECONVPATH(td)) {
if (args->pathname != NULL) {
return (kern_utimensat(td, dfd, args->pathname,
UIO_USERSPACE, timesp, UIO_SYSSPACE, flags));
}
}
if (args->pathname != NULL)
LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
else if (args->flags != 0)