JavaScript is required to for searching.
Skip Navigation Links
Exit Print View
STREAMS Programming Guide
search filter icon
search icon

Document Information

Preface

Part I Application Programming Interface

1.  Overview of STREAMS

2.  STREAMS Application-Level Components

3.  STREAMS Application-Level Mechanisms

4.  Application Access to the STREAMS Driver and Module Interfaces

5.  STREAMS Administration

6.  Pipes and Queues

Part II Kernel Interface

7.  STREAMS Framework - Kernel Level

8.  STREAMS Kernel-Level Mechanisms

9.  STREAMS Drivers

10.  STREAMS Modules

11.  Configuring STREAMS Drivers and Modules

Kernel Data Structures

modlinkage

modldrv

modlstrmod

dev_ops

cb_ops

streamtab

qinit

STREAMS Driver Entry Points

pts Example

STREAMS Module Configuration

Compilation

Kernel Loading

Checking the Module Type

Tunable Parameters

STREAMS Administrative Driver

Application Interface

STREAMS Anchors

Anchors and Data Flow

Using Anchors

12.  Multithreaded STREAMS

13.  STREAMS Multiplex Drivers

Part III Advanced Topics

14.  Debugging STREAMS-based Applications

Part IV Appendixes

A.  Message Types

B.  Kernel Utility Interface Summary

C.  STREAMS-Based Terminal Subsystem

D.  STREAMS FAQ

Glossary

Index

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.

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);
}