diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c --- a/sys/kern/sys_socket.c +++ b/sys/kern/sys_socket.c @@ -90,6 +90,7 @@ extern fo_kqfilter_t soo_kqfilter; static fo_stat_t soo_stat; static fo_close_t soo_close; +static fo_chmod_t soo_chmod; static fo_fill_kinfo_t soo_fill_kinfo; static fo_aio_queue_t soo_aio_queue; @@ -104,7 +105,7 @@ .fo_kqfilter = soo_kqfilter, .fo_stat = soo_stat, .fo_close = soo_close, - .fo_chmod = invfo_chmod, + .fo_chmod = soo_chmod, .fo_chown = invfo_chown, .fo_sendfile = invfo_sendfile, .fo_fill_kinfo = soo_fill_kinfo, @@ -353,6 +354,20 @@ return (error); } +static int +soo_chmod(struct file *fp, mode_t mode, struct ucred *cred, struct thread *td) +{ + struct socket *so; + int error; + + so = fp->f_data; + if (so->so_proto->pr_chmod != NULL) + error = so->so_proto->pr_chmod(so, mode, cred, td); + else + error = EINVAL; + return (error); +} + static int soo_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp) { diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -484,6 +484,7 @@ unp->unp_socket = so; so->so_pcb = unp; refcount_init(&unp->unp_refcount, 1); + unp->unp_mode = ACCESSPERMS; if ((locked = UNP_LINK_WOWNED()) == false) UNP_LINK_WLOCK(); @@ -526,6 +527,7 @@ struct mount *mp; cap_rights_t rights; char *buf; + mode_t mode; if (nam->sa_family != AF_UNIX) return (EAFNOSUPPORT); @@ -558,6 +560,7 @@ return (EALREADY); } unp->unp_flags |= UNP_BINDING; + mode = unp->unp_mode; UNP_PCB_UNLOCK(unp); buf = malloc(namelen + 1, M_TEMP, M_WAITOK); @@ -590,7 +593,7 @@ } VATTR_NULL(&vattr); vattr.va_type = VSOCK; - vattr.va_mode = (ACCESSPERMS & ~td->td_proc->p_pd->pd_cmask); + vattr.va_mode = (mode & ~td->td_proc->p_pd->pd_cmask); #ifdef MAC error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd, &vattr); @@ -702,6 +705,26 @@ } } +static int +uipc_chmod(struct socket *so, mode_t mode, struct ucred *cred __unused, + struct thread *td __unused) +{ + struct unpcb *unp; + int error; + + unp = sotounpcb(so); + + error = 0; + UNP_PCB_LOCK(unp); + if (unp->unp_vnode == NULL || (unp->unp_flags & UNP_BINDING) != 0 || + (mode & ~ACCESSPERMS) != 0) + error = EINVAL; + else + unp->unp_mode = mode; + UNP_PCB_UNLOCK(unp); + return (error); +} + static int uipc_connect2(struct socket *so1, struct socket *so2) { @@ -3357,6 +3380,7 @@ .pr_sockaddr = uipc_sockaddr, .pr_soreceive = soreceive_generic, .pr_close = uipc_close, + .pr_chmod = uipc_chmod, }; static struct protosw dgramproto = { @@ -3380,6 +3404,7 @@ .pr_sockaddr = uipc_sockaddr, .pr_soreceive = uipc_soreceive_dgram, .pr_close = uipc_close, + .pr_chmod = uipc_chmod, }; static struct protosw seqpacketproto = { @@ -3411,6 +3436,7 @@ .pr_sockaddr = uipc_sockaddr, .pr_soreceive = soreceive_generic, /* XXX: or...? */ .pr_close = uipc_close, + .pr_chmod = uipc_chmod, }; static struct domain localdomain = { diff --git a/sys/sys/protosw.h b/sys/sys/protosw.h --- a/sys/sys/protosw.h +++ b/sys/sys/protosw.h @@ -32,6 +32,8 @@ #ifndef _SYS_PROTOSW_H_ #define _SYS_PROTOSW_H_ +#include + /* Forward declare these structures referenced from prototypes below. */ struct kaiocb; struct mbuf; @@ -100,6 +102,8 @@ typedef int pr_connectat_t(int, struct socket *, struct sockaddr *, struct thread *); typedef int pr_aio_queue_t(struct socket *, struct kaiocb *); +typedef int pr_chmod_t(struct socket *, __mode_t, struct ucred *, + struct thread *); struct protosw { short pr_type; /* socket type used for */ @@ -139,6 +143,7 @@ pr_sense_t *pr_sense; /* stat(2) */ pr_sosetlabel_t *pr_sosetlabel; /* MAC, XXXGL: remove */ pr_setsbopt_t *pr_setsbopt; /* Socket buffer ioctls */ + pr_chmod_t *pr_chmod; /* fchmod(2) */ }; /*#endif*/ diff --git a/sys/sys/unpcb.h b/sys/sys/unpcb.h --- a/sys/sys/unpcb.h +++ b/sys/sys/unpcb.h @@ -93,6 +93,7 @@ u_int unp_msgcount; /* (g) references from message queue */ u_int unp_gcrefs; /* (g) garbage collector refcount */ ino_t unp_ino; /* (g) fake inode number */ + mode_t unp_mode; /* (g) initial pre-bind() mode */ LIST_ENTRY(unpcb) unp_dead; /* (g) link in dead list */ } __aligned(CACHE_LINE_SIZE);