if ((vp->v_mode & I_TYPE) != I_REGULAR)
r = ENOEXEC;
- else if ((r1 = forbidden(vp, X_BIT)) != OK)
+ else if ((r1 = forbidden(fp, vp, X_BIT)) != OK)
r = r1;
else
r = req_stat(vp->v_fs_e, vp->v_inode_nr, VFS_PROC_NR,
if(vp->v_fs_e != vp_d->v_fs_e)
r = EXDEV;
else
- r = forbidden(vp_d, W_BIT | X_BIT);
+ r = forbidden(fp, vp_d, W_BIT | X_BIT);
if (r == OK)
r = req_link(vp->v_fs_e, vp_d->v_inode_nr, user_fullpath,
}
/* The caller must have both search and execute permission */
- if ((r = forbidden(vldirp, X_BIT | W_BIT)) != OK) {
+ if ((r = forbidden(fp, vldirp, X_BIT | W_BIT)) != OK) {
put_vnode(vldirp);
return(r);
}
if(old_dirp->v_fs_e != new_dirp->v_fs_e) r = EXDEV;
/* Parent dirs must be writable, searchable and on a writable device */
- if ((r1 = forbidden(old_dirp, W_BIT|X_BIT)) != OK ||
- (r1 = forbidden(new_dirp, W_BIT|X_BIT)) != OK) r = r1;
+ if ((r1 = forbidden(fp, old_dirp, W_BIT|X_BIT)) != OK ||
+ (r1 = forbidden(fp, new_dirp, W_BIT|X_BIT)) != OK) r = r1;
if(r == OK)
r = req_rename(old_dirp->v_fs_e, old_dirp->v_inode_nr, old_name,
if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code);
/* Ask FS to truncate the file */
- if ((r = forbidden(vp, W_BIT)) == OK)
+ if ((r = forbidden(fp, vp, W_BIT)) == OK)
r = truncate_vnode(vp, m_in.flength);
put_vnode(vp);
if(fetch_name(m_in.name2, m_in.name2_length, M1) != OK) return(err_code);
if ((vp = last_dir(fp)) == NULL) return(err_code);
- if ((r = forbidden(vp, W_BIT|X_BIT)) == OK) {
+ if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
r = req_slink(vp->v_fs_e, vp->v_inode_nr, user_fullpath, who_e,
m_in.name1, m_in.name1_length - 1, fp->fp_effuid,
fp->fp_effgid);
/* Only do the normal open code if we didn't just create the file. */
if(exist) {
/* Check protections. */
- if ((r = forbidden(vp, bits)) == OK) {
+ if ((r = forbidden(fp, vp, bits)) == OK) {
/* Opening reg. files, directories, and special files differ */
switch (vp->v_mode & I_TYPE) {
case I_REGULAR:
/* Truncate regular file if O_TRUNC. */
if (oflags & O_TRUNC) {
- if ((r = forbidden(vp, W_BIT)) != OK)
+ if ((r = forbidden(fp, vp, W_BIT)) != OK)
break;
truncate_vnode(vp, 0);
}
put_vnode(dirp);
return(NULL);
}
- if ((r = forbidden(dirp, W_BIT|X_BIT)) != OK ||
+ if ((r = forbidden(fp, dirp, W_BIT|X_BIT)) != OK ||
(r = req_create(dirp->v_fs_e, dirp->v_inode_nr,bits, fp->fp_effuid,
fp->fp_effgid, user_fullpath, &res)) != OK ) {
/* Can't create inode either due to permissions or some other
return(ENOTDIR);
}
- if ((r = forbidden(vp, W_BIT|X_BIT)) == OK) {
+ if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
r = req_mknod(vp->v_fs_e, vp->v_inode_nr, user_fullpath, fp->fp_effuid,
fp->fp_effgid, bits, m_in.mk_z0);
}
return(ENOTDIR);
}
- if ((r = forbidden(vp, W_BIT|X_BIT)) == OK) {
+ if ((r = forbidden(fp, vp, W_BIT|X_BIT)) == OK) {
r = req_mkdir(vp->v_fs_e, vp->v_inode_nr, user_fullpath, fp->fp_effuid,
fp->fp_effgid, bits);
}
}
/* check permissions */
- r = forbidden(vp, (R_BIT | W_BIT));
+ r = forbidden(rfp, vp, (R_BIT | W_BIT));
put_vnode(vp);
return(r);
if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
if ((vp = eat_path(PATH_NOFLAGS, fp)) == NULL) return(err_code);
- r = forbidden(vp, m_in.mode);
+ r = forbidden(fp, vp, m_in.mode);
put_vnode(vp);
return(r);
}
/*===========================================================================*
* forbidden *
*===========================================================================*/
-PUBLIC int forbidden(struct vnode *vp, mode_t access_desired)
+PUBLIC int forbidden(struct fproc *rfp, struct vnode *vp, mode_t access_desired)
{
/* Given a pointer to an vnode, 'vp', and the access desired, determine
* if the access is allowed, and if not why not. The routine looks up the
/* Isolate the relevant rwx bits from the mode. */
bits = vp->v_mode;
- uid = (call_nr == ACCESS ? fp->fp_realuid : fp->fp_effuid);
- gid = (call_nr == ACCESS ? fp->fp_realgid : fp->fp_effgid);
+ uid = (call_nr == ACCESS ? rfp->fp_realuid : rfp->fp_effuid);
+ gid = (call_nr == ACCESS ? rfp->fp_realgid : rfp->fp_effgid);
if (uid == SU_UID) {
/* Grant read and write permission. Grant search permission for
_PROTOTYPE( int do_chmod, (void) );
_PROTOTYPE( int do_chown, (void) );
_PROTOTYPE( int do_umask, (void) );
-_PROTOTYPE( int forbidden, (struct vnode *vp, mode_t access_desired) );
+_PROTOTYPE( int forbidden, (struct fproc *rfp, struct vnode *vp,
+ mode_t access_desired) );
_PROTOTYPE( int read_only, (struct vnode *vp) );
/* read.c */
if ((vp->v_mode & I_TYPE) != I_DIRECTORY)
r = ENOTDIR;
else
- r = forbidden(vp, X_BIT); /* Check if dir is searchable*/
+ r = forbidden(fp, vp, X_BIT); /* Check if dir is searchable*/
/* If error, return vnode */
if (r != OK) {
/* Only the owner of a file or the super user can change its name. */
r = OK;
if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM;
- if (m_in.utime_length == 0 && r != OK) r = forbidden(vp, W_BIT);
+ if (m_in.utime_length == 0 && r != OK) r = forbidden(fp, vp, W_BIT);
if (read_only(vp) != OK) r = EROFS; /* Not even su can touch if R/O */
if (r == OK) {
/* Issue request */
test30 test31 test32 test34 test35 test36 test37 test38 \
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
test42 test45 test47 test49 test50 test51 test52 test53 \
- test54 test56 test58 t60a t60b
+ test54 test58 t60a t60b
BIGOBJ= test20 test24
-ROOTOBJ= test11 test33 test43 test44 test46 test60 test61
+ROOTOBJ= test11 test33 test43 test44 test46 test56 test60 test61
GCCOBJ= test45-gcc test48 test49-gcc test55
GCCFPUOBJ= test51-gcc test52-gcc
OTHEROBJ= test57 test59
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
- debug("Test bind() success");
-
SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
rc = bind(sd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un));
if (rc == -1) {
}
}
+void test_permissions(void) {
+ /* Test bind and connect for permission verification
+ *
+ * After creating a UDS socket we change user credentials. At that
+ * point we should not be allowed to bind or connect to the UDS socket
+ */
+
+ pid_t pid;
+ int sd, rc, status;
+ struct sockaddr_un addr, client_addr;
+ char buf[10];
+ socklen_t client_addr_size;
+
+ client_addr_size = sizeof(struct sockaddr_un);
+
+ memset(&addr, '\0', sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, TEST_SUN_PATH, sizeof(addr.sun_path) - 1);
+
+ UNLINK(TEST_SUN_PATH);
+
+ pid = fork();
+ if (pid < 0) test_fail("unable to fork");
+ else if (pid == 0) {
+ SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
+ if (setuid(999) != 0) test_fail("unable to chance uid");
+ rc = bind(sd, (struct sockaddr *) &addr,
+ sizeof(struct sockaddr_un));
+ if (rc != -1) {
+ test_fail("bind() should not have worked");
+ }
+ exit(errct);
+ } else {
+ rc = waitpid(pid, &status, 0);
+ errct += WEXITSTATUS(status);
+ }
+
+ /* the signal handler is only used by the client, but we have to
+ * install it now. if we don't the server may signal the client
+ * before the handler is installed.
+ */
+ debug("installing signal handler");
+ if (signal(SIGUSR1, test_xfer_sighdlr) == SIG_ERR) {
+ test_fail("signal(SIGUSR1, test_xfer_sighdlr) failed");
+ }
+
+ debug("signal handler installed");
+
+ server_ready = 0;
+
+ pid = fork();
+ if (pid < 0) test_fail("unable to fork");
+ else if (pid == 0) {
+ while (server_ready == 0) {
+ debug("[client] waiting for the server to signal");
+ sleep(1);
+ }
+ SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
+ if (setuid(999) != 0) test_fail("unable to chance uid");
+ rc = connect(sd, (struct sockaddr *) &addr,
+ sizeof(struct sockaddr_un));
+ if (rc != -1)
+ test_fail("connect should not have worked");
+ exit(errct);
+ } else {
+ int client_sd;
+ SOCKET(sd, PF_UNIX, SOCK_STREAM, 0);
+ rc = bind(sd, (struct sockaddr *) &addr,
+ sizeof(struct sockaddr_un));
+ if (rc == -1) {
+ test_fail("bind() should have worked");
+ }
+
+ rc = listen(sd, 8);
+ if (rc == -1) {
+ test_fail("listen(sd, 8) should have worked");
+ }
+ kill(pid, SIGUSR1);
+ sleep(1);
+ CLOSE(sd);
+
+ rc = waitpid(pid, &status, 0);
+ errct += WEXITSTATUS(status);
+ }
+
+ UNLINK(TEST_SUN_PATH);
+}
+
void test_fd_passing(void) {
int status;
int sv[2];
start(56);
test_socket();
+ test_bind();
test_listen();
test_getsockname();
test_header();
test_shutdown();
test_close();
+ test_permissions();
test_dup();
test_dup2();
test_socketpair();
test_write();
test_sockopts();
test_ucred();
- test_bind();
test_xfer();
for (i = 0; i < 3; i++) {
test_multiproc_write();
test_scm_credentials();
test_fd_passing();
-
quit();
return -1; /* we should never get here */