Skip Navigation Links | |
Exit Print View | |
STREAMS Programming Guide Oracle Solaris 11.1 Information Library |
Part I Application Programming Interface
2. STREAMS Application-Level Components
3. STREAMS Application-Level Mechanisms
4. Application Access to the STREAMS Driver and Module Interfaces
7. STREAMS Framework - Kernel Level
8. STREAMS Kernel-Level Mechanisms
11. Configuring STREAMS Drivers and Modules
14. Debugging STREAMS-based Applications
B. Kernel Utility Interface Summary
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.
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.
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); }