summaryrefslogtreecommitdiffstats
path: root/sys/security/lomac/kernel_pipe.c
blob: 3aee257587daa73ff99b3f4c50c6b14bfc84c887 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/*-
 * Copyright (c) 2001 Networks Associates Technology, Inc.
 * All rights reserved.
 *
 * This software was developed for the FreeBSD Project by NAI Labs, the
 * Security Research Division of Network Associates, Inc. under
 * DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA
 * CHATS research program.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Id$
 * $FreeBSD$
 */

/*
 * This file contains part of LOMAC's interface to the kernel.  This
 * part allows LOMAC to monitor (unnamed) pipe read and write
 * operations by interposing control on the kernel's pipeops vector.
 *
 * The pipeops vector is defined in kern/sys_pipe.c.
 * 
 * USAGE:
 *
 * The LOMAC LKM should call lomac_initialize_pipes() at LKM load time.
 * This function turns unnamed pipe interposition on by modifying
 * the function addresses in pipeops.
 *
 * Once the LOMAC LKM turns interposition on, all reads and writes
 * will pass through this file's monitoring functions.
 *
 * This file provides a lomac_uninitialize_pipes() function which
 * turns unnamed pipe interposition off by restoring pipeops to
 * its original unmodified state.  Once the LOMAC LKM turns
 * interposition off, subsequent unnamed pipe reads and writes
 * will not pass through this file's monitoring functions.
 *
 * HOW LOMAC HANDLES PIPES: 
 *
 * (This text describes how LOMAC handles (unnamed) pipes in terms of
 * abstract architecture-independent concepts.)  LOMAC does not treat
 * pipes as objects, as it does files.  When the kernel creates a new
 * pipe, LOMAC assigns it the highest level.  Whenever a process
 * writes to the pipe, LOMAC reduces the pipe's level to match the
 * level of the writing process.  Whenever a process reads from a
 * pipe, LOMAC reduces the level of the reading process to match the
 * pipe's level.  As a result, if a high-level process reads the
 * output of a low-level process through a pipe, the reading process
 * will wind up at the low level.
 * 
 * It takes two `struct pipe's to make a pipe.  We set the level
 * information in both `struct pipes', and keep them synchronized.
 *                                                                        
 * This code presently relies on the one-big-kernel-lock to
 * synchronize its access to the `pipe_state' field of each `struct
 * pipe'.
 *                                                                        
 */

#include <sys/types.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/file.h>
#include <sys/selinfo.h>
#include <sys/pipe.h>
#include <sys/proc.h>
#include <sys/uio.h>

#include "lomac.h"
#include "kernel_interface.h"
#include "kernel_monitor.h"
#include "kernel_pipe.h"


/* `pipeops' is the kernel's pipe operations vector for the file       *
 * structure.  All reads and writes to pipes call through this vector. */
extern struct fileops pipeops;           /* defined in kern/sys_pipe.c */


/* These vars store the original addresses of the pipeops read and *
 * write operations, so we can call them, and even restore them    *
 * later if we want to.                                            */
static int (*pipe_read_orig)(struct file *, struct uio *, struct ucred *,
    int, struct thread *);
static int (*pipe_write_orig)(struct file *, struct uio *, struct ucred *,
    int, struct thread *);


/* declarations of functions private to this module: */
static int lomac_pipe_read(struct file *, struct uio *, struct ucred *, 
    int, struct thread *);
static int lomac_pipe_write(struct file *, struct uio *, struct ucred *, 
    int, struct thread *);

/* -------------------- public functions ---------------------------- */

/* lomac_initialize_pipes()
 *
 * in:     nothing
 * out:    nothing
 * return: 0
 *
 * Turns pipe interposition on by replacing the pipe_read() and pipe_write()
 * operations in the kernel's pipeops vector with lomac_pipe_read() and
 * lomac_pipe_write().  Saves the addresses of the original operations
 * so other functions can call them, and so pipe_interposition_off()
 * can restore the pipeops vector to its original unmodified state.
 *
 */

