Page MenuHomeFreeBSD

D60035.1794807428.diff
No OneTemporary

Authored By
Unknown
Size
38 KB
Referenced Files
None
Subscribers
None

D60035.1794807428.diff

diff --git a/include/unistd.h b/include/unistd.h
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -502,6 +502,7 @@
int acct(const char *);
int async_daemon(void);
+int chaltroot(const char *);
int check_utility_compat(const char *);
int close_range(unsigned int, unsigned int, int);
ssize_t copy_file_range(int, off_t *, int, off_t *, size_t, unsigned int);
@@ -517,6 +518,7 @@
int execvpe(const char *, char * const *, char * const *);
int feature_present(const char *);
int fchroot(int);
+int fchaltroot(int);
char *fflagstostr(u_long);
ssize_t freadlink(int fd, char *buf, size_t bufsize);
int getdomainname(char *, int);
diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h
--- a/lib/libprocstat/libprocstat.h
+++ b/lib/libprocstat/libprocstat.h
@@ -83,6 +83,7 @@
#define PS_FST_UFLAG_TEXT 0x0010
#define PS_FST_UFLAG_MMAP 0x0020
#define PS_FST_UFLAG_CTTY 0x0040
+#define PS_FST_UFLAG_ADIR 0x0080
/*
* Descriptor flags.
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -530,6 +530,13 @@
if (entry != NULL)
STAILQ_INSERT_TAIL(head, entry, next);
}
+ /* alt root, if any. */
+ if (pwd.pwd_adir != NULL && pwd.pwd_adir != pwd.pwd_rdir) {
+ entry = filestat_new_entry(pwd.pwd_adir, PS_FST_TYPE_VNODE, -1,
+ PS_FST_FFLAG_READ, PS_FST_UFLAG_ADIR, 0, 0, NULL, NULL);
+ if (entry != NULL)
+ STAILQ_INSERT_TAIL(head, entry, next);
+ }
}
/* ktrace vnode, if one */
if (kp->ki_tracep) {
@@ -777,6 +784,8 @@
{
switch (fd) {
+ case KF_FD_TYPE_ALTROOT:
+ return (PS_FST_UFLAG_ADIR);
case KF_FD_TYPE_CTTY:
return (PS_FST_UFLAG_CTTY);
case KF_FD_TYPE_CWD:
diff --git a/lib/libsys/Makefile.sys b/lib/libsys/Makefile.sys
--- a/lib/libsys/Makefile.sys
+++ b/lib/libsys/Makefile.sys
@@ -416,7 +416,9 @@
MLINKS+=chown.2 fchown.2 \
chown.2 fchownat.2 \
chown.2 lchown.2
-MLINKS+=chroot.2 fchroot.2
+MLINKS+=chroot.2 fchroot.2 \
+ chroot.2 chaltroot.2 \
+ chroot.2 fchaltroot.2
MLINKS+=clock_gettime.2 clock_getres.2 \
clock_gettime.2 clock_settime.2
MLINKS+=closefrom.2 close_range.2
diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map
--- a/lib/libsys/Symbol.sys.map
+++ b/lib/libsys/Symbol.sys.map
@@ -391,6 +391,8 @@
};
FBSD_1.9 {
+ chaltroot;
+ fchaltroot;
kexec_load;
pddupfd;
pdopenpid;
diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h
--- a/lib/libsys/_libsys.h
+++ b/lib/libsys/_libsys.h
@@ -478,6 +478,8 @@
typedef int (__sys_pdopenpid_t)(pid_t, int);
typedef int (__sys_pddupfd_t)(int, int, int);
typedef int (__sys_pdptrace_t)(int, int, int, void *, int);
+typedef int (__sys_chaltroot_t)(const char *);
+typedef int (__sys_fchaltroot_t)(int);
_Noreturn void __sys__exit(int rval);
int __sys_fork(void);
@@ -891,6 +893,8 @@
int __sys_pdopenpid(pid_t pid, int flags);
int __sys_pddupfd(int pd, int fd, int flags);
int __sys_pdptrace(int req, int pfd, int lwpid, void * addr, int data);
+int __sys_chaltroot(const char * path);
+int __sys_fchaltroot(int fd);
__END_DECLS
#endif /* __LIBSYS_H_ */
diff --git a/lib/libsys/cap_enter.2 b/lib/libsys/cap_enter.2
--- a/lib/libsys/cap_enter.2
+++ b/lib/libsys/cap_enter.2
@@ -64,6 +64,12 @@
may be used to create kernel-enforced sandboxes in which
appropriately-crafted applications or application components may be run.
.Pp
+Entering capability mode clears the alternative root set by
+.Xr chaltroot 2 .
+Other threads are stopped while the call runs, so some of their
+interrupted system calls may return
+.Er EINTR .
+.Pp
.Fn cap_getmode
returns a flag indicating whether or not the process is in a capability mode
sandbox.
@@ -116,6 +122,18 @@
.El
.Pp
The
+.Fn cap_enter
+system call may also return the following error:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The file descriptor table or the current/root directory state of the
+process is shared with another process, see
+.Xr rfork 2 .
+Sharing would allow the other process to grant additional privileges
+to the process after it entered capability mode, without its consent.
+.El
+.Pp
+The
.Fn cap_getmode
system call may also return the following error:
.Bl -tag -width Er
diff --git a/lib/libsys/chroot.2 b/lib/libsys/chroot.2
--- a/lib/libsys/chroot.2
+++ b/lib/libsys/chroot.2
@@ -40,6 +40,10 @@
.Fn chroot "const char *dirname"
.Ft int
.Fn fchroot "int fd"
+.Ft int
+.Fn chaltroot "const char *dirname"
+.Ft int
+.Fn fchaltroot "int fd"
.Sh DESCRIPTION
The
.Fa dirname
@@ -61,13 +65,6 @@
.Fn chroot
has no effect on the process's current directory.
.Pp
-This call is restricted to the super-user, unless the
-.Ql Va security.bsd.unprivileged_chroot
-sysctl variable is set to 1
-and the process has enabled the
-.Dv PROC_NO_NEW_PRIVS_CTL
-.Xr procctl 2 .
-.Pp
Depending on the setting of the
.Ql kern.chroot_allow_open_directories
sysctl variable, open file descriptors which reference directories
@@ -106,15 +103,77 @@
system call is identical to
.Fn chroot
except it takes a file descriptor instead of path.
+.Pp
+The
+.Fn chaltroot
+system call sets or changes the
+.Dq alternative root
+directory.
+If set to a directory for which the process has
+search permission, that directory is used as a root for
+absolute path lookups.
+If the lookup succeeds, the result is used.
+If the lookup fails with
+.Er ENOENT ,
+a second lookup is automatically initiated,
+starting from the process' true root directory,
+and the result of that lookup is returned.
+.Pp
+Calling the
+.Fn chaltroot
+system call with the
+.Fa dirname
+argument set to
+.Dv NULL
+disables the alternative root for the process.
+.Pp
+As with the normal root directory, the alternative root directory is
+inherited by child processes created by
+.Xr fork 2 ,
+and preserved across image activations on
+.Xr execve 2 .
+.Pp
+The alternative root facility is used by ABI emulators to
+provide a parallel installation of foreign system files
+while still providing seamless access to the file hierarchy
+of the host system.
+Upon activation of the executable image branded for the ABI
+emulator, the kernel automatically resets the alternative root to
+the value assigned to the ABI.
+.Pp
+The
+.Fn fchaltroot
+system call is similar to
+.Fn chaltroot
+but takes a file descriptor to designate the new alternative root
+instead of a path.
+Calling the
+.Fn fchaltroot
+system call with the
+.Fa fd
+argument of
+.Dv FCHALTROOT_DISABLE
+disables the alternative root for the process.
+.Pp
+All functions described in this page are restricted to the super-user,
+unless the
+.Ql Va security.bsd.unprivileged_chroot
+sysctl variable is set to 1
+and the process has enabled the
+.Dv PROC_NO_NEW_PRIVS_CTL
+.Xr procctl 2
+setting.
.Sh RETURN VALUES
.Rv -std
.Sh ERRORS
The
-.Fn chroot
+.Fn chroot ,
+.Fn fchroot ,
+.Fn chaltroot ,
and
-.Fn fchroot
+.Fn fchaltroot
system calls
-will fail and the root directory will be unchanged if:
+will fail and the root or alternative root directory will be unchanged if:
.Bl -tag -width Er
.It Bq Er EPERM
The effective user ID is not the super-user and the
@@ -137,8 +196,11 @@
.Pp
The
.Fn chroot
-system call
-will fail and the root directory will be unchanged if:
+and
+.Fn chaltroot
+system calls
+will fail and the root or alternative root directory
+will be unchanged if:
.Bl -tag -width Er
.It Bq Er ENOTDIR
A component of the path name is not a directory.
@@ -160,8 +222,11 @@
.Pp
The
.Fn fchroot
-system call
-will fail and the root directory will be unchanged if:
+and
+.Fn fchaltroot
+system calls
+will fail and the root or alternative root directory
+will be unchanged if:
.Bl -tag -width Er
.It Bq Er EACCES
Search permission is denied for the directory referenced by the
@@ -172,6 +237,15 @@
is not a valid file descriptor.
.It Bq Er ENOTDIR
The file descriptor does not reference a directory.
+.It Bq Er ENOTCAPABLE
+The
+.Fa fd
+file descriptor has the
+.Dv FD_RESOLVE_BENEATH
+flag set.
+In particular, it was opened with the
+.Dv O_RESOLVE_BENEATH
+flag.
.El
.Sh SEE ALSO
.Xr chdir 2 ,
@@ -190,6 +264,12 @@
.Fn fchroot
system call first appeared in
.Fx 15.0 .
+The
+.Fn chaltroot
+and
+.Fn fchaltroot
+system calls first appeared in
+.Fx 16.0 .
.Sh BUGS
If the process is able to change its working directory to the target
directory, but another access control check fails (such as a check for
diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map
--- a/lib/libsys/syscalls.map
+++ b/lib/libsys/syscalls.map
@@ -831,4 +831,8 @@
__sys_pddupfd;
_pdptrace;
__sys_pdptrace;
+ _chaltroot;
+ __sys_chaltroot;
+ _fchaltroot;
+ __sys_fchaltroot;
};
diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h
--- a/sys/bsm/audit_kevents.h
+++ b/sys/bsm/audit_kevents.h
@@ -667,6 +667,8 @@
#define AUE_PDRFORK 43273 /* FreeBSD-specific. */
#define AUE_PDOPENPID 43274 /* FreeBSD-specific. */
#define AUE_PDPTRACE 43275 /* FreeBSD-specific. */
+#define AUE_CHALTROOT 43276 /* FreeBSD-specific. */
+#define AUE_FCHALTROOT 43277 /* FreeBSD-specific. */
/*
* Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -523,4 +523,6 @@
#define FREEBSD32_SYS_pdopenpid 603
#define FREEBSD32_SYS_pddupfd 604
#define FREEBSD32_SYS_freebsd32_pdptrace 605
-#define FREEBSD32_SYS_MAXSYSCALL 606
+#define FREEBSD32_SYS_chaltroot 606
+#define FREEBSD32_SYS_fchaltroot 607
+#define FREEBSD32_SYS_MAXSYSCALL 608
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -611,4 +611,6 @@
"pdopenpid", /* 603 = pdopenpid */
"pddupfd", /* 604 = pddupfd */
"freebsd32_pdptrace", /* 605 = freebsd32_pdptrace */
+ "chaltroot", /* 606 = chaltroot */
+ "fchaltroot", /* 607 = fchaltroot */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -673,4 +673,6 @@
{ .sy_narg = AS(pdopenpid_args), .sy_call = (sy_call_t *)sys_pdopenpid, .sy_auevent = AUE_PDOPENPID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 603 = pdopenpid */
{ .sy_narg = AS(pddupfd_args), .sy_call = (sy_call_t *)sys_pddupfd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 604 = pddupfd */
{ .sy_narg = AS(freebsd32_pdptrace_args), .sy_call = (sy_call_t *)freebsd32_pdptrace, .sy_auevent = AUE_PDPTRACE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 605 = freebsd32_pdptrace */
+ { .sy_narg = AS(chaltroot_args), .sy_call = (sy_call_t *)sys_chaltroot, .sy_auevent = AUE_CHALTROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 606 = chaltroot */
+ { .sy_narg = AS(fchaltroot_args), .sy_call = (sy_call_t *)sys_fchaltroot, .sy_auevent = AUE_FCHALTROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 607 = fchaltroot */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3486,6 +3486,20 @@
*n_args = 5;
break;
}
+ /* chaltroot */
+ case 606: {
+ struct chaltroot_args *p = params;
+ uarg[a++] = (intptr_t)p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* fchaltroot */
+ case 607: {
+ struct fchaltroot_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9426,6 +9440,26 @@
break;
};
break;
+ /* chaltroot */
+ case 606:
+ switch (ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fchaltroot */
+ case 607:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11374,6 +11408,16 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* chaltroot */
+ case 606:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fchaltroot */
+ case 607:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c
--- a/sys/compat/linux/linux_util.c
+++ b/sys/compat/linux/linux_util.c
@@ -74,6 +74,10 @@
linux_emul_path, sizeof(linux_emul_path),
"Linux runtime environment path");
+/*
+ * Do not prevent execution if altroot is non-existent or is not a
+ * directory.
+ */
int
linux_pwd_onexec(struct thread *td)
{
@@ -83,12 +87,13 @@
NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, linux_emul_path);
error = namei(&nd);
if (error != 0) {
- /* Do not prevent execution if altroot is non-existent. */
pwd_altroot(td, NULL);
return (0);
}
NDFREE_PNBUF(&nd);
- pwd_altroot(td, nd.ni_vp);
+ error = pwd_altroot(td, nd.ni_vp);
+ if (error != 0)
+ pwd_altroot(td, NULL);
vrele(nd.ni_vp);
return (0);
}
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -672,4 +672,6 @@
{ .sy_narg = AS(pdopenpid_args), .sy_call = (sy_call_t *)sys_pdopenpid, .sy_auevent = AUE_PDOPENPID, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 603 = pdopenpid */
{ .sy_narg = AS(pddupfd_args), .sy_call = (sy_call_t *)sys_pddupfd, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 604 = pddupfd */
{ .sy_narg = AS(pdptrace_args), .sy_call = (sy_call_t *)sys_pdptrace, .sy_auevent = AUE_PDPTRACE, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 605 = pdptrace */
+ { .sy_narg = AS(chaltroot_args), .sy_call = (sy_call_t *)sys_chaltroot, .sy_auevent = AUE_CHALTROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 606 = chaltroot */
+ { .sy_narg = AS(fchaltroot_args), .sy_call = (sy_call_t *)sys_fchaltroot, .sy_auevent = AUE_FCHALTROOT, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 607 = fchaltroot */
};
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -2446,6 +2446,7 @@
PWDDESC_LOCK_INIT(newpdp);
refcount_init(&newpdp->pd_refcount, 1);
+ refcount_init(&newpdp->pd_sharecount, 1);
newpdp->pd_cmask = CMASK;
if (pdp == NULL) {
@@ -2527,6 +2528,7 @@
PWDDESC_XUNLOCK(pdp);
return;
}
+ MPASS(refcount_load(&pdp->pd_sharecount) == 0);
pwd = PWDDESC_XLOCKED_LOAD_PWD(pdp);
pwd_set(pdp, NULL);
PWDDESC_XUNLOCK(pdp);
@@ -2553,7 +2555,9 @@
struct pwddesc *
pdshare(struct pwddesc *pdp)
{
+ MPASS(refcount_load(&pdp->pd_sharecount) > 0);
refcount_acquire(&pdp->pd_refcount);
+ refcount_acquire(&pdp->pd_sharecount);
return (pdp);
}
@@ -2585,7 +2589,7 @@
p = td->td_proc;
/* Not shared. */
- if (refcount_load(&p->p_pd->pd_refcount) == 1)
+ if (refcount_load(&p->p_pd->pd_sharecount) == 1)
return;
pdp = pdcopy(p->p_pd);
@@ -2868,6 +2872,8 @@
atomic_thread_fence_seq_cst();
PROC_WAIT_UNLOCKED(p);
+ MPASS(refcount_load(&pdp->pd_sharecount) > 0);
+ refcount_release(&pdp->pd_sharecount);
pddrop(pdp);
}
@@ -4387,37 +4393,41 @@
}
/*
- * Process is transitioning to/from a non-native ABI.
+ * Set the alternative root directory for the process.
+ *
+ * A non-NULL altroot_vp enables the alternative root and uses
+ * altroot_vp for it. NULL disables it by setting the alternative
+ * root to the process root directory.
*/
-void
+int
pwd_altroot(struct thread *td, struct vnode *altroot_vp)
{
struct pwddesc *pdp;
struct pwd *newpwd, *oldpwd;
+ struct vnode *vp;
+ if (altroot_vp != NULL && altroot_vp->v_type != VDIR)
+ return (ENOTDIR);
newpwd = pwd_alloc();
pdp = td->td_proc->p_pd;
PWDDESC_XLOCK(pdp);
oldpwd = PWDDESC_XLOCKED_LOAD_PWD(pdp);
- if (altroot_vp != NULL) {
- /*
- * Native process to a non-native ABI.
- */
-
- vrefact(altroot_vp);
- newpwd->pwd_adir = altroot_vp;
+ vp = altroot_vp != NULL ? altroot_vp : oldpwd->pwd_rdir;
+ if (vp != oldpwd->pwd_adir) {
+ vrefact(vp);
+ newpwd->pwd_adir = vp;
+ pwd_fill(oldpwd, newpwd);
+ pwd_set(pdp, newpwd);
+ newpwd = NULL;
} else {
- /*
- * Non-native process to the native ABI.
- */
-
- vrefact(oldpwd->pwd_rdir);
- newpwd->pwd_adir = oldpwd->pwd_rdir;
+ oldpwd = NULL;
}
- pwd_fill(oldpwd, newpwd);
- pwd_set(pdp, newpwd);
PWDDESC_XUNLOCK(pdp);
- pwd_drop(oldpwd);
+ if (oldpwd != NULL)
+ pwd_drop(oldpwd);
+ if (newpwd != NULL)
+ pwd_drop(newpwd);
+ return (0);
}
/*
@@ -5051,6 +5061,13 @@
error = export_vnode_to_sb(pwd->pwd_jdir,
KF_FD_TYPE_JAIL, FREAD, efbuf);
}
+ /* alt root directory */
+ if (error == 0 && pwd->pwd_adir != NULL &&
+ pwd->pwd_adir != pwd->pwd_rdir) {
+ vrefact(pwd->pwd_adir);
+ error = export_vnode_to_sb(pwd->pwd_adir,
+ KF_FD_TYPE_ALTROOT, FREAD, efbuf);
+ }
}
PWDDESC_XUNLOCK(pdp);
if (error != 0)
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1265,6 +1265,15 @@
imgp->vmspace_destroyed = true;
imgp->sysent = sv;
+ /*
+ * Drop altroot if setuid. It is done so late to avoid
+ * clearing altroot until there is no way for execve(2) to
+ * return to the calling image.
+ */
+ if (imgp->credential_setid &&
+ (sv->sv_flags & SV_ABI_MASK) == SV_ABI_FREEBSD)
+ pwd_altroot(td, NULL);
+
if (p->p_sysent->sv_onexec_old != NULL)
p->p_sysent->sv_onexec_old(td);
itimers_exec(p);
diff --git a/sys/kern/sys_capability.c b/sys/kern/sys_capability.c
--- a/sys/kern/sys_capability.c
+++ b/sys/kern/sys_capability.c
@@ -102,19 +102,38 @@
{
struct ucred *newcred, *oldcred;
struct proc *p;
+ int error;
if (IN_CAPABILITY_MODE(td))
return (0);
- newcred = crget();
+ error = 0;
+ oldcred = newcred = crget();
p = td->td_proc;
PROC_LOCK(p);
+ if (thread_single(p, SINGLE_BOUNDARY)) {
+ error = ERESTART;
+ goto out1;
+ }
+ if (refcount_load(&p->p_pd->pd_sharecount) > 1 ||
+ refcount_load(&p->p_fd->fd_refcnt) > 1) {
+ error = EBUSY;
+ goto out;
+ }
+ PROC_UNLOCK(p);
+ error = pwd_altroot(td, NULL);
+ PROC_LOCK(p);
+ if (error != 0)
+ goto out;
oldcred = crcopysafe(p, newcred);
newcred->cr_flags |= CRED_FLAG_CAPMODE;
proc_set_cred(p, newcred);
+out:
+ thread_single_end(p, SINGLE_BOUNDARY);
+out1:
PROC_UNLOCK(p);
crfree(oldcred);
- return (0);
+ return (error);
}
/*
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -611,4 +611,6 @@
"pdopenpid", /* 603 = pdopenpid */
"pddupfd", /* 604 = pddupfd */
"pdptrace", /* 605 = pdptrace */
+ "chaltroot", /* 606 = chaltroot */
+ "fchaltroot", /* 607 = fchaltroot */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3451,5 +3451,15 @@
int data
);
}
+606 AUE_CHALTROOT STD {
+ int chaltroot(
+ _In_z_opt_ const char *path
+ );
+ }
+607 AUE_FCHALTROOT STD {
+ int fchaltroot(
+ int fd
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3583,6 +3583,20 @@
*n_args = 5;
break;
}
+ /* chaltroot */
+ case 606: {
+ struct chaltroot_args *p = params;
+ uarg[a++] = (intptr_t)p->path; /* const char * */
+ *n_args = 1;
+ break;
+ }
+ /* fchaltroot */
+ case 607: {
+ struct fchaltroot_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9600,6 +9614,26 @@
break;
};
break;
+ /* chaltroot */
+ case 606:
+ switch (ndx) {
+ case 0:
+ p = "userland const char *";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* fchaltroot */
+ case 607:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11643,6 +11677,16 @@
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* chaltroot */
+ case 606:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* fchaltroot */
+ case 607:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -419,9 +419,17 @@
NI_LCF_CAP_DOTDOT;
}
}
- if (error == 0 && (ndp->ni_lcf & NI_LCF_STRICTREL) != 0)
+ if (error == 0 && (ndp->ni_lcf & NI_LCF_STRICTREL) != 0) {
ndp->ni_rbeneath_dpp = *dpp;
+ /*
+ * Prevent use of the alternative root and restarting
+ * the lookup on ENOENT.
+ */
+ cnp->cn_flags |= ISRESTARTED;
+ ndp->ni_rootdir = pwd->pwd_rdir;
+ }
+
/*
* If we are auditing the kernel pathname, save the user pathname.
*/
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -969,31 +969,31 @@
&unprivileged_chroot, 0,
"Unprivileged processes can use chroot(2)");
+static int
+chroot_check_priv(struct thread *td)
+{
+ if (priv_check(td, PRIV_VFS_CHROOT) == 0)
+ return (0);
+ if (unprivileged_chroot == 0)
+ return (EXTERROR(EPERM,
+ "security.bsd.unprivileged_chroot sysctl not enabled"));
+ if ((td->td_proc->p_flag2 & P2_NO_NEW_PRIVS) == 0)
+ return (EXTERROR(EPERM,
+ "PROC_NO_NEW_PRIVS not enabled"));
+ return (0);
+}
+
/*
* Takes locked vnode, unlocks it before returning.
*/
static int
kern_chroot(struct thread *td, struct vnode *vp)
{
- struct proc *p;
int error;
- error = priv_check(td, PRIV_VFS_CHROOT);
- if (error != 0) {
- p = td->td_proc;
- if (unprivileged_chroot == 0) {
- error = EXTERROR(EPERM,
- "security.bsd.unprivileged_chroot sysctl not enabled");
- goto e_vunlock;
- }
- if ((p->p_flag2 & P2_NO_NEW_PRIVS) == 0) {
- error = EXTERROR(EPERM,
- "PROC_NO_NEW_PRIVS not enabled");
- goto e_vunlock;
- }
- }
-
- error = change_dir(vp, td);
+ error = chroot_check_priv(td);
+ if (error == 0)
+ error = change_dir(vp, td);
if (error != 0)
goto e_vunlock;
#ifdef MAC
@@ -5338,3 +5338,88 @@
error = copyout(outoffp, uap->outoffp, sizeof(off_t));
return (error);
}
+
+static int
+disable_altdir(struct thread *td)
+{
+#ifdef MAC
+ int error;
+
+ error = mac_vnode_check_chaltroot(td->td_ucred, NULL);
+ if (error != 0)
+ return (error);
+#endif
+ return (pwd_altroot(td, NULL));
+}
+
+static int
+change_altdir(struct thread *td, struct vnode *vp)
+{
+ int error;
+
+ if (vp->v_type != VDIR) {
+ error = ENOTDIR;
+ } else {
+#ifdef MAC
+ error = mac_vnode_check_chaltroot(td->td_ucred, vp);
+ if (error == 0)
+#endif
+ error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
+ }
+ VOP_UNLOCK(vp);
+ if (error == 0)
+ error = pwd_altroot(td, vp);
+ vrele(vp);
+ return (error);
+}
+
+int
+sys_chaltroot(struct thread *td, struct chaltroot_args *uap)
+{
+ struct nameidata nd;
+ int error;
+
+ error = chroot_check_priv(td);
+ if (error != 0)
+ return (error);
+
+ if (uap->path == NULL)
+ return (disable_altdir(td));
+
+ NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, UIO_USERSPACE,
+ uap->path);
+ error = namei(&nd);
+ if (error != 0)
+ return (error);
+ NDFREE_PNBUF(&nd);
+ return (change_altdir(td, nd.ni_vp));
+}
+
+int
+sys_fchaltroot(struct thread *td, struct fchaltroot_args *uap)
+{
+ struct vnode *vp;
+ struct file *fp;
+ int error;
+ uint8_t fdflags;
+
+ error = chroot_check_priv(td);
+ if (error != 0)
+ return (error);
+
+ if (uap->fd == FCHALTROOT_DISABLE)
+ return (disable_altdir(td));
+
+ error = getvnode_path(td, uap->fd, &cap_fchroot_rights, &fdflags, &fp);
+ if (error != 0)
+ return (error);
+ if ((fdflags & UF_RESOLVE_BENEATH) != 0) {
+ fdrop(fp, td);
+ return (ENOTCAPABLE);
+ }
+ vp = fp->f_vnode;
+ vrefact(vp);
+ fdrop(fp, td);
+ vn_lock(vp, LK_SHARED | LK_RETRY);
+ return (change_altdir(td, vp));
+}
diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c
--- a/sys/security/audit/audit_bsm.c
+++ b/sys/security/audit/audit_bsm.c
@@ -826,8 +826,10 @@
break;
case AUE_JAIL_SET:
+ case AUE_CHALTROOT:
case AUE_CHDIR:
case AUE_CHROOT:
+ case AUE_FCHALTROOT:
case AUE_FSTATAT:
case AUE_FUTIMESAT:
case AUE_GETATTRLIST:
diff --git a/sys/security/mac/mac_framework.h b/sys/security/mac/mac_framework.h
--- a/sys/security/mac/mac_framework.h
+++ b/sys/security/mac/mac_framework.h
@@ -535,6 +535,7 @@
return (mac_vnode_check_access_impl(cred, dvp, accmode));
return (0);
}
+int mac_vnode_check_chaltroot(struct ucred *cred, struct vnode *dvp);
int mac_vnode_check_chdir(struct ucred *cred, struct vnode *dvp);
int mac_vnode_check_chroot(struct ucred *cred, struct vnode *dvp);
int mac_vnode_check_create(struct ucred *cred, struct vnode *dvp,
diff --git a/sys/security/mac/mac_policy.h b/sys/security/mac/mac_policy.h
--- a/sys/security/mac/mac_policy.h
+++ b/sys/security/mac/mac_policy.h
@@ -619,6 +619,8 @@
typedef int (*mpo_vnode_check_access_t)(struct ucred *cred,
struct vnode *vp, struct label *vplabel,
accmode_t accmode);
+typedef int (*mpo_vnode_check_chaltroot_t)(struct ucred *cred,
+ struct vnode *dvp, struct label *dvplabel);
typedef int (*mpo_vnode_check_chdir_t)(struct ucred *cred,
struct vnode *dvp, struct label *dvplabel);
typedef int (*mpo_vnode_check_chroot_t)(struct ucred *cred,
@@ -1015,6 +1017,7 @@
mpo_thread_userret_t mpo_thread_userret;
mpo_vnode_check_access_t mpo_vnode_check_access;
+ mpo_vnode_check_chaltroot_t mpo_vnode_check_chaltroot;
mpo_vnode_check_chdir_t mpo_vnode_check_chdir;
mpo_vnode_check_chroot_t mpo_vnode_check_chroot;
mpo_vnode_check_create_t mpo_vnode_check_create;
diff --git a/sys/security/mac/mac_vfs.c b/sys/security/mac/mac_vfs.c
--- a/sys/security/mac/mac_vfs.c
+++ b/sys/security/mac/mac_vfs.c
@@ -464,6 +464,24 @@
return (error);
}
+MAC_CHECK_PROBE_DEFINE2(vnode_check_chaltroot, "struct ucred *",
+ "struct vnode *");
+
+int
+mac_vnode_check_chaltroot(struct ucred *cred, struct vnode *dvp)
+{
+ int error;
+
+ if (dvp != NULL)
+ ASSERT_VOP_LOCKED(dvp, "mac_vnode_check_chaltroot");
+
+ MAC_POLICY_CHECK(vnode_check_chaltroot, cred, dvp, dvp != NULL ?
+ dvp->v_label : NULL);
+ MAC_CHECK_PROBE2(vnode_check_chaltroot, error, cred, dvp);
+
+ return (error);
+}
+
MAC_CHECK_PROBE_DEFINE4(vnode_check_create, "struct ucred *",
"struct vnode *", "struct componentname *", "struct vattr *");
diff --git a/sys/security/mac_stub/mac_stub.c b/sys/security/mac_stub/mac_stub.c
--- a/sys/security/mac_stub/mac_stub.c
+++ b/sys/security/mac_stub/mac_stub.c
@@ -1500,6 +1500,14 @@
return (0);
}
+static int
+stub_vnode_check_chaltroot(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ return (0);
+}
+
static int
stub_vnode_check_create(struct ucred *cred, struct vnode *dvp,
struct label *dvplabel, struct componentname *cnp, struct vattr *vap)
@@ -2051,6 +2059,7 @@
.mpo_vnode_check_access = stub_vnode_check_access,
.mpo_vnode_check_chdir = stub_vnode_check_chdir,
.mpo_vnode_check_chroot = stub_vnode_check_chroot,
+ .mpo_vnode_check_chaltroot = stub_vnode_check_chaltroot,
.mpo_vnode_check_create = stub_vnode_check_create,
.mpo_vnode_check_deleteacl = stub_vnode_check_deleteacl,
.mpo_vnode_check_deleteextattr = stub_vnode_check_deleteextattr,
diff --git a/sys/security/mac_test/mac_test.c b/sys/security/mac_test/mac_test.c
--- a/sys/security/mac_test/mac_test.c
+++ b/sys/security/mac_test/mac_test.c
@@ -2738,6 +2738,20 @@
return (0);
}
+COUNTER_DECL(vnode_check_chaltroot);
+static int
+test_vnode_check_chaltroot(struct ucred *cred, struct vnode *dvp,
+ struct label *dvplabel)
+{
+
+ LABEL_CHECK(cred->cr_label, MAGIC_CRED);
+ if (dvplabel != NULL)
+ LABEL_CHECK(dvplabel, MAGIC_VNODE);
+ COUNTER_INC(vnode_check_chaltroot);
+
+ return (0);
+}
+
COUNTER_DECL(vnode_check_create);
static int
test_vnode_check_create(struct ucred *cred, struct vnode *dvp,
@@ -3505,6 +3519,7 @@
.mpo_vnode_associate_singlelabel = test_vnode_associate_singlelabel,
.mpo_vnode_check_chdir = test_vnode_check_chdir,
.mpo_vnode_check_chroot = test_vnode_check_chroot,
+ .mpo_vnode_check_chaltroot = test_vnode_check_chaltroot,
.mpo_vnode_check_create = test_vnode_check_create,
.mpo_vnode_check_deleteacl = test_vnode_check_deleteacl,
.mpo_vnode_check_deleteextattr = test_vnode_check_deleteextattr,
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -103,7 +103,8 @@
struct pwddesc {
struct mtx pd_lock; /* protects members of this struct */
smrpwd_t pd_pwd; /* directories */
- u_int pd_refcount;
+ u_int pd_refcount; /* lifetime */
+ u_int pd_sharecount; /* processes sharing the descriptor */
u_short pd_cmask; /* mask for file creation */
};
@@ -371,7 +372,7 @@
struct pwddesc *pdshare(struct pwddesc *pdp);
void pdunshare(struct thread *td);
-void pwd_altroot(struct thread *td, struct vnode *altroot_vp);
+int pwd_altroot(struct thread *td, struct vnode *altroot_vp);
void pwd_chdir(struct thread *td, struct vnode *vp);
int pwd_chroot(struct thread *td, struct vnode *vp);
int pwd_chroot_chdir(struct thread *td, struct vnode *vp);
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -544,4 +544,6 @@
#define SYS_pdopenpid 603
#define SYS_pddupfd 604
#define SYS_pdptrace 605
-#define SYS_MAXSYSCALL 606
+#define SYS_chaltroot 606
+#define SYS_fchaltroot 607
+#define SYS_MAXSYSCALL 608
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -447,4 +447,6 @@
renameat2.o \
pdopenpid.o \
pddupfd.o \
- pdptrace.o
+ pdptrace.o \
+ chaltroot.o \
+ fchaltroot.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1948,6 +1948,12 @@
char addr_l_[PADL_(void *)]; void * addr; char addr_r_[PADR_(void *)];
char data_l_[PADL_(int)]; int data; char data_r_[PADR_(int)];
};
+struct chaltroot_args {
+ char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)];
+};
+struct fchaltroot_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+};
int sys__exit(struct thread *, struct _exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2361,6 +2367,8 @@
int sys_pdopenpid(struct thread *, struct pdopenpid_args *);
int sys_pddupfd(struct thread *, struct pddupfd_args *);
int sys_pdptrace(struct thread *, struct pdptrace_args *);
+int sys_chaltroot(struct thread *, struct chaltroot_args *);
+int sys_fchaltroot(struct thread *, struct fchaltroot_args *);
#ifdef COMPAT_43
@@ -3366,6 +3374,8 @@
#define SYS_AUE_pdopenpid AUE_PDOPENPID
#define SYS_AUE_pddupfd AUE_NULL
#define SYS_AUE_pdptrace AUE_PDPTRACE
+#define SYS_AUE_chaltroot AUE_CHALTROOT
+#define SYS_AUE_fchaltroot AUE_FCHALTROOT
#undef PAD_
#undef PADL_
diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h
--- a/sys/sys/unistd.h
+++ b/sys/sys/unistd.h
@@ -226,6 +226,8 @@
#define COPY_FILE_RANGE_CLONE 0x00800000 /* Require cloning. */
#define COPY_FILE_RANGE_USERFLAGS (COPY_FILE_RANGE_CLONE)
+#define FCHALTROOT_DISABLE (-110) /* Disable altroot by fchaltroot(2). */
+
#endif /* __BSD_VISIBLE */
#endif /* !_SYS_UNISTD_H_ */
diff --git a/sys/sys/user.h b/sys/sys/user.h
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -283,12 +283,13 @@
#define KF_VTYPE_VBAD 8
#define KF_VTYPE_UNKNOWN 255
-#define KF_FD_TYPE_CWD -1 /* Current working directory */
-#define KF_FD_TYPE_ROOT -2 /* Root directory */
-#define KF_FD_TYPE_JAIL -3 /* Jail directory */
-#define KF_FD_TYPE_TRACE -4 /* Ktrace vnode */
-#define KF_FD_TYPE_TEXT -5 /* Text vnode */
-#define KF_FD_TYPE_CTTY -6 /* Controlling terminal */
+#define KF_FD_TYPE_CWD (-1) /* Current working directory */
+#define KF_FD_TYPE_ROOT (-2) /* Root directory */
+#define KF_FD_TYPE_JAIL (-3) /* Jail directory */
+#define KF_FD_TYPE_TRACE (-4) /* Ktrace vnode */
+#define KF_FD_TYPE_TEXT (-5) /* Text vnode */
+#define KF_FD_TYPE_CTTY (-6) /* Controlling terminal */
+#define KF_FD_TYPE_ALTROOT (-7) /* Alternative root directory */
#define KF_NTSYNC_TYPE_DEV 1 /* Not reported, reserved */
#define KF_NTSYNC_TYPE_SEM 2
diff --git a/usr.bin/fstat/fstat.1 b/usr.bin/fstat/fstat.1
--- a/usr.bin/fstat/fstat.1
+++ b/usr.bin/fstat/fstat.1
@@ -44,7 +44,8 @@
.Nm
utility identifies open files.
A file is considered open by a process if it was explicitly opened,
-is the working directory, root directory, jail root directory,
+is the working directory, root directory, alternative root directory,
+jail root directory,
active executable text, or kernel trace file for that process.
If no options are specified,
.Nm
@@ -122,6 +123,8 @@
memory-mapped file
.It Sy root
root inode
+.It Sy altr
+alternative root inode
.It Sy text
executable text inode
.It Sy tr
diff --git a/usr.bin/fstat/fstat.c b/usr.bin/fstat/fstat.c
--- a/usr.bin/fstat/fstat.c
+++ b/usr.bin/fstat/fstat.c
@@ -271,6 +271,8 @@
printf(" wd");
else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
printf(" root");
+ else if (fst->fs_uflags & PS_FST_UFLAG_ADIR)
+ printf(" altr");
else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
printf(" tr");
else if (fst->fs_uflags & PS_FST_UFLAG_MMAP)
diff --git a/usr.bin/fstat/fuser.1 b/usr.bin/fstat/fuser.1
--- a/usr.bin/fstat/fuser.1
+++ b/usr.bin/fstat/fuser.1
@@ -43,7 +43,8 @@
For block and character special devices, all processes using files
on that device are listed.
A file is considered open by a process if it was explicitly opened,
-is the working directory, root directory, jail root directory,
+is the working directory, root directory, alternative root directory,
+jail root directory,
active executable text, kernel trace file or the controlling terminal
of the process.
If
@@ -83,6 +84,8 @@
.It Sy a
The file is open as append only
.Pq Dv O_APPEND No was specified .
+.It Sy b
+The file is the alternative root directory of the process.
.It Sy c
The file is the current workdir directory of the process.
.It Sy d
diff --git a/usr.bin/fstat/fuser.c b/usr.bin/fstat/fuser.c
--- a/usr.bin/fstat/fuser.c
+++ b/usr.bin/fstat/fuser.c
@@ -73,6 +73,7 @@
{PS_FST_UFLAG_RDIR, 'r'},
{PS_FST_UFLAG_CDIR, 'c'},
{PS_FST_UFLAG_JAIL, 'j'},
+ {PS_FST_UFLAG_ADIR, 'b'},
{PS_FST_UFLAG_TRACE, 't'},
{PS_FST_UFLAG_TEXT, 'x'},
{PS_FST_UFLAG_MMAP, 'm'},
diff --git a/usr.bin/procstat/procstat.1 b/usr.bin/procstat/procstat.1
--- a/usr.bin/procstat/procstat.1
+++ b/usr.bin/procstat/procstat.1
@@ -349,7 +349,7 @@
.It COMM
command
.It FD
-file descriptor number or cwd/root/jail
+file descriptor number or cwd/root/jail/altr
.It T
file descriptor type
.It V
diff --git a/usr.bin/procstat/procstat_files.c b/usr.bin/procstat/procstat_files.c
--- a/usr.bin/procstat/procstat_files.c
+++ b/usr.bin/procstat/procstat_files.c
@@ -352,6 +352,8 @@
xo_emit("{P: }{:fd/%s} ", "jail");
else if (fst->fs_uflags & PS_FST_UFLAG_RDIR)
xo_emit("{P: }{:fd/%s} ", "root");
+ else if (fst->fs_uflags & PS_FST_UFLAG_ADIR)
+ xo_emit("{P: }{:fd/%s} ", "altr");
else if (fst->fs_uflags & PS_FST_UFLAG_TEXT)
xo_emit("{P: }{:fd/%s} ", "text");
else if (fst->fs_uflags & PS_FST_UFLAG_TRACE)
diff --git a/usr.sbin/chroot/chroot.8 b/usr.sbin/chroot/chroot.8
--- a/usr.sbin/chroot/chroot.8
+++ b/usr.sbin/chroot/chroot.8
@@ -37,8 +37,16 @@
.Op Fl g Ar group
.Op Fl u Ar user
.Op Fl n
+.Op Fl a
.Ar newroot
.Op Ar command Op Ar arg ...
+.Nm
+.Op Fl G Ar group Ns Op Cm \&, Ns Ar group ...
+.Op Fl g Ar group
+.Op Fl u Ar user
+.Op Fl n
+.Fl A
+.Op Ar command Op Ar arg ...
.Sh DESCRIPTION
The
.Nm
@@ -48,6 +56,15 @@
.Ar command
with provided arguments, if supplied,
or an interactive copy of the user's login shell.
+With the
+.Fl a
+or
+.Fl A
+options,
+.Nm
+instead changes or disables the alternative root, see
+.Xr chaltroot 2 ,
+and does not change the current directory.
.Pp
The options are as follows:
.Bl -tag -width "-G group[,group ...]"
@@ -71,6 +88,14 @@
.Va security.bsd.unprivileged_chroot
sysctl is set to 1, it will make it possible to chroot without
superuser privileges.
+.It Fl a
+Change the alternative root instead of root, see
+.Xr chaltroot 2 .
+.It Fl A
+Disable the alternative root.
+The
+.Ar newroot
+argument must not be provided.
.El
.Sh ENVIRONMENT
The following environment variable is referenced by
diff --git a/usr.sbin/chroot/chroot.c b/usr.sbin/chroot/chroot.c
--- a/usr.sbin/chroot/chroot.c
+++ b/usr.sbin/chroot/chroot.c
@@ -99,7 +99,7 @@
gid_t gid, *gidlist;
uid_t uid;
int arg, ch, error, gids;
- bool nonprivileged;
+ bool altroot, clear_altroot, nonprivileged;
gid = 0;
uid = 0;
@@ -107,7 +107,8 @@
user = group = grouplist = NULL;
gidlist = NULL;
nonprivileged = false;
- while ((ch = getopt(argc, argv, "G:g:u:n")) != -1) {
+ altroot = clear_altroot = false;
+ while ((ch = getopt(argc, argv, "AaG:g:u:n")) != -1) {
switch(ch) {
case 'u':
user = optarg;
@@ -132,6 +133,12 @@
case 'n':
nonprivileged = true;
break;
+ case 'a':
+ altroot = true;
+ break;
+ case 'A':
+ clear_altroot = true;
+ break;
case '?':
default:
usage();
@@ -140,7 +147,9 @@
argc -= optind;
argv += optind;
- if (argc < 1)
+ if (!clear_altroot && argc < 1)
+ usage();
+ if (clear_altroot && altroot)
usage();
if (group != NULL)
@@ -170,13 +179,24 @@
if (error != 0)
err(1, "procctl");
}
-
- if (chdir(argv[0]) == -1)
- err(1, "%s", argv[0]);
- if (chroot(".") == -1) {
- if (errno == EPERM && !nonprivileged && geteuid() != 0)
- errx(1, "unprivileged use requires -n");
- err(1, "%s", argv[0]);
+ if (clear_altroot) {
+ if (chaltroot(NULL) == -1)
+ err(1, "clearing altroot");
+ } else {
+ if (altroot) {
+ error = chaltroot(argv[0]);
+ } else {
+ if (chdir(argv[0]) == -1)
+ err(1, "%s", argv[0]);
+ error = chroot(".");
+ }
+ if (error == -1) {
+ if (errno == EPERM && !nonprivileged && geteuid() != 0)
+ errx(1, "unprivileged use requires -n");
+ err(1, "%s", argv[0]);
+ }
+ argc--;
+ argv++;
}
if (gidlist != NULL && setgroups(gids, gidlist) == -1)
@@ -186,9 +206,9 @@
if (user && setuid(uid) == -1)
err(1, "setuid");
- if (argv[1]) {
- execvp(argv[1], &argv[1]);
- err(1, "%s", argv[1]);
+ if (argc > 0) {
+ execvp(argv[0], argv);
+ err(1, "%s", argv[0]);
}
if (!(shell = getenv("SHELL")))
@@ -202,6 +222,8 @@
usage(void)
{
(void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
- "[-u user] [-n] newroot [command]\n");
+ "[-u user] [-an] newroot [command]\n");
+ (void)fprintf(stderr, " chroot [-g group] [-G group,group,...] "
+ "[-u user] -A [command]\n");
exit(1);
}

File Metadata

Mime Type
text/plain
Expires
Mon, Nov 16, 5:37 AM (21 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41762646
Default Alt Text
D60035.1794807428.diff (38 KB)

Event Timeline