1145519Sdarrenr/*	$FreeBSD$	*/
2145510Sdarrenr
3145510Sdarrenr/*
4255332Scy * Copyright (C) 2012 by Darren Reed.
5145510Sdarrenr *
6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing.
7145510Sdarrenr */
8145510Sdarrenr/*
9145510Sdarrenr * kmemcpy() - copies n bytes from kernel memory into user buffer.
10145510Sdarrenr * returns 0 on success, -1 on error.
11145510Sdarrenr */
12145510Sdarrenr
13145510Sdarrenr#include <stdio.h>
14145510Sdarrenr#include <sys/param.h>
15145510Sdarrenr#include <sys/types.h>
16145510Sdarrenr#include <sys/uio.h>
17145510Sdarrenr#include <unistd.h>
18145510Sdarrenr#include <string.h>
19145510Sdarrenr#include <fcntl.h>
20145510Sdarrenr#include <sys/file.h>
21153881Sguido#if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && !defined(linux) && !defined(_AIX51)
22145510Sdarrenr#include <kvm.h>
23145510Sdarrenr#endif
24145510Sdarrenr#include <fcntl.h>
25145510Sdarrenr#include <sys/socket.h>
26145510Sdarrenr#include <sys/ioctl.h>
27145510Sdarrenr#include <netinet/in.h>
28145510Sdarrenr#include <arpa/inet.h>
29145510Sdarrenr#include <netinet/in_systm.h>
30145510Sdarrenr#include <netinet/ip.h>
31145510Sdarrenr#include <net/if.h>
32145510Sdarrenr#if __FreeBSD_version >= 300000
33145510Sdarrenr# include <net/if_var.h>
34145510Sdarrenr#endif
35145510Sdarrenr#if defined(linux) || defined(__osf__) || defined(__sgi) || defined(__hpux)
36145510Sdarrenr# include <stdlib.h>
37145510Sdarrenr#endif
38145510Sdarrenr
39145510Sdarrenr#include "kmem.h"
40145510Sdarrenr
41145510Sdarrenr#ifndef __STDC__
42145510Sdarrenr# define	const
43145510Sdarrenr#endif
44145510Sdarrenr
45145510Sdarrenr#if !defined(lint)
46145510Sdarrenrstatic const char sccsid[] = "@(#)kmem.c	1.4 1/12/96 (C) 1992 Darren Reed";
47255332Scystatic const char rcsid[] = "@(#)$Id$";
48145510Sdarrenr#endif
49145510Sdarrenr
50145510Sdarrenr
51145510Sdarrenr
52153881Sguido#if !defined(__sgi) && !defined(__hpux) && !defined(__osf__) && \
53153881Sguido    !defined(linux) && !defined(_AIX51)
54145510Sdarrenr/*
55145510Sdarrenr * For all platforms where there is a libkvm and a kvm_t, we use that...
56145510Sdarrenr */
57145510Sdarrenrstatic	kvm_t	*kvm_f = NULL;
58145510Sdarrenr
59145510Sdarrenr#else
60145510Sdarrenr/*
61145510Sdarrenr *...and for the others (HP-UX, IRIX, Tru64), we have to provide our own.
62145510Sdarrenr */
63145510Sdarrenr
64145510Sdarrenrtypedef	int *	kvm_t;
65145510Sdarrenr
66145510Sdarrenrstatic	kvm_t	kvm_f = NULL;
67145510Sdarrenrstatic	char	*kvm_errstr = NULL;
68145510Sdarrenr
69145510Sdarrenrkvm_t kvm_open __P((char *, char *, char *, int, char *));
70145510Sdarrenrint kvm_read __P((kvm_t, u_long, char *, size_t));
71145510Sdarrenr
72145510Sdarrenrkvm_t kvm_open(kernel, core, swap, mode, errstr)
73255332Scy	char *kernel, *core, *swap;
74255332Scy	int mode;
75255332Scy	char *errstr;
76145510Sdarrenr{
77145510Sdarrenr	kvm_t k;
78145510Sdarrenr	int fd;
79145510Sdarrenr
80145510Sdarrenr	kvm_errstr = errstr;
81145510Sdarrenr
82145510Sdarrenr	if (core == NULL)
83145510Sdarrenr		core = "/dev/kmem";
84145510Sdarrenr
85145510Sdarrenr	fd = open(core, mode);
86145510Sdarrenr	if (fd == -1)
87145510Sdarrenr		return NULL;
88145510Sdarrenr	k = malloc(sizeof(*k));
89145510Sdarrenr	if (k == NULL)
90145510Sdarrenr		return NULL;
91145510Sdarrenr	*k = fd;
92145510Sdarrenr	return k;
93145510Sdarrenr}
94145510Sdarrenr
95145510Sdarrenrint kvm_read(kvm, pos, buffer, size)
96255332Scy	kvm_t kvm;
97255332Scy	u_long pos;
98255332Scy	char *buffer;
99255332Scy	size_t size;
100145510Sdarrenr{
101145510Sdarrenr	int r = 0, left;
102145510Sdarrenr	char *bufp;
103145510Sdarrenr
104145510Sdarrenr	if (lseek(*kvm, pos, 0) == -1) {
105145510Sdarrenr		if (kvm_errstr != NULL) {
106145510Sdarrenr			fprintf(stderr, "%s", kvm_errstr);
107145510Sdarrenr			perror("lseek");
108145510Sdarrenr		}
109145510Sdarrenr		return -1;
110145510Sdarrenr	}
111145510Sdarrenr
112145510Sdarrenr	for (bufp = buffer, left = size; left > 0; bufp += r, left -= r) {
113145510Sdarrenr		r = read(*kvm, bufp, left);
114145510Sdarrenr#ifdef	__osf__
115145510Sdarrenr		/*
116145510Sdarrenr		 * Tru64 returns "0" for successful operation, not the number
117145510Sdarrenr		 * of bytes read.
118145510Sdarrenr		 */
119145510Sdarrenr		if (r == 0)
120145510Sdarrenr			r = left;
121145510Sdarrenr#endif
122145510Sdarrenr		if (r <= 0)
123145510Sdarrenr			return -1;
124145510Sdarrenr	}
125145510Sdarrenr	return r;
126145510Sdarrenr}
127145510Sdarrenr#endif /* !defined(__sgi) && !defined(__hpux) && !defined(__osf__) */
128145510Sdarrenr
129145510Sdarrenrint	openkmem(kern, core)
130255332Scy	char	*kern, *core;
131145510Sdarrenr{
132145510Sdarrenr	kvm_f = kvm_open(kern, core, NULL, O_RDONLY, NULL);
133145510Sdarrenr	if (kvm_f == NULL)
134145510Sdarrenr	    {
135145510Sdarrenr		perror("openkmem:open");
136145510Sdarrenr		return -1;
137145510Sdarrenr	    }
138145510Sdarrenr	return kvm_f != NULL;
139145510Sdarrenr}
140145510Sdarrenr
141145510Sdarrenrint	kmemcpy(buf, pos, n)
142255332Scy	register char	*buf;
143255332Scy	long	pos;
144255332Scy	register int	n;
145145510Sdarrenr{
146145510Sdarrenr	register int	r;
147145510Sdarrenr
148145510Sdarrenr	if (!n)
149145510Sdarrenr		return 0;
150145510Sdarrenr
151145510Sdarrenr	if (kvm_f == NULL)
152145510Sdarrenr		if (openkmem(NULL, NULL) == -1)
153145510Sdarrenr			return -1;
154145510Sdarrenr
155145510Sdarrenr	while ((r = kvm_read(kvm_f, pos, buf, n)) < n)
156145510Sdarrenr		if (r <= 0)
157145510Sdarrenr		    {
158145510Sdarrenr			fprintf(stderr, "pos=0x%lx ", (u_long)pos);
159145510Sdarrenr			perror("kmemcpy:read");
160145510Sdarrenr			return -1;
161145510Sdarrenr		    }
162145510Sdarrenr		else
163145510Sdarrenr		    {
164145510Sdarrenr			buf += r;
165145510Sdarrenr			pos += r;
166145510Sdarrenr			n -= r;
167145510Sdarrenr		    }
168145510Sdarrenr	return 0;
169145510Sdarrenr}
170145510Sdarrenr
171145510Sdarrenrint	kstrncpy(buf, pos, n)
172255332Scy	register char	*buf;
173255332Scy	long	pos;
174255332Scy	register int	n;
175145510Sdarrenr{
176145510Sdarrenr	register int	r;
177145510Sdarrenr
178145510Sdarrenr	if (!n)
179145510Sdarrenr		return 0;
180145510Sdarrenr
181145510Sdarrenr	if (kvm_f == NULL)
182145510Sdarrenr		if (openkmem(NULL, NULL) == -1)
183145510Sdarrenr			return -1;
184145510Sdarrenr
185145510Sdarrenr	while (n > 0)
186145510Sdarrenr	    {
187145510Sdarrenr		r = kvm_read(kvm_f, pos, buf, 1);
188145510Sdarrenr		if (r <= 0)
189145510Sdarrenr		    {
190145510Sdarrenr			fprintf(stderr, "pos=0x%lx ", (u_long)pos);
191145510Sdarrenr			perror("kmemcpy:read");
192145510Sdarrenr			return -1;
193145510Sdarrenr		    }
194145510Sdarrenr		else
195145510Sdarrenr		    {
196145510Sdarrenr			if (*buf == '\0')
197145510Sdarrenr				break;
198145510Sdarrenr			buf++;
199145510Sdarrenr			pos++;
200145510Sdarrenr			n--;
201145510Sdarrenr		    }
202145510Sdarrenr	    }
203145510Sdarrenr	return 0;
204145510Sdarrenr}
205