Page MenuHomeFreeBSD

D60035.id189613.diff
No OneTemporary

D60035.id189613.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) {
+ 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

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)

Event Timeline