summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/clone.c58
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/ioctl.c3
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_brand.c99
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/misc.c22
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/signal.c6
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/socket.c209
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/sysctl.c4
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/wait.c82
-rw-r--r--usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s6
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h4
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h4
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h58
-rw-r--r--usr/src/lib/brand/lx/lx_support/lx_support.c34
13 files changed, 521 insertions, 68 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/common/clone.c b/usr/src/lib/brand/lx/lx_brand/common/clone.c
index 726017809a..b6ec17e6ad 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/clone.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/clone.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -349,6 +349,7 @@ lx_clone(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
volatile int clone_res;
int sig;
int rval;
+ int pid;
lx_regs_t *rp;
sigset_t sigmask;
@@ -367,15 +368,38 @@ lx_clone(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
return (-EINVAL);
/*
- * CLONE_THREAD require CLONE_SIGHAND. CLONE_THREAD and
- * CLONE_DETACHED must both be either set or cleared.
+ * CLONE_THREAD requires CLONE_SIGHAND.
+ *
+ * CLONE_THREAD and CLONE_DETACHED must both be either set or cleared
+ * in kernel 2.4 and prior.
+ * In kernel 2.6 CLONE_DETACHED was dropped completely, so we no
+ * longer have this requirement.
*/
- if ((flags & CLONE_TD) &&
- (!(flags & LX_CLONE_SIGHAND) || ((flags & CLONE_TD) != CLONE_TD)))
- return (-EINVAL);
+
+ if (flags & CLONE_TD) {
+ if (!(flags & LX_CLONE_SIGHAND))
+ return (-EINVAL);
+ if ((lx_get_kern_version() <= LX_KERN_2_4) &&
+ (flags & CLONE_TD) != CLONE_TD)
+ return (-EINVAL);
+ }
rp = lx_syscall_regs();
+ /* test if pointer passed by user are writable */
+ if (flags & LX_CLONE_PARENT_SETTID) {
+ if (uucopy(ptidp, &pid, sizeof (int)) != 0)
+ return (-EFAULT);
+ if (uucopy(&pid, ptidp, sizeof (int)) != 0)
+ return (-EFAULT);
+ }
+ if (flags & LX_CLONE_CHILD_SETTID) {
+ if (uucopy(ctidp, &pid, sizeof (int)) != 0)
+ return (-EFAULT);
+ if (uucopy(&pid, ctidp, sizeof (int)) != 0)
+ return (-EFAULT);
+ }
+
/* See if this is a fork() operation or a thr_create(). */
if (IS_FORK(flags) || IS_VFORK(flags)) {
if (flags & LX_CLONE_PARENT) {
@@ -399,8 +423,26 @@ lx_clone(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4,
(void) sleep(lx_rpm_delay);
}
- if (rval > 0 && (flags & LX_CLONE_PARENT_SETTID))
- *((int *)ptidp) = rval;
+ /*
+ * Since we've already forked, we can't do much if uucopy fails,
+ * so we just ignore failure. Failure is unlikely since we've
+ * tested the memory before we did the fork.
+ */
+ if (rval > 0 && (flags & LX_CLONE_PARENT_SETTID)) {
+ (void) uucopy(&rval, ptidp, sizeof (int));
+ }
+
+ if (rval == 0 && (flags & LX_CLONE_CHILD_SETTID)) {
+ /*
+ * lx_getpid should not fail, and if it does, there's
+ * not much we can do about it since we've already
+ * forked, so on failure, we just don't copy the
+ * memory.
+ */
+ pid = lx_getpid();
+ if (pid >= 0)
+ (void) uucopy(&pid, ctidp, sizeof (int));
+ }
/* Parent just returns */
if (rval != 0)
diff --git a/usr/src/lib/brand/lx/lx_brand/common/ioctl.c b/usr/src/lib/brand/lx/lx_brand/common/ioctl.c
index 2be27b4237..2f2b022ed5 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/ioctl.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/ioctl.c
@@ -536,7 +536,7 @@ lx_ioctl(uintptr_t p1, uintptr_t p2, uintptr_t p3)
int cmd = (int)p2;
intptr_t arg = (uintptr_t)p3;
struct stat stat;
- ioc_cmd_translator_t *ict;
+ ioc_cmd_translator_t *ict = NULL;
ioc_errno_translator_t *iet = NULL;
major_t fd_major;
int i, ret;
@@ -561,7 +561,6 @@ lx_ioctl(uintptr_t p1, uintptr_t p2, uintptr_t p3)
switch (stat.st_mode & S_IFMT) {
default:
- ict = NULL;
break;
case S_IFREG:
/* Use file translators. */
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 9368ba0116..993f9faf73 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
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -165,7 +165,9 @@ struct lx_sysent {
char sy_narg;
};
-static struct lx_sysent sysents[LINUX_MAX_SYSCALL + 1];
+static struct lx_sysent sysents[LX_NSYSCALLS + 1];
+/* Differs for kernel versions, set during lx_init */
+static int lx_max_syscall;
static uintptr_t stack_bottom;
@@ -399,7 +401,7 @@ lx_emulate(lx_regs_t *rp)
syscall_num = rp->lxr_eax;
- if (syscall_num < 0 || syscall_num > LINUX_MAX_SYSCALL)
+ if (syscall_num < 0 || syscall_num > lx_max_syscall)
s = &sysents[0];
else
s = &sysents[syscall_num];
@@ -638,6 +640,23 @@ lx_init(int argc, char *argv[], char *envp[])
char locale_translated_name[MAXLOCALENAMELEN];
static lx_tsd_t lx_tsd;
+ /* Look up the PID that serves as init for this zone */
+ if ((err = lx_lpid_to_spid(1, &zoneinit_pid)) < 0)
+ lx_err_fatal(gettext(
+ "Unable to find PID for zone init process: %s"),
+ strerror(err));
+
+ /*
+ * Ubuntu init will fail if its TERM environment variable is not set
+ * so if we are running init, and TERM is not set, we set term and
+ * reexec so that the new environment variable is propagated to the
+ * linux application stack.
+ */
+ if ((getpid() == zoneinit_pid) && (getenv("TERM") == NULL)) {
+ if (setenv("TERM", "vt100", 1) < 0 || execv(argv[0], argv) < 0)
+ lx_err_fatal(gettext("failed to set TERM"));
+ }
+
if ((set_l10n_alternate_root("/native") == 0) &&
(setlocale(LC_ALL, lx_translate_locale(locale_translated_name,
sizeof (locale_translated_name))) != NULL) &&
@@ -659,11 +678,22 @@ lx_init(int argc, char *argv[], char *envp[])
lx_debug_init();
- r = getenv("LX_RELEASE");
- if (r == NULL)
- (void) strlcpy(lx_release, LX_UNAME_RELEASE, 128);
+ if (lx_get_kern_version() <= LX_KERN_2_4)
+ lx_max_syscall = LX_NSYSCALLS_2_4;
else
+ lx_max_syscall = LX_NSYSCALLS_2_6;
+
+ r = getenv("LX_RELEASE");
+ if (r == NULL) {
+ if (lx_get_kern_version() == LX_KERN_2_6)
+ (void) strlcpy(lx_release, LX_UNAME_RELEASE_2_6,
+ sizeof (lx_release));
+ else
+ (void) strlcpy(lx_release, LX_UNAME_RELEASE_2_4,
+ sizeof (lx_release));
+ } else {
(void) strlcpy(lx_release, r, 128);
+ }
lx_debug("lx_release: %s\n", lx_release);
@@ -803,12 +833,6 @@ lx_init(int argc, char *argv[], char *envp[])
"Unable to initialize thread-specific data: %s"),
strerror(err));
- /* Look up the PID that serves as init for this zone */
- if ((err = lx_lpid_to_spid(1, &zoneinit_pid)) < 0)
- lx_err_fatal(gettext(
- "Unable to find PID for zone init process: %s"),
- strerror(err));
-
/*
* Save the current context of this thread.
* We'll restore this context when this thread attempts to exit.
@@ -1227,5 +1251,54 @@ static struct lx_sysent sysents[] = {
{"clock_nanosleep", lx_clock_nanosleep, 0, 4}, /* 267 */
{"statfs64", lx_statfs64, 0, 2}, /* 268 */
{"fstatfs64", lx_fstatfs64, 0, 2}, /* 269 */
- {"tgkill", lx_tgkill, 0, 3} /* 270 */
+ {"tgkill", lx_tgkill, 0, 3}, /* 270 */
+
+ /* The following system calls only exist in kernel 2.6 and greater */
+ {"utimes", utimes, SYS_PASSTHRU, 2}, /* 271 */
+ {"fadvise64_64", NULL, NOSYS_NULL, 0}, /* 272 */
+ {"vserver", NULL, NOSYS_NULL, 0}, /* 273 */
+ {"mbind", NULL, NOSYS_NULL, 0}, /* 274 */
+ {"get_mempolicy", NULL, NOSYS_NULL, 0}, /* 275 */
+ {"set_mempolicy", NULL, NOSYS_NULL, 0}, /* 276 */
+ {"mq_open", NULL, NOSYS_NULL, 0}, /* 277 */
+ {"mq_unlink", NULL, NOSYS_NULL, 0}, /* 278 */
+ {"mq_timedsend", NULL, NOSYS_NULL, 0}, /* 279 */
+ {"mq_timedreceive", NULL, NOSYS_NULL, 0}, /* 280 */
+ {"mq_notify", NULL, NOSYS_NULL, 0}, /* 281 */
+ {"mq_getsetattr", NULL, NOSYS_NULL, 0}, /* 282 */
+ {"kexec_load", NULL, NOSYS_NULL, 0}, /* 283 */
+ {"waitid", lx_waitid, 0, 4}, /* 284 */
+ {"sys_setaltroot", NULL, NOSYS_NULL, 0}, /* 285 */
+ {"add_key", NULL, NOSYS_NULL, 0}, /* 286 */
+ {"request_key", NULL, NOSYS_NULL, 0}, /* 287 */
+ {"keyctl", NULL, NOSYS_NULL, 0}, /* 288 */
+ {"ioprio_set", NULL, NOSYS_NULL, 0}, /* 289 */
+ {"ioprio_get", NULL, NOSYS_NULL, 0}, /* 290 */
+ {"inotify_init", NULL, NOSYS_NULL, 0}, /* 291 */
+ {"inotify_add_watch", NULL, NOSYS_NULL, 0}, /* 292 */
+ {"inotify_rm_watch", NULL, NOSYS_NULL, 0}, /* 293 */
+ {"migrate_pages", NULL, NOSYS_NULL, 0}, /* 294 */
+ {"openat", NULL, NOSYS_NULL, 0}, /* 295 */
+ {"mkdirat", NULL, NOSYS_NULL, 0}, /* 296 */
+ {"mknodat", NULL, NOSYS_NULL, 0}, /* 297 */
+ {"fchownat", NULL, NOSYS_NULL, 0}, /* 298 */
+ {"futimesat", NULL, NOSYS_NULL, 0}, /* 299 */
+ {"fstatat64", NULL, NOSYS_NULL, 0}, /* 300 */
+ {"unlinkat", NULL, NOSYS_NULL, 0}, /* 301 */
+ {"renameat", NULL, NOSYS_NULL, 0}, /* 302 */
+ {"linkat", NULL, NOSYS_NULL, 0}, /* 303 */
+ {"symlinkat", NULL, NOSYS_NULL, 0}, /* 304 */
+ {"readlinkat", NULL, NOSYS_NULL, 0}, /* 305 */
+ {"fchmodat", NULL, NOSYS_NULL, 0}, /* 306 */
+ {"faccessat", NULL, NOSYS_NULL, 0}, /* 307 */
+ {"pselect6", NULL, NOSYS_NULL, 0}, /* 308 */
+ {"ppoll", NULL, NOSYS_NULL, 0}, /* 309 */
+ {"unshare", NULL, NOSYS_NULL, 0}, /* 310 */
+ {"set_robust_list", NULL, NOSYS_NULL, 0}, /* 311 */
+ {"get_robust_list", NULL, NOSYS_NULL, 0}, /* 312 */
+ {"splice", NULL, NOSYS_NULL, 0}, /* 313 */
+ {"sync_file_range", NULL, NOSYS_NULL, 0}, /* 314 */
+ {"tee", NULL, NOSYS_NULL, 0}, /* 315 */
+ {"vmsplice", NULL, NOSYS_NULL, 0}, /* 316 */
+ {"move_pages", NULL, NOSYS_NULL, 0}, /* 317 */
};
diff --git a/usr/src/lib/brand/lx/lx_brand/common/misc.c b/usr/src/lib/brand/lx/lx_brand/common/misc.c
index 77cf94d194..c6cceb1577 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/misc.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/misc.c
@@ -46,6 +46,7 @@
#include <sys/lx_thunk_server.h>
#include <unistd.h>
#include <libintl.h>
+#include <zone.h>
extern int sethostname(char *, int);
@@ -184,6 +185,27 @@ lx_getcwd(uintptr_t p1, uintptr_t p2)
}
int
+lx_get_kern_version(void)
+{
+ /*
+ * Since this function is called quite often, and zone_getattr is slow,
+ * we cache the kernel version in kvers_cache. -1 signifies that no
+ * value has yet been cached.
+ */
+ static int kvers_cache = -1;
+ /* dummy variable for use in zone_getattr */
+ int kvers;
+
+ if (kvers_cache != -1)
+ return (kvers_cache);
+ if (zone_getattr(getzoneid(), LX_KERN_VERSION_NUM, &kvers, sizeof (int))
+ != sizeof (int))
+ return (kvers_cache = LX_KERN_2_4);
+ else
+ return (kvers_cache = kvers);
+}
+
+int
lx_uname(uintptr_t p1)
{
struct lx_utsname *un = (struct lx_utsname *)p1;
diff --git a/usr/src/lib/brand/lx/lx_brand/common/signal.c b/usr/src/lib/brand/lx/lx_brand/common/signal.c
index 119961c0d8..c6ac519e19 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/signal.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/signal.c
@@ -390,7 +390,7 @@ stol_sigcode(int si_code)
}
}
-static int
+int
stol_siginfo(siginfo_t *siginfop, lx_siginfo_t *lx_siginfop)
{
lx_siginfo_t lx_siginfo;
@@ -535,7 +535,7 @@ lx_sigaltstack(uintptr_t nsp, uintptr_t osp)
if (nsp) {
if (uucopy((void *)nsp, &ls, sizeof (lx_stack_t)) != 0)
- return (-errno);
+ return (-errno);
if ((ls.ss_flags & LX_SS_DISABLE) == 0 &&
ls.ss_size < LX_MINSIGSTKSZ)
@@ -1677,7 +1677,7 @@ lx_siginit(void)
if (sa.sa_handler == SIG_IGN) {
lx_debug("marking signal %d (lx %d) as SIG_IGN",
- sig, lx_sig);
+ sig, lx_sig);
lx_sighandlers.lx_sa[lx_sig].lxsa_handler = SIG_IGN;
}
}
diff --git a/usr/src/lib/brand/lx/lx_brand/common/socket.c b/usr/src/lib/brand/lx/lx_brand/common/socket.c
index 009018d8fe..41b84b6f4b 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/socket.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/socket.c
@@ -31,6 +31,7 @@
#include <errno.h>
#include <signal.h>
#include <stdio.h>
+#include <stdlib.h>
#include <libintl.h>
#include <strings.h>
#include <alloca.h>
@@ -52,6 +53,14 @@
#include <sys/lx_brand.h>
#include <sys/lx_misc.h>
+/*
+ * This string is used to prefix all abstract namespace unix sockets, ie all
+ * abstract namespace sockets are converted to regular sockets in the /tmp
+ * directory with .ABSK_ prefixed to their names.
+ */
+#define ABST_PRFX "/tmp/.ABSK_"
+#define ABST_PRFX_LEN 11
+
static int lx_socket(ulong_t *);
static int lx_bind(ulong_t *);
static int lx_connect(ulong_t *);
@@ -283,6 +292,11 @@ convert_cmsgs(int direction, struct lx_msghdr *msg, char *caller)
return (err);
}
+/*
+ * If inaddr is an abstract namespace unix socket, this function expects addr
+ * to have enough memory to hold the expanded socket name, ie it must be of
+ * size *len + ABST_PRFX_LEN.
+ */
static int
convert_sockaddr(struct sockaddr *addr, socklen_t *len,
struct sockaddr *inaddr, socklen_t inlen)
@@ -290,6 +304,7 @@ convert_sockaddr(struct sockaddr *addr, socklen_t *len,
sa_family_t family;
int lx_in6_len;
int size;
+ int i, orig_len;
/*
* Note that if the buffer at inaddr is ever smaller than inlen bytes,
@@ -341,6 +356,66 @@ convert_sockaddr(struct sockaddr *addr, socklen_t *len,
return (-EINVAL);
*len = inlen;
+
+ /*
+ * Linux supports abstract unix sockets, which are
+ * simply sockets that do not exist on the file system.
+ * These sockets are denoted by beginning the path with
+ * a NULL character. To support these, we strip out the
+ * leading NULL character and change the path to point
+ * to a real place in /tmp directory, by prepending
+ * ABST_PRFX and replacing all illegal characters with
+ * '_'.
+ */
+ if (addr->sa_data[0] == '\0') {
+
+ /*
+ * inlen is the entire size of the sockaddr_un
+ * data structure, including the sun_family, so
+ * we need to subtract this out. We subtract
+ * 1 since we want to overwrite the leadin NULL
+ * character, and thus do not include it in the
+ * length.
+ */
+ orig_len = inlen - sizeof (addr->sa_family) - 1;
+
+ /*
+ * Since abstract paths can contain illegal
+ * filename characters, we simply replace these
+ * with '_'
+ */
+ for (i = 1; i < orig_len + 1; i++) {
+ if (addr->sa_data[i] == '\0' ||
+ addr->sa_data[i] == '/')
+ addr->sa_data[i] = '_';
+ }
+
+ /*
+ * prepend ABST_PRFX to file name, minus the
+ * leading NULL character. This places the
+ * socket as a hidden file in the /tmp
+ * directory.
+ */
+ (void) memmove(addr->sa_data + ABST_PRFX_LEN,
+ addr->sa_data + 1, orig_len);
+ bcopy(ABST_PRFX, addr->sa_data, ABST_PRFX_LEN);
+
+ /*
+ * Since abstract socket paths may not be NULL
+ * terminated, we must explicitly NULL terminate
+ * our string.
+ */
+ addr->sa_data[orig_len + ABST_PRFX_LEN] = '\0';
+
+ /*
+ * Make len reflect the new len of our string.
+ * Although we removed the NULL character at the
+ * beginning of the string, we added a NULL
+ * character to the end, so the net gain in
+ * length is simply ABST_PRFX_LEN.
+ */
+ *len = inlen + ABST_PRFX_LEN;
+ }
break;
default:
@@ -453,6 +528,22 @@ lx_socket(ulong_t *args)
/* Right now IPv6 sockets don't work */
if (domain == AF_INET6)
return (-EAFNOSUPPORT);
+
+ /*
+ * Clients of the auditing subsystem used by CentOS 4 and 5 expect to
+ * be able to create AF_ROUTE SOCK_RAW sockets to communicate with the
+ * auditing daemons. Failure to create these sockets will cause login,
+ * ssh and useradd, amoung other programs to fail. To trick these
+ * programs into working, we convert the socket domain and type to
+ * something that we do support. Then when sendto is called on these
+ * sockets, we return an error code. See lx_sendto.
+ */
+ if (domain == AF_ROUTE && type == SOCK_RAW) {
+ domain = AF_INET;
+ type = SOCK_STREAM;
+ protocol = 0;
+ }
+
fd = socket(domain, type, protocol);
if (fd >= 0)
return (fd);
@@ -468,16 +559,71 @@ lx_bind(ulong_t *args)
{
int sockfd = (int)args[0];
struct stat64 statbuf;
- struct sockaddr *name;
+ struct sockaddr *name, oldname;
socklen_t len;
- int r;
+ int r, r2, ret, tmperrno;
+ int abst_sock;
+ struct stat sb;
+
+ if (uucopy((struct sockaddr *)args[1], &oldname,
+ sizeof (struct sockaddr)) != 0)
+ return (-errno);
+
+ /*
+ * Handle Linux abstract sockets, which are UNIX sockets whose path
+ * begins with a NULL character.
+ */
+ abst_sock = (oldname.sa_family == AF_UNIX) &&
+ (oldname.sa_data[0] == '\0');
- if ((name = SAFE_ALLOCA((socklen_t)args[2])) == NULL)
+ /*
+ * convert_sockaddr will expand the socket path if it is abstract, so
+ * we need to allocate extra memory for it now.
+ */
+ if ((name = SAFE_ALLOCA((socklen_t)args[2] +
+ abst_sock * ABST_PRFX_LEN)) == NULL)
return (-EINVAL);
+
if ((r = convert_sockaddr(name, &len, (struct sockaddr *)args[1],
(socklen_t)args[2])) < 0)
return (r);
+ /*
+ * Linux abstract namespace unix sockets are simply socket that do not
+ * exist on the filesystem. We emulate them by changing their paths
+ * in covert_sockaddr so that they point real files names on the
+ * filesystem. Because in Linux they do not exist on the filesystem
+ * applications do not have to worry about deleting files, however in
+ * our filesystem based emulation we do. To solve this problem, we first
+ * check to see if the socket already exists before we create one. If it
+ * does we attempt to connect to it to see if it is in use, or just
+ * left over from a previous lx_bind call. If we are unable to connect,
+ * we assume it is not in use and remove the file, then continue on
+ * as if the file never existed.
+ */
+ if (abst_sock && stat(name->sa_data, &sb) == 0 &&
+ S_ISSOCK(sb.st_mode)) {
+ if ((r2 = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
+ return (-ENOSR);
+ ret = connect(r2, name, len);
+ tmperrno = errno;
+ if (close(r2) < 0)
+ return (-EINVAL);
+
+ /*
+ * if we can't connect to the socket, assume no one is using it
+ * and remove it, otherwise assume it is in use and return
+ * EADDRINUSE.
+ */
+ if ((ret < 0) && (tmperrno == ECONNREFUSED)) {
+ if (unlink(name->sa_data) < 0) {
+ return (-EADDRINUSE);
+ }
+ } else {
+ return (-EADDRINUSE);
+ }
+ }
+
lx_debug("\tbind(%d, 0x%p, %d)", sockfd, name, len);
if (name->sa_family == AF_UNIX)
@@ -501,11 +647,26 @@ static int
lx_connect(ulong_t *args)
{
int sockfd = (int)args[0];
- struct sockaddr *name;
+ struct sockaddr *name, oldname;
socklen_t len;
int r;
+ int abst_sock;
+
+ if (uucopy((struct sockaddr *)args[1], &oldname,
+ sizeof (struct sockaddr)) != 0)
+ return (-errno);
+
- if ((name = SAFE_ALLOCA((socklen_t)args[2])) == NULL)
+ /* Handle Linux abstract sockets */
+ abst_sock = (oldname.sa_family == AF_UNIX) &&
+ (oldname.sa_data[0] == '\0');
+
+ /*
+ * convert_sockaddr will expand the socket path, if it is abstract, so
+ * we need to allocate extra memory for it now.
+ */
+ if ((name = SAFE_ALLOCA((socklen_t)args[2] +
+ abst_sock * ABST_PRFX_LEN)) == NULL)
return (-EINVAL);
if ((r = convert_sockaddr(name, &len, (struct sockaddr *)args[1],
@@ -805,25 +966,44 @@ lx_sendto(ulong_t *args)
void *buf = (void *)args[1];
size_t len = (size_t)args[2];
int flags = (int)args[3];
- struct sockaddr *to;
+ struct sockaddr *to, oldto;
socklen_t tolen;
ssize_t r;
+ int abst_sock;
int nosigpipe = flags & LX_MSG_NOSIGNAL;
struct sigaction newact, oact;
- if ((to = SAFE_ALLOCA((socklen_t)args[5])) == NULL)
+ if (uucopy((struct sockaddr *)args[4], &oldto,
+ sizeof (struct sockaddr)) != 0)
+ return (-errno);
+
+ /* Handle Linux abstract sockets */
+ abst_sock = (oldto.sa_family == AF_UNIX) &&
+ (oldto.sa_data[0] == '\0');
+
+ /*
+ * convert_sockaddr will expand the socket path, if it is abstract, so
+ * we need to allocate extra memory for it now.
+ */
+ if ((to = SAFE_ALLOCA(args[5] + abst_sock * ABST_PRFX_LEN)) == NULL)
return (-EINVAL);
if ((r = convert_sockaddr(to, &tolen, (struct sockaddr *)args[4],
(socklen_t)args[5])) < 0)
return (r);
+
lx_debug("\tsendto(%d, 0x%p, 0x%d, 0x%x, 0x%x, %d)", sockfd, buf, len,
flags, to, tolen);
flags = convert_sockflags(flags);
+ /* return this error to make auditing subsystem happy */
+ if (to->sa_family == AF_ROUTE) {
+ return (-ECONNREFUSED);
+ }
+
/*
* If nosigpipe is set, we want to emulate the Linux action of
* not sending a SIGPIPE to the caller if the remote socket has
@@ -959,6 +1139,14 @@ lx_setsockopt(ulong_t *args)
optname <= 0 || optname >= (ltos_proto_opts[level].maxentries))
return (-ENOPROTOOPT);
+ /*
+ * Linux sets this option when it wants to send credentials over a
+ * socket. Currently we just ignore it to make Linux programs happy.
+ */
+ if ((level == LX_SOL_SOCKET) && (optname == LX_SO_PASSCRED))
+ return (0);
+
+
if ((level == IPPROTO_TCP) && (optname == LX_TCP_CORK)) {
/*
* TCP_CORK is a Linux-only option that instructs the TCP
@@ -1024,8 +1212,13 @@ lx_getsockopt(ulong_t *args)
optname <= 0 || optname >= (ltos_proto_opts[level].maxentries))
return (-ENOPROTOOPT);
- if ((level == IPPROTO_TCP) && (optname == LX_TCP_CORK)) {
+ if ((level == LX_SOL_SOCKET) && (optname == LX_SO_PASSCRED) ||
+ (level == IPPROTO_TCP) && (optname == LX_TCP_CORK)) {
/*
+ * Linux sets LX_SO_PASSCRED when it wants to send credentials
+ * over a socket. Since we do not support it, it is never set
+ * and we return 0.
+ *
* We don't support TCP_CORK but some apps rely on it. So,
* rather than return an error we just return 0. This
* isn't exactly a lie, since this option really isn't set,
diff --git a/usr/src/lib/brand/lx/lx_brand/common/sysctl.c b/usr/src/lib/brand/lx/lx_brand/common/sysctl.c
index 03fcce4ef0..1cf4ca3ac1 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/sysctl.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/sysctl.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -118,7 +118,7 @@ lx_sysctl(uintptr_t raw)
(void) strlcpy(namebuf, LX_UNAME_SYSNAME, oldlen);
break;
case LX_KERN_OSRELEASE:
- (void) strlcpy(namebuf, LX_UNAME_RELEASE, oldlen);
+ (void) strlcpy(namebuf, lx_release, oldlen);
break;
case LX_KERN_VERSION:
(void) strlcpy(namebuf, LX_UNAME_VERSION, oldlen);
diff --git a/usr/src/lib/brand/lx/lx_brand/common/wait.c b/usr/src/lib/brand/lx/lx_brand/common/wait.c
index 0895e76bc0..33b3d49923 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/wait.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/wait.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -91,6 +91,10 @@
#define LX_WALL 0x40000000
#define LX_WCLONE 0x80000000
+#define LX_P_ALL 0x0
+#define LX_P_PID 0x1
+#define LX_P_GID 0x2
+
static int
ltos_options(uintptr_t options)
{
@@ -143,6 +147,36 @@ lx_wstat(int code, int status)
return (stat);
}
+/* wrapper to make solaris waitid work properly with ptrace */
+static int
+lx_waitid_helper(idtype_t idtype, id_t id, siginfo_t *info, int options)
+{
+ do {
+ /*
+ * It's possible that we return EINVAL here if the idtype is
+ * P_PID or P_PGID and id is out of bounds for a valid pid or
+ * pgid, but Linux expects to see ECHILD. No good way occurs to
+ * handle this so we'll punt for now.
+ */
+ if (waitid(idtype, id, info, options) < 0)
+ return (-errno);
+
+ /*
+ * If the WNOHANG flag was specified and no child was found
+ * return 0.
+ */
+ if ((options & WNOHANG) && info->si_pid == 0)
+ return (0);
+
+ /*
+ * It's possible that we may have a spurious return for one of
+ * the child processes created by the ptrace subsystem. If
+ * that's the case, we simply try again.
+ */
+ } while (lx_ptrace_wait(info) == -1);
+ return (0);
+}
+
int
lx_wait4(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
{
@@ -195,30 +229,14 @@ lx_wait4(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
options |= WEXITED | WTRAPPED;
-again:
- /*
- * It's possible that we return EINVAL here if the idtype is P_PID or
- * P_PGID and id is out of bounds for a valid pid or pgid, but Linux
- * expects to see ECHILD. No good way occurs to handle this so we'll
- * punt for now.
- */
- if (waitid(idtype, id, &info, options) < 0)
- return (-errno);
-
+ if ((rval = lx_waitid_helper(idtype, id, &info, options)) < 0)
+ return (rval);
/*
* If the WNOHANG flag was specified and no child was found return 0.
*/
if ((options & WNOHANG) && info.si_pid == 0)
return (0);
- /*
- * It's possible that we may have a spurious return for one of the
- * child processes created by the ptrace subsystem. In that's the case,
- * we simply try again.
- */
- if (lx_ptrace_wait(&info) == -1)
- goto again;
-
status = lx_wstat(info.si_code, info.si_status);
/*
@@ -242,3 +260,29 @@ lx_waitpid(uintptr_t p1, uintptr_t p2, uintptr_t p3)
{
return (lx_wait4(p1, p2, p3, NULL));
}
+
+int
+lx_waitid(uintptr_t idtype, uintptr_t id, uintptr_t infop, uintptr_t opt)
+{
+ int rval, options;
+ siginfo_t s_infop = {0};
+ if ((options = ltos_options(opt)) == -1)
+ return (-1);
+ switch (idtype) {
+ case LX_P_ALL:
+ idtype = P_ALL;
+ break;
+ case LX_P_PID:
+ idtype = P_PID;
+ break;
+ case LX_P_GID:
+ idtype = P_GID;
+ break;
+ default:
+ return (-EINVAL);
+ }
+ if ((rval = lx_waitid_helper(idtype, (id_t)id, &s_infop, options)) < 0)
+ return (rval);
+
+ return (stol_siginfo(&s_infop, (lx_siginfo_t *)infop));
+}
diff --git a/usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s b/usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s
index b55eec5855..413ef9852d 100644
--- a/usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s
+++ b/usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -126,13 +126,13 @@ lx_sigreturn_tolibc(uintptr_t sp)
.align 16
ENTRY_NP(lx_handler_trace_table)
TJMP256
- TJMP16
+ TJMP64
SET_SIZE(lx_handler_trace_table)
.align 16
ENTRY_NP(lx_handler_table)
JMP256
- JMP16
+ JMP64
SET_SIZE(lx_handler_table)
ENTRY_NP(lx_handler_trace)
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h
index 68ea113600..2954275c75 100644
--- a/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_misc.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -127,6 +127,8 @@ extern int lx_lpid_to_spid(pid_t, pid_t *);
extern int lx_ptrace_wait(siginfo_t *);
extern void lx_ptrace_fork(void);
+extern int lx_get_kern_version(void);
+
extern int lx_check_alloca(size_t);
#define SAFE_ALLOCA(sz) (lx_check_alloca(sz) ? alloca(sz) : NULL)
diff --git a/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h b/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h
index 981c7d1ad2..b7609962ae 100644
--- a/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h
+++ b/usr/src/lib/brand/lx/lx_brand/sys/lx_signal.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -288,6 +288,8 @@ extern void lx_sigreturn_tolibc(uintptr_t);
extern void lx_sigdeliver(int, siginfo_t *, void *, size_t, void (*)(),
void (*)(), uintptr_t);
+extern int stol_siginfo(siginfo_t *siginfop, lx_siginfo_t *lx_siginfop);
+
#endif /* !defined(_ASM) */
#ifdef __cplusplus
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 241faf7c5b..5c52b1acec 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
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,6 +32,7 @@
#if !defined(_ASM)
#include <sys/types.h>
+#include <sys/procset.h>
#ifdef __cplusplus
extern "C" {
@@ -82,6 +83,7 @@ extern int lx_setgroups(uintptr_t, uintptr_t);
extern int lx_waitpid(uintptr_t, uintptr_t, uintptr_t);
+extern int lx_waitid(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern int lx_wait4(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern int lx_getuid16(void);
@@ -193,6 +195,9 @@ extern int lx_rt_sigtimedwait(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern int lx_sync(void);
+extern int lx_futex(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
+ uintptr_t);
+
extern int lx_tkill(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t,
uintptr_t);
extern int lx_tgkill(uintptr_t, uintptr_t, uintptr_t);
@@ -222,12 +227,13 @@ extern int lx_sched_setscheduler(uintptr_t, uintptr_t, uintptr_t);
extern int lx_sched_get_priority_min(uintptr_t);
extern int lx_sched_get_priority_max(uintptr_t);
+extern int lx_keyctl(void);
+
extern int lx_ipc(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
#endif /* !defined(_ASM) */
#define EBP_HAS_ARG6 0x01
-#define LINUX_MAX_SYSCALL 270
/*
* Linux syscall numbers
@@ -481,6 +487,54 @@ extern int lx_ipc(uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
#define LX_SYS_clock_getres 266
#define LX_SYS_clock_nanosleep 267
#define LX_SYS_tgkill 270
+/* the following syscalls are for 2.6 and later kernels */
+#define LX_SYS_utimes 271
+#define LX_SYS_fadvise64_64 272
+#define LX_SYS_vserver 273
+#define LX_SYS_mbind 274
+#define LX_SYS_get_mempolicyd 275
+#define LX_SYS_set_mempolicy 276
+#define LX_SYS_mq_open 277
+#define LX_SYS_mq_unlink 278
+#define LX_SYS_mq_timedsend 279
+#define LX_SYS_mq_timedreceive 280
+#define LX_SYS_mq_notify 281
+#define LX_SYS_mq_getsetattr 282
+#define LX_SYS_kexec_load 283
+#define LX_SYS_waitid 284
+#define LX_SYS_setaltroot 285
+#define LX_SYS_add_key 286
+#define LX_SYS_request_key 287
+#define LX_SYS_keyctl 288
+#define LX_SYS_ioprio_set 289
+#define LX_SYS_ioprio_get 290
+#define LX_SYS_inotify_init 291
+#define LX_SYS_inotify_add_watch 292
+#define LX_SYS_inotify_rm_watch 293
+#define LX_SYS_migrate_pages 294
+#define LX_SYS_openat 295
+#define LX_SYS_mkdirat 296
+#define LX_SYS_mknodat 297
+#define LX_SYS_fchownat 298
+#define LX_SYS_futimesat 299
+#define LX_SYS_fstatat64 300
+#define LX_SYS_unlinkat 301
+#define LX_SYS_renameat 302
+#define LX_SYS_linkat 303
+#define LX_SYS_symlinkat 304
+#define LX_SYS_readlinkat 305
+#define LX_SYS_fchmodat 306
+#define LX_SYS_faccessat 307
+#define LX_SYS_pselect6 308
+#define LX_SYS_ppoll 309
+#define LX_SYS_unshare 310
+#define LX_SYS_set_robust_list 311
+#define LX_SYS_get_robust_list 312
+#define LX_SYS_splice 313
+#define LX_SYS_sync_file_range 314
+#define LX_SYS_tee 315
+#define LX_SYS_vmsplice 316
+#define LX_SYS_move_pages 317
#ifdef __cplusplus
}
diff --git a/usr/src/lib/brand/lx/lx_support/lx_support.c b/usr/src/lib/brand/lx/lx_support/lx_support.c
index 714fc38e50..20e6a1bf71 100644
--- a/usr/src/lib/brand/lx/lx_support/lx_support.c
+++ b/usr/src/lib/brand/lx/lx_support/lx_support.c
@@ -177,7 +177,7 @@ lxs_remove_autofsck()
*/
static void
lxs_getattrs(zone_dochandle_t zdh, boolean_t *restart, boolean_t *audio,
- char **idev, char **odev)
+ char **idev, char **odev, char **kvers)
{
struct zone_attrtab attrtab;
int err;
@@ -190,13 +190,15 @@ lxs_getattrs(zone_dochandle_t zdh, boolean_t *restart, boolean_t *audio,
*idev = (char *)malloc(INTSTRLEN);
*odev = (char *)malloc(INTSTRLEN);
- if (*idev == NULL || *odev == NULL)
+ *kvers = (char *)malloc(INTSTRLEN);
+ if (*idev == NULL || *odev == NULL || *kvers == NULL)
lxs_err(gettext("out of memory"));
*audio = B_FALSE;
*restart = B_FALSE;
bzero(*idev, INTSTRLEN);
bzero(*odev, INTSTRLEN);
+ bzero(*kvers, INTSTRLEN);
while ((err = zonecfg_getattrent(zdh, &attrtab)) == Z_OK) {
if ((strcmp(attrtab.zone_attr_name, "init-restart") == 0) &&
(zonecfg_get_attr_boolean(&attrtab, restart) != Z_OK))
@@ -216,6 +218,11 @@ lxs_getattrs(zone_dochandle_t zdh, boolean_t *restart, boolean_t *audio,
INTSTRLEN) != Z_OK))
lxs_err(gettext("invalid type for zone attribute: %s"),
attrtab.zone_attr_name);
+ if ((strcmp(attrtab.zone_attr_name, "kernel-version") == 0) &&
+ (zonecfg_get_attr_string(&attrtab, *kvers,
+ INTSTRLEN) != Z_OK))
+ lxs_err(gettext("invalid type for zone attribute: %s"),
+ attrtab.zone_attr_name);
}
/* some kind of error while looking up attributes */
@@ -336,7 +343,8 @@ lxs_boot()
zoneid_t zoneid;
zone_dochandle_t zdh;
boolean_t audio, restart;
- char *idev, *odev;
+ char *idev, *odev, *kvers;
+ int kversnum;
lxs_make_initctl();
lxs_remove_autofsck();
@@ -350,7 +358,7 @@ lxs_boot()
}
/* Extract any relevant attributes from the config file. */
- lxs_getattrs(zdh, &restart, &audio, &idev, &odev);
+ lxs_getattrs(zdh, &restart, &audio, &idev, &odev, &kvers);
zonecfg_fini_handle(zdh);
/* Configure the zone's audio support (if any). */
@@ -367,6 +375,15 @@ lxs_boot()
sizeof (boolean_t)) == -1)
lxs_err(gettext("error setting zone's restart_init property"));
+ if ((kvers != NULL) && (strcmp(kvers, "2.6") == 0))
+ kversnum = LX_KERN_2_6;
+ else
+ kversnum = LX_KERN_2_4;
+
+ if (zone_setattr(zoneid, LX_KERN_VERSION_NUM, &kversnum,
+ sizeof (int)) < 0)
+ lxs_err(gettext("unable to set kernel version"));
+
return (0);
}
@@ -419,7 +436,7 @@ lxs_verify(char *xmlfile)
struct zone_dstab dstab;
struct zone_devtab devtab;
boolean_t audio, restart;
- char *idev, *odev;
+ char *idev, *odev, *kvers;
zone_iptype_t iptype;
if ((handle = zonecfg_init_handle()) == NULL)
@@ -485,7 +502,7 @@ lxs_verify(char *xmlfile)
}
/* Extract any relevant attributes from the config file. */
- lxs_getattrs(handle, &restart, &audio, &idev, &odev);
+ lxs_getattrs(handle, &restart, &audio, &idev, &odev, &kvers);
zonecfg_fini_handle(handle);
if (audio) {
@@ -498,6 +515,11 @@ lxs_verify(char *xmlfile)
lxs_err(gettext("invalid value for zone attribute: %s"),
"audio-outputdev");
}
+ if (kvers) {
+ if ((strcmp(kvers, "2.4")) != 0 && (strcmp(kvers, "2.6") != 0))
+ lxs_err(gettext("invalid value for zone attribute: %s"),
+ "kernel-version");
+ }
return (0);
}