Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
11.  Configuring STREAMS Drivers and Modules STREAMS Administrative Driver Application Interface  Previous   Contents   Next 
   
 
SAP_ONE

Configures a single minor device, sap_minor, of a driver

SAP_RANGE

Configures a range of minor devices from sap_minor to sap_lastminor, inclusive

SAP_ALL

Configures all minor devices of a device

SAP_CLEAR

Clears the previous settings by removing the entry with the matching sap_major and sap_minor fields

The list of modules is specified as a list of module names in sap_list. MAXAPUSH defines the maximum number of modules to push automatically.

A user can query the current configuration status of a given major/minor device by issuing the SAD_GAP ioctl(2) with sap_major and sap_minor values of the device set. On successful return from this system call, the strapush structure is filled in with the corresponding information for the device. The maximum number of entries that the SAD driver can cache is determined by the tunable parameter NAUTOPUSH which is found in the SAD driver's master file.

The following is an example of an autopush configuration file in /etc/iu.ap:

#	major      minor         lastminor      modules

	wc         0             0              ldterm ttcompat
	zs         0             1              ldterm ttcompat
	ptsl       0             15             ldterm ttcompat

The first line configures a single minor device whose major name is wc. Minor numbers start and end at 0, creating only one minor number. The modules automatically pushed are ldterm and ttcompat. The second line configures the zs driver whose minor device numbers are 0 and 1, and automatically pushes the same modules. The last line configures the ptsl driver whose minor device numbers are from 0 to 15, and automatically pushes the same modules.

STREAMS Anchors

An anchor is a lock that prevents the removal of a STREAMS module with an I_POP call. You place an anchor in a stream on the module you want to lock. All modules at or below the anchor are locked, and can only be popped by a privileged process.

An anchor is a lock that prevents the removal of a STREAMS module with an I_POP call. You place an anchor in a stream on the module you want to lock. All modules at or below the anchor are locked, and can only be popped by a privileged process.

Anchors and Data Flow


Note - Hardening Information. Anchors do not affect the flow of data in the stream or any other properties of the stream other than to lock down its plumbing. Any process can place an anchor on a stream, but once placed, it can only be removed by a privileged process.


An anchor is a per-stream entity; that is, there is exactly one per stream, and the anchor is moved upstream or downstream as needed. When a stream is created, the anchor is conceptually at the driver and therefore has no effect on the stream. By issuing the I_ANCHOR ioctl on a stream, a process places the anchor at the STREAMS module directly below the stream head. This means that a process can move an existing anchor upstream by pushing additional STREAMS modules and calling I_ANCHOR again.

Although anchors conceptually exist at a specific location in the stream, they are not a data processing element and therefore do not physically exist in the stream (for example, you will not find them parsing q_next pointers.) This means that anchors will not appear in ioctls such as I_LOOK, and they are not included in the module count on the stream.

To remove an anchor, a process pops the module at which the anchor was placed. The anchor will only allow a privileged process to pop modules at or below it, which provides security. Once an anchor has been removed, the anchor is not reset to its previous location in the stream, but rather positioned at the STREAMS driver again. When an unprivileged process attempts to pop an anchored module, the ioctl returns with EPERM.

The I_ANCHOR ioctl is processed completely in the stream head, and is never sent downstream. If a module or driver sends an I_ANCHOR to the stream head, the anchor is silently discarded.

Using Anchors

An anchor can be placed on a STREAMS module by adding an [anchor] flag to an autopush configuration file or by directly calling the I_ANCHOR ioctl.

For example, this configuration file specifies that autopush should place an anchor between foo and babar in the bb stream:

#	major      minor       lastminor     modules

	aa         0           0             foo babar
	bb         0           1             foo [anchor] babar
	bb         131072      131073        foo [anchor] babar

The following two examples illustrate the use of anchors in a client/server setting in which file descriptors are being passed. They call the I_ANCHOR ioctl directly.

In this example, the server program, fd_server.c, opens a stream, pushes modules on to it, and places an anchor on rlmod. The client program, fd_client.c attempts to pop modules, but can only pop rlmod or any modules below it if the client is run as root. That is, if the client is run as non-root, the I_POP fails.

