Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177590397
D60035.1794807428.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
38 KB
Referenced Files
None
Subscribers
None
D60035.1794807428.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D60035: chaltroot(2)
Attached
Detach File
Event Timeline