summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Jelinek <jerry.jelinek@joyent.com>2016-11-22 14:12:56 +0000
committerJerry Jelinek <jerry.jelinek@joyent.com>2016-11-26 14:49:24 +0000
commita434634703d530e1a12fdabde4691c73a93ca8b5 (patch)
treeed4cf9954365af5b3bec0ecbbc6108cd5b56ef6f
parent91bad8da9e9cc8662d6c49ddbdc16359f2502be4 (diff)
downloadillumos-joyent-a434634703d530e1a12fdabde4691c73a93ca8b5.tar.gz
OS-5802 LTP setpriority02 now failing
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Approved by: Patrick Mooney <patrick.mooney@joyent.com>
-rw-r--r--usr/src/lib/brand/lx/lx_brand/Makefile.com1
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_brand.c8
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/priority.c117
-rw-r--r--usr/src/lib/brand/lx/lx_brand/sys/lx_syscall.h3
-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_priority.c192
-rw-r--r--usr/src/uts/common/disp/priocntl.c4
-rw-r--r--usr/src/uts/intel/Makefile.files1
9 files changed, 205 insertions, 131 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/Makefile.com b/usr/src/lib/brand/lx/lx_brand/Makefile.com
index 53f5246834..262356884f 100644
--- a/usr/src/lib/brand/lx/lx_brand/Makefile.com
+++ b/usr/src/lib/brand/lx/lx_brand/Makefile.com
@@ -43,7 +43,6 @@ COBJS = aio.o \
module.o \
mount.o \
mount_nfs.o \
- priority.o \
ptrace.o \
sendfile.o \
signal.o \
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 5724b6cbba..200df187ae 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
@@ -1151,8 +1151,8 @@ static lx_syscall_handler_t lx_handlers[] = {
lx_statfs, /* 137: statfs */
lx_fstatfs, /* 138: fstatfs */
lx_sysfs, /* 139: sysfs */
- lx_getpriority, /* 140: getpriority */
- lx_setpriority, /* 141: setpriority */
+ NULL, /* 140: getpriority */
+ NULL, /* 141: setpriority */
NULL, /* 142: sched_setparam */
NULL, /* 143: sched_getparam */
NULL, /* 144: sched_setscheduler */
@@ -1438,8 +1438,8 @@ static lx_syscall_handler_t lx_handlers[] = {
lx_ftruncate, /* 93: ftruncate */
NULL, /* 94: fchmod */
NULL, /* 95: fchown16 */
- lx_getpriority, /* 96: getpriority */
- lx_setpriority, /* 97: setpriority */
+ NULL, /* 96: getpriority */
+ NULL, /* 97: setpriority */
NULL, /* 98: profil */
lx_statfs, /* 99: statfs */
lx_fstatfs, /* 100: fstatfs */
diff --git a/usr/src/lib/brand/lx/lx_brand/common/priority.c b/usr/src/lib/brand/lx/lx_brand/common/priority.c
deleted file mode 100644
index 5974abe40e..0000000000
--- a/usr/src/lib/brand/lx/lx_brand/common/priority.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-
-/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
- * Use is subject to license terms.
- * Copyright 2015 Joyent, Inc. All rights reserved.
- */
-
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/lx_debug.h>
-#include <sys/lx_misc.h>
-#include <sys/lx_syscall.h>
-#include <sys/lx_types.h>
-#include <sys/resource.h>
-#include <sys/lx_misc.h>
-#include <sched.h>
-
-/*
- * The Linux syscall returns priorities in the range (lowest) 40-1 (highest)
- * and then glibc adjusts these to the range -20 - 19.
- */
-long
-lx_getpriority(uintptr_t p1, uintptr_t p2)
-{
- int which = (int)p1;
- id_t who = (id_t)p2;
- int ret;
-
- /*
- * The only valid values for 'which' are positive integers, and unlike
- * Solaris, linux doesn't support anything past PRIO_USER.
- */
- if (which < 0 || which > PRIO_USER)
- return (-EINVAL);
-
- lx_debug("\tgetpriority(%d, %d)", which, who);
-
- errno = 0;
-
- if ((which == PRIO_PROCESS) && (who == 1))
- who = zoneinit_pid;
-
- ret = getpriority(which, who);
- if (ret == -1 && errno != 0) {
- pid_t mypid = getpid();
-
- if (which == PRIO_PROCESS &&
- (who == mypid || who == 0 || who == P_MYID) &&
- sched_getscheduler(mypid) == SCHED_RR) {
- /*
- * The getpriority kernel handling will always return
- * an error if we're in the RT class. The zone itself
- * won't be able to put itself or any of its processes
- * into RT but if we put the whole zone into RT via
- * the scheduling-class property, then getpriority will
- * always fail. This breaks pam and prevents any login.
- * Just pretend to be the highest priority.
- */
- return (1);
- }
-
- /*
- * Linux does not return EINVAL for invalid 'who' values, it
- * returns ESRCH instead. We already validated 'which' above.
- */
- if (errno == EINVAL)
- errno = ESRCH;
- return (-errno);
- }
-
- /*
- * The return value of the getpriority syscall is biased by 20 to avoid
- * returning negative values when successful.
- */
- return (20 - ret);
-}
-
-long
-lx_setpriority(uintptr_t p1, uintptr_t p2, uintptr_t p3)
-{
- int which = (int)p1;
- id_t who = (id_t)p2;
- int prio = (int)p3;
- int rval;
-
- if (which > PRIO_USER)
- return (-EINVAL);
-
- lx_debug("\tsetpriority(%d, %d, %d)", which, who, prio);
-
- if ((which == PRIO_PROCESS) && (who == 1))
- who = zoneinit_pid;
-
- rval = setpriority(which, who, prio);
-
- return ((rval == -1) ? -errno : rval);
-}
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 64e1ca6ab8..efcbef8f70 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
@@ -157,9 +157,6 @@ extern long lx_fork(void);
extern long lx_vfork(void);
extern long lx_exec(uintptr_t, uintptr_t, uintptr_t);
-extern long lx_getpriority(uintptr_t, uintptr_t);
-extern long lx_setpriority(uintptr_t, uintptr_t, uintptr_t);
-
extern long lx_ptrace(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
extern long lx_xattr2(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 7cb29f1004..3a558d89b0 100644
--- a/usr/src/uts/common/brand/lx/os/lx_syscall.c
+++ b/usr/src/uts/common/brand/lx/os/lx_syscall.c
@@ -615,8 +615,8 @@ lx_sysent_t lx_sysent32[] = {
{"ftruncate", NULL, 0, 2}, /* 93 */
{"fchmod", lx_fchmod, 0, 2}, /* 94 */
{"fchown16", lx_fchown16, 0, 3}, /* 95 */
- {"getpriority", NULL, 0, 2}, /* 96 */
- {"setpriority", NULL, 0, 3}, /* 97 */
+ {"getpriority", lx_getpriority, 0, 2}, /* 96 */
+ {"setpriority", lx_setpriority, 0, 3}, /* 97 */
{"profil", NULL, NOSYS_NO_EQUIV, 0}, /* 98 */
{"statfs", NULL, 0, 2}, /* 99 */
{"fstatfs", NULL, 0, 2}, /* 100 */
@@ -1030,8 +1030,8 @@ lx_sysent_t lx_sysent64[] = {
{"statfs", NULL, 0, 2}, /* 137 */
{"fstatfs", NULL, 0, 2}, /* 138 */
{"sysfs", NULL, 0, 3}, /* 139 */
- {"getpriority", NULL, 0, 2}, /* 140 */
- {"setpriority", NULL, 0, 3}, /* 141 */
+ {"getpriority", lx_getpriority, 0, 2}, /* 140 */
+ {"setpriority", lx_setpriority, 0, 3}, /* 141 */
{"sched_setparam", lx_sched_setparam, 0, 2}, /* 142 */
{"sched_getparam", lx_sched_getparam, 0, 2}, /* 143 */
{"sched_setscheduler", lx_sched_setscheduler, 0, 3}, /* 144 */
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 f8fb1c145d..63afc0e795 100644
--- a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h
+++ b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h
@@ -102,6 +102,7 @@ extern long lx_getpgrp();
extern long lx_getsockname();
extern long lx_getpid();
extern long lx_getppid();
+extern long lx_getpriority();
extern long lx_getrandom();
extern long lx_getresgid();
extern long lx_getresgid16();
@@ -203,6 +204,7 @@ extern long lx_setgid();
extern long lx_setgid16();
extern long lx_sethostname();
extern long lx_setpgid();
+extern long lx_setpriority();
extern long lx_setregid();
extern long lx_setregid16();
extern long lx_setresgid();
diff --git a/usr/src/uts/common/brand/lx/syscall/lx_priority.c b/usr/src/uts/common/brand/lx/syscall/lx_priority.c
new file mode 100644
index 0000000000..44c60b66bf
--- /dev/null
+++ b/usr/src/uts/common/brand/lx/syscall/lx_priority.c
@@ -0,0 +1,192 @@
+/*
+ * 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/systm.h>
+#include <sys/procset.h>
+#include <sys/resource.h>
+#include <sys/priocntl.h>
+#include <sys/param.h>
+#include <sys/policy.h>
+#include <sys/brand.h>
+#include <sys/lx_brand.h>
+
+/* From uts/common/disp/priocntl.c */
+extern int donice(procset_t *, pcnice_t *);
+
+/*
+ * The Linux syscall returns priorities in the range (highest) 40-1 (lowest)
+ * and then glibc adjusts these to the range -20 - 19.
+ */
+long
+lx_getpriority(int which, id_t who)
+{
+ int rval;
+ idtype_t idtype;
+ id_t id, lid;
+ pcnice_t pcnice;
+ procset_t procset;
+
+ switch (which) {
+ case PRIO_PROCESS:
+ idtype = P_PID;
+ if (who > 0 && lx_lpid_to_spair(who, &who, &lid) < 0)
+ return (set_errno(ESRCH));
+ break;
+ case PRIO_PGRP:
+ idtype = P_PGID;
+ break;
+ case PRIO_USER:
+ idtype = P_UID;
+ break;
+ default:
+ return (set_errno(EINVAL));
+ }
+
+ /* Linux fails with a different errno on a negative id */
+ if (who < 0)
+ return (set_errno(ESRCH));
+
+ id = (who == 0 ? P_MYID : who);
+
+ pcnice.pc_val = 0;
+ pcnice.pc_op = PC_GETNICE;
+
+ setprocset(&procset, POP_AND, idtype, id, P_ALL, 0);
+
+ rval = donice(&procset, &pcnice);
+ if (rval != 0) {
+ if (which == PRIO_PROCESS &&
+ (who == curproc->p_pid || who == 0) &&
+ strcmp(sclass[curthread->t_cid].cl_name, "RT") == 0) {
+ /*
+ * donice() will always return EINVAL if we're in the
+ * RT class. The zone won't be able to put itself or any
+ * of its processes into RT, but if we put the whole
+ * zone into RT via the scheduling-class property, then
+ * getpriority would always fail. This breaks pam and
+ * prevents any login. Just pretend to be the highest
+ * priority.
+ */
+ return (40);
+ }
+
+ /*
+ * Linux does not return EINVAL for invalid 'who' values, it
+ * returns ESRCH instead. We already validated 'which' above.
+ */
+ if (rval == EINVAL)
+ rval = ESRCH;
+ return (set_errno(rval));
+ }
+
+ /*
+ * The return value of the getpriority syscall is biased by 20 to avoid
+ * returning negative values when successful (-20 internally is our
+ * highest priority and 19 is our lowest).
+ */
+ return (20 - pcnice.pc_val);
+}
+
+/*
+ * Return EPERM if the current process is not allowed to operate on the target
+ * process (which is part of the procset for setpriority).
+ */
+/* ARGSUSED */
+static int
+lx_chk_pripriv(proc_t *pp, char *dummy)
+{
+ ASSERT(MUTEX_HELD(&pidlock));
+ mutex_enter(&pp->p_lock);
+ if (!prochasprocperm(pp, curproc, CRED())) {
+ mutex_exit(&pp->p_lock);
+ return (EPERM);
+ }
+ mutex_exit(&pp->p_lock);
+ return (0);
+}
+
+long
+lx_setpriority(int which, id_t who, int prio)
+{
+ int rval;
+ idtype_t idtype;
+ id_t id, lid;
+ pcnice_t pcnice;
+ procset_t procset;
+
+ switch (which) {
+ case PRIO_PROCESS:
+ idtype = P_PID;
+ if (who > 0 && lx_lpid_to_spair(who, &who, &lid) < 0)
+ return (set_errno(ESRCH));
+ break;
+ case PRIO_PGRP:
+ idtype = P_PGID;
+ break;
+ case PRIO_USER:
+ idtype = P_UID;
+ break;
+ default:
+ return (set_errno(EINVAL));
+ }
+
+ /* Linux fails with a different errno on a negative id */
+ if (who < 0)
+ return (set_errno(ESRCH));
+
+ id = (who == 0 ? P_MYID : who);
+
+ if (prio > NZERO - 1) {
+ prio = NZERO - 1;
+ } else if (prio < -NZERO) {
+ prio = -NZERO;
+ }
+
+ pcnice.pc_val = prio;
+ pcnice.pc_op = PC_SETNICE;
+
+ setprocset(&procset, POP_AND, idtype, id, P_ALL, 0);
+
+ rval = donice(&procset, &pcnice);
+ if (rval != 0) {
+ /*
+ * Once we fully support Linux capabilities, we should update
+ * the following check to look at the CAP_SYS_NICE capability.
+ */
+ if (rval == EPERM && crgetuid(CRED()) != 0) {
+ /*
+ * donice() returns EPERM under two conditions:
+ * 1) if either the real or eff. uid don't match
+ * 2) we lack the privileges to raise the priority
+ *
+ * However, setpriority() must return a different errno
+ * based on the following:
+ * EPERM - real or eff. uid did not match
+ * EACCES - trying to increase priority
+ *
+ * We use lx_chk_pripriv to determine which case we hit.
+ *
+ * Note that the native setpriority(3C) code has the
+ * same race on re-checking.
+ */
+ if (dotoprocs(&procset, lx_chk_pripriv, NULL) != EPERM)
+ rval = EACCES;
+ }
+
+ return (set_errno(rval));
+ }
+
+ return (0);
+}
diff --git a/usr/src/uts/common/disp/priocntl.c b/usr/src/uts/common/disp/priocntl.c
index 0101d12432..fb48f15306 100644
--- a/usr/src/uts/common/disp/priocntl.c
+++ b/usr/src/uts/common/disp/priocntl.c
@@ -113,7 +113,7 @@ copyin_vaparms32(caddr_t arg, pc_vaparms_t *vap, uio_seg_t seg)
#endif
-static int donice(procset_t *, pcnice_t *);
+int donice(procset_t *, pcnice_t *);
static int doprio(procset_t *, pcprio_t *);
static int proccmp(proc_t *, struct pcmpargs *);
static int setparms(proc_t *, struct stprmargs *);
@@ -990,7 +990,7 @@ setprocnice(proc_t *pp, pcnice_t *pcnice)
/*
* Update the nice value of the specified LWP or set of processes.
*/
-static int
+int
donice(procset_t *procset, pcnice_t *pcnice)
{
int err_proc = 0;
diff --git a/usr/src/uts/intel/Makefile.files b/usr/src/uts/intel/Makefile.files
index aeddaa9203..5e819809fd 100644
--- a/usr/src/uts/intel/Makefile.files
+++ b/usr/src/uts/intel/Makefile.files
@@ -346,6 +346,7 @@ LX_BRAND_OBJS = \
lx_pipe.o \
lx_poll.o \
lx_prctl.o \
+ lx_priority.o \
lx_ptrace.o \
lx_rename.o \
lx_rlimit.o \