This example also shows that once the module with the anchor on it is popped by the privileged root process, the anchor is destroyed (technically, it is moved back to the driver, where it has no effect). Subsequent attempts by the client to pop modules will succeed, even if the client is run as non-root.

Finally, this example also illustrates the effect of passing file descriptors, rather than copying modules or the stream as a whole. Specifically, because the stream is not duplicated, all instances of the client operate on the same stream. In this case, running the client repeatedly causes it to work down the list of modules, popping each one off in turn, until all modules have been removed from the stream.


Example 11-4 STREAMS Anchors fd_server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <stropts.h>
#include <sys/conf.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

#define	SPIPE_PATH	"/tmp/mypipe"

int
main(void)
{
	int 			pipefd[2];
	struct strrecvfd	strrecvfd;
	int			streamfd;

	/*
	 * Open a stream to hand back to the client.  Since this
	 * is just an example, we don't really care what we open;
	 * make a rlmod<->udp<->ip stream.  Stick an anchor above
	 * rlmod so the client cannot I_POP rlmod unless it's root.
	 */
	streamfd = open("/dev/udp", O_RDWR);
	if (streamfd == -1) {
		perror("open");
		return (EXIT_FAILURE);
	}

	if (ioctl(streamfd, I_PUSH, "rlmod") == -1) {
		perror("ioctl (I_PUSH) rlmod");
		return (EXIT_FAILURE);
	}

	if (ioctl(streamfd, I_ANCHOR, 0) == -1) {
		perror("ioctl (I_ANCHOR)");
		return (EXIT_FAILURE);
	}

	/*
	 * Open ourselves for business by making a mounted stream.
	 */
	if (pipe(pipefd) == -1) {
		perror("pipe");
		return (EXIT_FAILURE);
	}

	if (ioctl(pipefd[1], I_PUSH, "connld") == -1) {
		perror("ioctl (I_PUSH) connld");
		return (EXIT_FAILURE);
	}

	(void) umask(0);
	(void) close(creat(SPIPE_PATH, 0666));

	if (fattach(pipefd[1], SPIPE_PATH) == -1) {
		perror("fattach");
		return (EXIT_FAILURE);
	}

	/*
	 * Accept clients (iterative server)
	 */
	for (;;) {

		if (ioctl(pipefd[0], I_RECVFD, &strrecvfd) == -1) {
			perror("ioctl (I_RECVFD)");
			return (EXIT_FAILURE);
		}

		/*
		 * Send the STREAMS descriptor back to the client.
		 */
		if (ioctl(strrecvfd.fd, I_SENDFD, streamfd) == -1) {
			perror("ioctl (I_SENDFD)");
			return (EXIT_FAILURE);
		}
	}
}


Example 11-5 STREAMS Anchors fd_client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <stropts.h>
#include <sys/conf.h>
#include <unistd.h>
#include <stdlib.h>

#define	SPIPE_PATH	"/tmp/mypipe"

int
main(void)
{
	int 			serverfd;
	struct strrecvfd	strrecvfd;

	/*
	 * Open a connection to the server.
	 */
	serverfd = open(SPIPE_PATH, O_RDWR);
	if (serverfd == -1) {
		perror("open");
		return (EXIT_FAILURE);
	}

	/*
	 * Receive the STREAMS descriptor from the server.
	 */
	if (ioctl(serverfd, I_RECVFD, &strrecvfd) == -1) {
		perror("ioctl (I_RECVFD)");
		return (EXIT_FAILURE);
	}

	(void) printf("received the STREAMS descriptor; attempting to pop "
	    "the top module\n");

	/*
	 * Try to remove the top module from the stream.
	 */
	if (ioctl(strrecvfd.fd, I_POP, 0) == -1)
		perror("ioctl (I_POP)");

	(void) printf("modules on the stream: ");
	(void) fflush(stdout);

	/*
	 * Print out what the stream currently looks like.
	 */
	(void) dup2(strrecvfd.fd, 0);
	(void) system("strconf | paste -s -d' ' -");

	return (EXIT_SUCCESS);
}

 
 
 
  Previous   Contents   Next