Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F176535270
D60035.id189613.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
D60035.id189613.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) {
+ 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/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,6 +103,63 @@
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 'alternative root' directory.
+If set to a directory for which the process has
+executable permissions, that directory is used as a root for
+absolute path lookups.
+If the lookup succeeds, the result is used.
+If the lookup fails with
+.Ev 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 path
+argument set to 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 images activations on
+.Xr execve 2 .
+.Pp
+The alternative root facility is used by ABI emulators to
+provide a parallel installation of foreign systems 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, kernel automatically resets the alternative root to
+the value assigned to the ABI.
+.Pp
+The
+.Fn fchaltroot
+function 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
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,7 @@
#define AUE_PDRFORK 43273 /* FreeBSD-specific. */
#define AUE_PDOPENPID 43274 /* FreeBSD-specific. */
#define AUE_PDPTRACE 43275 /* FreeBSD-specific. */
+#define AUE_CHALTROOT 43276 /* 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_NULL, .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
@@ -88,9 +88,9 @@
return (0);
}
NDFREE_PNBUF(&nd);
- pwd_altroot(td, nd.ni_vp);
+ error = pwd_altroot(td, nd.ni_vp);
vrele(nd.ni_vp);
- return (0);
+ return (error);
}
void
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_NULL, .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
@@ -4388,36 +4388,45 @@
/*
* Process is transitioning to/from a non-native ABI.
+ *
+ * Non-null altroot_vp assigns the alternative root lookups and
+ * enables it. NULL altroot_vp disables alternative root, alt root is
+ * set to the native root.
*/
-void
+int
pwd_altroot(struct thread *td, struct vnode *altroot_vp)
{
struct pwddesc *pdp;
struct pwd *newpwd, *oldpwd;
+ 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;
+ if (altroot_vp != oldpwd->pwd_adir) {
+ if (altroot_vp != NULL) {
+ /* Native process to a non-native ABI. */
+ vrefact(altroot_vp);
+ newpwd->pwd_adir = altroot_vp;
+ } else {
+ /* Non-native process to the native ABI. */
+ vrefact(oldpwd->pwd_rdir);
+ newpwd->pwd_adir = oldpwd->pwd_rdir;
+ }
+ 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 +5060,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/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_ const char *path
+ );
+ }
+607 AUE_NULL 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_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_unpriv(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_unpriv(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_unpriv(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_unpriv(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/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,21 @@
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;
+
+ 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/sys/filedesc.h b/sys/sys/filedesc.h
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -371,7 +371,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_NULL
#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 altroot
+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(" altroot");
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
@@ -96,6 +97,8 @@
The file is mmapped.
.It Sy r
The file is the root directory of the process.
+.It Sy a
+The file is the alternative root directory of the process.
.It Sy s
Shared lock is hold.
.It Sy t
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, 'a'},
{PS_FST_UFLAG_TRACE, 't'},
{PS_FST_UFLAG_TEXT, 'x'},
{PS_FST_UFLAG_MMAP, 'm'},
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,6 +37,8 @@
.Op Fl g Ar group
.Op Fl u Ar user
.Op Fl n
+.Op Fl a
+.Op Fl A
.Ar newroot
.Op Ar command Op Ar arg ...
.Sh DESCRIPTION
@@ -71,6 +73,11 @@
.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.
.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();
@@ -170,10 +177,17 @@
if (error != 0)
err(1, "procctl");
}
+ if (clear_altroot && chaltroot(NULL) == -1)
+ err(1, "%s: clearing altroot", argv[0]);
- if (chdir(argv[0]) == -1)
- err(1, "%s", argv[0]);
- if (chroot(".") == -1) {
+ 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]);
@@ -202,6 +216,6 @@
usage(void)
{
(void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
- "[-u user] [-n] newroot [command]\n");
+ "[-u user] [-naA] newroot [command]\n");
exit(1);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Oct 20, 3:34 PM (15 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41118776
Default Alt Text
D60035.id189613.diff (28 KB)
Attached To
Mode
D60035: chaltroot(2)
Attached
Detach File
Event Timeline
Log In to Comment