int
lomac_initialize_pipes(void) {

	pipe_read_orig  = pipeops.fo_read;
	pipeops.fo_read = lomac_pipe_read;
	pipe_write_orig  = pipeops.fo_write;
	pipeops.fo_write = lomac_pipe_write;
	return (0);
} /* lomac_initialize_pipes() */


/* lomac_uninitialize_pipes()
 *
 * in:     nothing
 * out:    nothing
 * return: 0
 *
 * Turns pipe interposition off by restoring the pipeops vector to its
 * original unmodified state.
 *
 * See note at top of file regarding this function and unloading the
 * LOMAC LKM.
 *
 */

int
lomac_uninitialize_pipes(void) {

	KASSERT(pipe_read_orig,  ("LOMAC:pipe interpositon off before on"));
	KASSERT(pipe_write_orig, ("LOMAC:pipe interpositon off before on"));
	pipeops.fo_read  = pipe_read_orig;
	pipeops.fo_write = pipe_write_orig;
	return (0);
} /* lomac_uninitialize_pipes() */



/* ------------------- private functions --------------------------- */

#ifndef MIN
#define	MIN(lo, mac) ((lo) < (mac) ? (lo) : (mac))
#endif

/* lomac_pipe_read()
 *
 * Passes the read operation down to pipe_read_orig().  If
 * pipe_read_orig() returns success, examines the level of the pipe
 * and the reading process.  If the reading process has a higher
 * level, reduces the level of the process to equal the pipe's level.
 *
 */

static int
lomac_pipe_read(struct file *fp, struct uio *uio, struct ucred *cred, 
    int flags, struct thread *td) {
	lomac_object_t read_pipe;     /* attrs are in read end of pipe */
	struct uio kuio;
	struct iovec kiov;
	void *buf;
	int len;
	int ret_val;                            /* holds return values */

	len = MIN(uio->uio_resid, BIG_PIPE_SIZE);
	kiov.iov_base = buf = malloc(len, M_TEMP, M_WAITOK);
	kiov.iov_len = len;
	kuio.uio_iov = &kiov;
	kuio.uio_iovcnt = 1;
	kuio.uio_offset = 0;
	kuio.uio_resid = len;
	kuio.uio_segflg = UIO_SYSSPACE;
	kuio.uio_rw = UIO_READ;
	kuio.uio_td = td;
	ret_val = pipe_read_orig(fp, &kuio, cred, flags, td);
	if (ret_val == 0) {
		read_pipe.lo_type = LO_TYPE_PIPE;
		read_pipe.lo_object.pipe = (struct pipe *)fp->f_data;
		(void)monitor_read_object(td->td_proc, &read_pipe);
		ret_val = uiomove(buf, len - kuio.uio_resid, uio);
	}
	free(buf, M_TEMP);
	return (ret_val);
} /* lomac_pipe_read() */ 


/* lomac_pipe_write()
 *
 * Passes the write operation down to pipe_write_orig().  If
 * pipe_write_orig() returns success, examines the level of the pipe
 * and the writing process.  If the pipe has a higher level than the
 * writing process, this function reduces the pipe's level to equal
 * the level of the writing process.
 *
 */

static int
lomac_pipe_write(struct file *fp, struct uio *uio, struct ucred *cred, 
    int flags, struct thread *td) {
	lomac_object_t pipe;   
	int ret_val;                            /* holds return values */

	pipe.lo_type = LO_TYPE_PIPE;
	pipe.lo_object.pipe = (struct pipe *)fp->f_data;
	ret_val = monitor_pipe_write(td->td_proc, &pipe);
	if (ret_val == 0)
		ret_val = pipe_write_orig(fp, uio, cred, flags, td);

	return (ret_val);
} /* lomac_pipe_write() */ 
OpenPOWER on IntegriCloud