diff options
author | Patrick Mooney <pmooney@pfmooney.com> | 2016-01-15 20:49:19 +0000 |
---|---|---|
committer | Patrick Mooney <pmooney@pfmooney.com> | 2016-01-19 15:29:30 +0000 |
commit | 8843c35f721fa2818edf0a3ca6047c03d7021f30 (patch) | |
tree | e6b563e7f9b8e87e94d7a9dfbca89add9aa00f4f | |
parent | 8572d6e7175fb68fa8140a6d25fcaea6e81bc742 (diff) | |
download | illumos-joyent-8843c35f721fa2818edf0a3ca6047c03d7021f30.tar.gz |
OS-3925 lxbrand in-kernel link(2) and linkat(2)
OS-5094 lxbrand link to symlink failure
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/file.c | 74 | ||||
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/common/lx_brand.c | 8 | ||||
-rw-r--r-- | usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h | 4 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/os/lx_syscall.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/sys/lx_syscalls.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/brand/lx/syscall/lx_link.c | 97 | ||||
-rw-r--r-- | usr/src/uts/intel/Makefile.files | 1 |
7 files changed, 110 insertions, 84 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/file.c b/usr/src/lib/brand/lx/lx_brand/common/file.c index 0654ac5c3e..79dc5e060d 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/file.c +++ b/usr/src/lib/brand/lx/lx_brand/common/file.c @@ -22,7 +22,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. - * Copyright 2015 Joyent, Inc. All rights reserved. + * Copyright 2016 Joyent, Inc. */ #include <sys/fstyp.h> @@ -120,23 +120,6 @@ ltos_at_flag(int lflag, int allow, boolean_t enforce) */ /* - * On Linux, even root cannot create a link to a directory, so we have to - * add an explicit check. - */ -long -lx_link(uintptr_t p1, uintptr_t p2) -{ - char *from = (char *)p1; - char *to = (char *)p2; - struct stat64 statbuf; - - if ((stat64(from, &statbuf) == 0) && S_ISDIR(statbuf.st_mode)) - return (-EPERM); - - return (link(from, to) ? -errno : 0); -} - -/* * On Linux, an unlink of a directory returns EISDIR, not EPERM. */ long @@ -633,61 +616,6 @@ lx_symlinkat(uintptr_t p1, uintptr_t ext1, uintptr_t p2) } long -lx_linkat(uintptr_t ext1, uintptr_t p1, uintptr_t ext2, uintptr_t p2, - uintptr_t p3) -{ - int atfd1 = (int)ext1; - int atfd2 = (int)ext2; - char pathbuf1[MAXPATHLEN]; - char pathbuf2[MAXPATHLEN]; - int ret; - - /* - * The flag specifies whether the hardlink will point to a symlink or - * not, on solaris the default behaviour of link() is to dereference a - * symlink and there is no obvious way to trigger the other behaviour. - * So for now we just ignore this flag and act like link(). - */ - int flag = p3; - - /* return proper error for invalid flags */ - if ((flag & ~(LX_AT_SYMLINK_FOLLOW | LX_AT_EMPTY_PATH)) != 0) - return (-EINVAL); - - ret = getpathat(atfd1, p1, pathbuf1, sizeof (pathbuf1)); - if (ret < 0) { - if (ret == -EBADF) { - /* - * Try to figure out correct Linux errno. We know path - * is relative. Check if we have a fd for a dir which - * has been removed. - */ - if (atfd1 != -1 && lx_fd_to_path(atfd1, pathbuf1, - sizeof (pathbuf1)) == NULL) - ret = -ENOENT; - } - return (ret); - } - - ret = getpathat(atfd2, p2, pathbuf2, sizeof (pathbuf2)); - if (ret < 0) { - if (ret == -EBADF) { - /* - * Try to figure out correct Linux errno. We know path - * is relative. Check if we have a fd for a dir which - * has been removed. - */ - if (atfd2 != -1 && lx_fd_to_path(atfd2, pathbuf2, - sizeof (pathbuf2)) == NULL) - ret = -ENOENT; - } - return (ret); - } - - return (lx_link((uintptr_t)pathbuf1, (uintptr_t)pathbuf2)); -} - -long lx_readlink(uintptr_t p1, uintptr_t p2, uintptr_t p3) { int ret; diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c index bc3c1921f3..582c2f0b55 100644 --- a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c +++ b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c @@ -1045,7 +1045,7 @@ static lx_syscall_handler_t lx_handlers[] = { NULL, /* 83: mkdir */ lx_rmdir, /* 84: rmdir */ lx_creat, /* 85: creat */ - lx_link, /* 86: link */ + NULL, /* 86: link */ lx_unlink, /* 87: unlink */ lx_symlink, /* 88: symlink */ lx_readlink, /* 89: readlink */ @@ -1224,7 +1224,7 @@ static lx_syscall_handler_t lx_handlers[] = { NULL, /* 262: fstatat64 */ lx_unlinkat, /* 263: unlinkat */ lx_renameat, /* 264: renameat */ - lx_linkat, /* 265: linkat */ + NULL, /* 265: linkat */ lx_symlinkat, /* 266: symlinkat */ lx_readlinkat, /* 267: readlinkat */ NULL, /* 268: fchmodat */ @@ -1299,7 +1299,7 @@ static lx_syscall_handler_t lx_handlers[] = { lx_close, /* 6: close */ NULL, /* 7: waitpid */ lx_creat, /* 8: creat */ - lx_link, /* 9: link */ + NULL, /* 9: link */ lx_unlink, /* 10: unlink */ lx_execve, /* 11: execve */ lx_chdir, /* 12: chdir */ @@ -1593,7 +1593,7 @@ static lx_syscall_handler_t lx_handlers[] = { NULL, /* 300: fstatat64 */ lx_unlinkat, /* 301: unlinkat */ lx_renameat, /* 302: renameat */ - lx_linkat, /* 303: linkat */ + NULL, /* 303: linkat */ lx_symlinkat, /* 304: symlinkat */ lx_readlinkat, /* 305: readlinkat */ NULL, /* 306: fchmodat */ diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h index a3f199dece..df68d4059f 100644 --- a/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h +++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h @@ -25,7 +25,7 @@ */ /* - * Copyright 2015 Joyent, Inc. All rights reserved. + * Copyright 2016 Joyent, Inc. */ #ifndef _SYS_LX_SYSCALL_H @@ -50,7 +50,6 @@ extern long lx_utimensat(uintptr_t, uintptr_t, uintptr_t, uintptr_t); extern long lx_fstatat64(uintptr_t, uintptr_t, uintptr_t, uintptr_t); extern long lx_unlinkat(uintptr_t, uintptr_t, uintptr_t); extern long lx_renameat(uintptr_t, uintptr_t, uintptr_t, uintptr_t); -extern long lx_linkat(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t); extern long lx_symlinkat(uintptr_t, uintptr_t, uintptr_t); extern long lx_readlinkat(uintptr_t, uintptr_t, uintptr_t, uintptr_t); extern long lx_access(uintptr_t, uintptr_t); @@ -144,7 +143,6 @@ extern long lx_ftruncate64(uintptr_t, uintptr_t, uintptr_t); extern long lx_sysctl(uintptr_t); extern long lx_fsync(uintptr_t); extern long lx_fdatasync(uintptr_t); -extern long lx_link(uintptr_t, uintptr_t); extern long lx_unlink(uintptr_t); extern long lx_rmdir(uintptr_t); extern long lx_rename(uintptr_t, uintptr_t); diff --git a/usr/src/uts/common/brand/lx/os/lx_syscall.c b/usr/src/uts/common/brand/lx/os/lx_syscall.c index de4caa9a66..c6076dbe6c 100644 --- a/usr/src/uts/common/brand/lx/os/lx_syscall.c +++ b/usr/src/uts/common/brand/lx/os/lx_syscall.c @@ -625,7 +625,7 @@ lx_sysent_t lx_sysent32[] = { {"close", lx_close, 0, 1}, /* 6 */ {"waitpid", lx_waitpid, 0, 3}, /* 7 */ {"creat", NULL, 0, 2}, /* 8 */ - {"link", NULL, 0, 2}, /* 9 */ + {"link", lx_link, 0, 2}, /* 9 */ {"unlink", NULL, 0, 1}, /* 10 */ {"execve", NULL, 0, 3}, /* 11 */ {"chdir", NULL, 0, 1}, /* 12 */ @@ -923,7 +923,7 @@ lx_sysent_t lx_sysent32[] = { {"fstatat64", lx_fstatat64, 0, 4}, /* 300 */ {"unlinkat", NULL, 0, 3}, /* 301 */ {"renameat", NULL, 0, 4}, /* 302 */ - {"linkat", NULL, 0, 5}, /* 303 */ + {"linkat", lx_linkat, 0, 5}, /* 303 */ {"symlinkat", NULL, 0, 3}, /* 304 */ {"readlinkat", NULL, 0, 4}, /* 305 */ {"fchmodat", lx_fchmodat, 0, 3}, /* 306 */ @@ -1073,7 +1073,7 @@ lx_sysent_t lx_sysent64[] = { {"mkdir", lx_mkdir, 0, 2}, /* 83 */ {"rmdir", NULL, 0, 1}, /* 84 */ {"creat", NULL, 0, 2}, /* 85 */ - {"link", NULL, 0, 2}, /* 86 */ + {"link", lx_link, 0, 2}, /* 86 */ {"unlink", NULL, 0, 1}, /* 87 */ {"symlink", NULL, 0, 2}, /* 88 */ {"readlink", NULL, 0, 3}, /* 89 */ @@ -1252,7 +1252,7 @@ lx_sysent_t lx_sysent64[] = { {"fstatat64", lx_fstatat64, 0, 4}, /* 262 */ {"unlinkat", NULL, 0, 3}, /* 263 */ {"renameat", NULL, 0, 4}, /* 264 */ - {"linkat", NULL, 0, 5}, /* 265 */ + {"linkat", lx_linkat, 0, 5}, /* 265 */ {"symlinkat", NULL, 0, 3}, /* 266 */ {"readlinkat", NULL, 0, 4}, /* 267 */ {"fchmodat", lx_fchmodat, 0, 3}, /* 268 */ diff --git a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h index 3636c8d718..03012d70d1 100644 --- a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h +++ b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h @@ -83,6 +83,8 @@ extern long lx_ioprio_set(); extern long lx_kill(); extern long lx_lchown(); extern long lx_lchown16(); +extern long lx_link(); +extern long lx_linkat(); extern long lx_lstat32(); extern long lx_lstat64(); extern long lx_mkdir(); diff --git a/usr/src/uts/common/brand/lx/syscall/lx_link.c b/usr/src/uts/common/brand/lx/syscall/lx_link.c new file mode 100644 index 0000000000..23e0768581 --- /dev/null +++ b/usr/src/uts/common/brand/lx/syscall/lx_link.c @@ -0,0 +1,97 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +#include <sys/fcntl.h> +#include <sys/errno.h> +#include <sys/file.h> +#include <sys/vnode.h> +#include <sys/systm.h> +#include <sys/lx_fcntl.h> + +#define LX_LINK_ALLOWED (LX_AT_SYMLINK_FOLLOW | LX_AT_EMPTY_PATH) + +static long +lx_link_common(int ffd, char *from, int tfd, char *to, int flags) +{ + int error; + vnode_t *fsvp = NULL, *tsvp = NULL; + enum symfollow follow = NO_FOLLOW; + + if ((flags & ~LX_LINK_ALLOWED) != 0) { + return (set_errno(EINVAL)); + } + if ((flags & LX_AT_EMPTY_PATH) == 0) { + char c; + + /* + * Check that both 'from' and 'to' names are non-empty if + * AT_EMPTY_PATH is not set. + */ + if (copyin(from, &c, sizeof (c)) != 0) { + return (set_errno(EFAULT)); + } else if (c == '\0') { + return (set_errno(ENOENT)); + } + if (copyin(to, &c, sizeof (c)) != 0) { + return (set_errno(EFAULT)); + } else if (c == '\0') { + return (set_errno(ENOENT)); + } + + /* + * XXX: When our support for LX capabilities improves, ENOENT + * should be thrown when a process lacking CAP_DAC_READ_SEARCH + * attempts to use the AT_EMPTY_PATH flag. + */ + } + if ((flags & LX_AT_SYMLINK_FOLLOW) != 0) { + follow = FOLLOW; + } + + if ((error = fgetstartvp(ffd, from, &fsvp)) != 0) { + goto out; + } + if ((error = fgetstartvp(tfd, to, &tsvp)) != 0) { + goto out; + } + error = vn_linkat(fsvp, from, follow, tsvp, to, UIO_USERSPACE); + +out: + if (fsvp != NULL) { + VN_RELE(fsvp); + } + if (tsvp != NULL) { + VN_RELE(tsvp); + } + if (error) { + return (set_errno(error)); + } + return (0); +} + +long +lx_link(char *from, char *to) +{ + return (lx_link_common(AT_FDCWD, from, AT_FDCWD, to, 0)); +} + +long +lx_linkat(int ffd, char *from, int tfd, char *to, int flags) +{ + ffd = (ffd == LX_AT_FDCWD) ? AT_FDCWD : ffd; + tfd = (tfd == LX_AT_FDCWD) ? AT_FDCWD : tfd; + + return (lx_link_common(ffd, from, tfd, to, flags)); +} diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files index 463b405341..b730774ac7 100644 --- a/usr/src/uts/intel/Makefile.files +++ b/usr/src/uts/intel/Makefile.files @@ -312,6 +312,7 @@ LX_BRAND_OBJS = \ lx_ioctl.o \ lx_ioprio.o \ lx_kill.o \ + lx_link.o \ lx_misc.o \ lx_mkdir.o \ lx_modify_ldt.o \ |