summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <pmooney@pfmooney.com>2016-01-15 20:49:19 +0000
committerPatrick Mooney <pmooney@pfmooney.com>2016-01-19 15:29:30 +0000
commit8843c35f721fa2818edf0a3ca6047c03d7021f30 (patch)
treee6b563e7f9b8e87e94d7a9dfbca89add9aa00f4f
parent8572d6e7175fb68fa8140a6d25fcaea6e81bc742 (diff)
downloadillumos-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.c74
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_brand.c8
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h4
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_syscall.c8
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_syscalls.h2
-rw-r--r--usr/src/uts/common/brand/lx/syscall/lx_link.c97
-rw-r--r--usr/src/uts/intel/Makefile.files1
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 \