Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F133624604
D47361.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
7 KB
Referenced Files
None
Subscribers
None
D47361.diff
View Options
diff --git a/lib/libsys/chmod.2 b/lib/libsys/chmod.2
--- a/lib/libsys/chmod.2
+++ b/lib/libsys/chmod.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 30, 2021
+.Dd October 31, 2024
.Dt CHMOD 2
.Os
.Sh NAME
@@ -214,6 +214,13 @@
by protecting set-user-id (set-group-id) files
from remaining set-user-id (set-group-id) if they are modified,
at the expense of a degree of compatibility.
+.Pp
+While it is normally an error to invoke
+.Fn fchmod
+on a socket, it is possible to do so on
+.Dv AF_LOCAL
+sockets before they are bound to a file name; see
+.Xr unix 4 .
.Sh RETURN VALUES
.Rv -std
.Sh ERRORS
diff --git a/share/man/man4/unix.4 b/share/man/man4/unix.4
--- a/share/man/man4/unix.4
+++ b/share/man/man4/unix.4
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 1, 2022
+.Dd October 31, 2024
.Dt UNIX 4
.Os
.Sh NAME
@@ -77,6 +77,15 @@
.Xr unlink 2
must be used to remove the file.
.Pp
+Prior to binding a socket,
+.Xr fchmod 2
+can be used to set the permissions of the socket file.
+This avoids the race that would otherwise occur between creation of the file
+and a subsequent call to
+.Xr chmod 2 .
+Once the socket is bound to a file name, the permissions of the file can not be
+changed this way.
+.Pp
The length of
.Ux Ns -domain
address, required by
@@ -441,6 +450,7 @@
.Sh SEE ALSO
.Xr connect 2 ,
.Xr dup 2 ,
+.Xr fchmod 2 ,
.Xr fcntl 2 ,
.Xr getsockopt 2 ,
.Xr listen 2 ,
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 & ~td->td_proc->p_pd->pd_cmask;
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;
#ifdef MAC
error = mac_vnode_check_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
&vattr);
@@ -702,6 +705,27 @@
}
}
+static int
+uipc_chmod(struct socket *so, mode_t mode, struct ucred *cred __unused,
+ struct thread *td __unused)
+{
+ struct unpcb *unp;
+ int error;
+
+ if ((mode & ~ACCESSPERMS) != 0)
+ return (EINVAL);
+
+ error = 0;
+ unp = sotounpcb(so);
+ UNP_PCB_LOCK(unp);
+ if (unp->unp_vnode != NULL || (unp->unp_flags & UNP_BINDING) != 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 +3381,7 @@
.pr_sockaddr = uipc_sockaddr,
.pr_soreceive = soreceive_generic,
.pr_close = uipc_close,
+ .pr_chmod = uipc_chmod,
};
static struct protosw dgramproto = {
@@ -3380,6 +3405,7 @@
.pr_sockaddr = uipc_sockaddr,
.pr_soreceive = uipc_soreceive_dgram,
.pr_close = uipc_close,
+ .pr_chmod = uipc_chmod,
};
static struct protosw seqpacketproto = {
@@ -3411,6 +3437,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 <sys/_types.h>
+
/* 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);
diff --git a/tests/sys/kern/unix_dgram.c b/tests/sys/kern/unix_dgram.c
--- a/tests/sys/kern/unix_dgram.c
+++ b/tests/sys/kern/unix_dgram.c
@@ -25,13 +25,15 @@
* SUCH DAMAGE.
*/
-#include <sys/time.h>
#include <sys/event.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <sys/sysctl.h>
+#include <sys/time.h>
#include <sys/un.h>
+
#include <aio.h>
#include <errno.h>
#include <fcntl.h>
@@ -391,12 +393,49 @@
ATF_REQUIRE(close(sd) == 0);
}
+ATF_TC_WITHOUT_HEAD(fchmod);
+ATF_TC_BODY(fchmod, tc)
+{
+ struct stat sb;
+ struct sockaddr_un sun;
+ int error, sd;
+
+ memset(&sun, 0, sizeof(sun));
+ sun.sun_len = sizeof(sun);
+ sun.sun_family = AF_UNIX;
+ strlcpy(sun.sun_path, "sock", sizeof(sun.sun_path));
+
+ sd = socket(PF_UNIX, SOCK_DGRAM, 0);
+ ATF_REQUIRE(sd != -1);
+
+ error = fchmod(sd, 0600 | S_ISUID);
+ ATF_REQUIRE_ERRNO(EINVAL, error == -1);
+
+ umask(0022);
+ error = fchmod(sd, 0766);
+ ATF_REQUIRE(error == 0);
+
+ error = bind(sd, (struct sockaddr *)&sun, sizeof(sun));
+ ATF_REQUIRE(error == 0);
+
+ error = stat(sun.sun_path, &sb);
+ ATF_REQUIRE(error == 0);
+ ATF_REQUIRE_MSG((sb.st_mode & 0777) == 0744,
+ "sb.st_mode = %o", sb.st_mode);
+
+ error = fchmod(sd, 0666);
+ ATF_REQUIRE_ERRNO(EINVAL, error == -1);
+
+ ATF_REQUIRE(close(sd) == 0);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, basic);
ATF_TP_ADD_TC(tp, one2many);
ATF_TP_ADD_TC(tp, event);
ATF_TP_ADD_TC(tp, selfgetpeername);
+ ATF_TP_ADD_TC(tp, fchmod);
return (atf_no_error());
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Oct 28, 2:48 AM (14 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24272730
Default Alt Text
D47361.diff (7 KB)
Attached To
Mode
D47361: unix: Add support for atomically setting the socket mode
Attached
Detach File
Event Timeline
Log In to Comment