summaryrefslogtreecommitdiffstats
path: root/sys/i386/linux
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>1999-08-25 14:11:01 +0000
committermarcel <marcel@FreeBSD.org>1999-08-25 14:11:01 +0000
commit09bd601964391c338888981d372d427b70b89fe6 (patch)
treeb97c0f43b5523c7fa263455f4007adf4e903b3a8 /sys/i386/linux
parentd7bf63683b371cadf138c48b1485b9ea74057769 (diff)
downloadFreeBSD-src-09bd601964391c338888981d372d427b70b89fe6.zip
FreeBSD-src-09bd601964391c338888981d372d427b70b89fe6.tar.gz
Fix {g|s}etgroups semantics. We use cr_groups[0] to hold egid. This means that
egid will be twice in the set and that setting cr_groups[0] will change egid. This is simply solved by ignoring cr_groups[0]. That is; linux_getgroups does not return cr_groups[0] and linux_setgroups does not touch it. Noticed by: bde Brought to my attention by: sheldonh
Diffstat (limited to 'sys/i386/linux')
-rw-r--r--sys/i386/linux/linux_misc.c123
1 files changed, 70 insertions, 53 deletions
diff --git a/sys/i386/linux/linux_misc.c b/sys/i386/linux/linux_misc.c
index 46176df..929bfaa 100644
--- a/sys/i386/linux/linux_misc.c
+++ b/sys/i386/linux/linux_misc.c
@@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $Id: linux_misc.c,v 1.65 1999/08/17 10:09:06 marcel Exp $
+ * $Id: linux_misc.c,v 1.66 1999/08/25 11:19:02 marcel Exp $
*/
#include "opt_compat.h"
@@ -1141,75 +1141,92 @@ linux_nice(struct proc *p, struct linux_nice_args *args)
int
linux_setgroups(p, uap)
- struct proc *p;
- struct linux_setgroups_args *uap;
+ struct proc *p;
+ struct linux_setgroups_args *uap;
{
- struct pcred *pc = p->p_cred;
- linux_gid_t linux_gidset[NGROUPS];
- gid_t *bsd_gidset;
- int ngrp, error;
+ struct pcred *pc;
+ linux_gid_t linux_gidset[NGROUPS];
+ gid_t *bsd_gidset;
+ int ngrp, error;
- if ((error = suser(p)))
- return error;
+ pc = p->p_cred;
+ ngrp = uap->gidsetsize;
+
+ /*
+ * cr_groups[0] holds egid. Setting the whole set from
+ * the supplied set will cause egid to be changed too.
+ * Keep cr_groups[0] unchanged to prevent that.
+ */
- if (uap->gidsetsize > NGROUPS)
- return EINVAL;
+ if ((error = suser(p)) != 0)
+ return (error);
- ngrp = uap->gidsetsize;
- pc->pc_ucred = crcopy(pc->pc_ucred);
- if (ngrp >= 1) {
- if ((error = copyin((caddr_t)uap->gidset,
- (caddr_t)linux_gidset,
- ngrp * sizeof(linux_gid_t))))
- return error;
+ if (ngrp >= NGROUPS)
+ return (EINVAL);
- pc->pc_ucred->cr_ngroups = ngrp;
+ pc->pc_ucred = crcopy(pc->pc_ucred);
+ if (ngrp > 0) {
+ error = copyin((caddr_t)uap->gidset, (caddr_t)linux_gidset,
+ ngrp * sizeof(linux_gid_t));
+ if (error)
+ return (error);
- bsd_gidset = pc->pc_ucred->cr_groups;
- ngrp--;
- while (ngrp >= 0) {
- bsd_gidset[ngrp] = linux_gidset[ngrp];
- ngrp--;
- }
- }
- else
- pc->pc_ucred->cr_ngroups = 1;
+ pc->pc_ucred->cr_ngroups = ngrp + 1;
+
+ bsd_gidset = pc->pc_ucred->cr_groups;
+ ngrp--;
+ while (ngrp >= 0) {
+ bsd_gidset[ngrp + 1] = linux_gidset[ngrp];
+ ngrp--;
+ }
+ }
+ else
+ pc->pc_ucred->cr_ngroups = 1;
- setsugid(p);
- return 0;
+ setsugid(p);
+ return (0);
}
int
linux_getgroups(p, uap)
- struct proc *p;
- struct linux_getgroups_args *uap;
+ struct proc *p;
+ struct linux_getgroups_args *uap;
{
- struct pcred *pc = p->p_cred;
- linux_gid_t linux_gidset[NGROUPS];
- gid_t *bsd_gidset;
- int ngrp, error;
+ struct pcred *pc;
+ linux_gid_t linux_gidset[NGROUPS];
+ gid_t *bsd_gidset;
+ int bsd_gidsetsz, ngrp, error;
- if ((ngrp = uap->gidsetsize) == 0) {
- p->p_retval[0] = pc->pc_ucred->cr_ngroups;
- return 0;
- }
+ pc = p->p_cred;
+ bsd_gidset = pc->pc_ucred->cr_groups;
+ bsd_gidsetsz = pc->pc_ucred->cr_ngroups;
+
+ /*
+ * cr_groups[0] holds egid. Returning the whole set
+ * here will cause a duplicate. Exclude cr_groups[0]
+ * to prevent that.
+ */
- if (ngrp < pc->pc_ucred->cr_ngroups)
- return EINVAL;
+ if ((ngrp = uap->gidsetsize) == 0) {
+ p->p_retval[0] = bsd_gidsetsz - 1;
+ return (0);
+ }
- ngrp = 0;
- bsd_gidset = pc->pc_ucred->cr_groups;
- while (ngrp < pc->pc_ucred->cr_ngroups) {
- linux_gidset[ngrp] = bsd_gidset[ngrp];
- ngrp++;
- }
+ if (ngrp < bsd_gidsetsz - 1)
+ return (EINVAL);
- if ((error = copyout((caddr_t)linux_gidset, (caddr_t)uap->gidset,
- ngrp * sizeof(linux_gid_t))))
- return error;
+ ngrp = 1;
+ while (ngrp < bsd_gidsetsz) {
+ linux_gidset[ngrp - 1] = bsd_gidset[ngrp];
+ ngrp++;
+ }
+
+ if ((error = copyout((caddr_t)linux_gidset, (caddr_t)uap->gidset,
+ ngrp * sizeof(linux_gid_t))))
+ return (error);
- p->p_retval[0] = ngrp;
- return (0);
+ p->p_retval[0] = ngrp - 1;
+ return (0);
}
int
OpenPOWER on IntegriCloud