Subject: vnd, VOP_ and encrypted fs.
To: tech-kern <>
From: Jorgen Lundman <>
List: tech-kern
Date: 10/29/2001 11:28:06

My apologies for cluttering up the kern-tech list, but I was hoping I
could get some insights on how the vnd driver works.

The basic idea of what I want to do is to create a simple crypted
filesystem, by passing all block to be written to encode first, and
passing all blocks read to decode.

Initially, while working out how vnd drivers work, my "cipher" is simply
changing 'e' to 'i', 'i' to 'o' and 'o' to 'e', and reverse to decode.
So that the string "Hello world" would be encoded to "Hille werld".

Luckily I was allowed to borrow some vnd modload source from Matt Green
so that I didn't need to reboot a new kernel everytime to test my code
(is this how you guys work normally?) - but I've made sure to compile
out vnd of my boot kernel so I don't get any symbol name clashes.

Onset: After reading the vnd sources it initially looked like it would
be a piece of cake, all reads and writes appeared to come from vndread()
and vndwrite(). I patched these calls to call my vnd_decode() and
vnd_encode() respectively. I turned on debug and FOLLOW so I could see
the execution.

Only to find that vndread() and vndwrite() is never called. (?) Is this

Revenge: Instead all magic seems to be occuring in vndstrategy() which
calls vndstart() and (eventually) vndiodone().

So I went to patch vndstart() and vndiodone() instead.

I took a guess that "->bp" means Buffer Pointer and bcount is the byte
count of the data. (Seems a good guess).

But I am unsure as to how I know a packet is to be READ off disk, and
which are to be WRITTEN to disk? When I encoded all data passed through
vndstart() and vndiodone() I was unable to newfs and disklabel the vnd
device, "bad magic" etc, so it seems there are some lower-level code
accessing the buffers outside of vnd* layer. (?) So I currently only
encode and decode buffers with a blkno > 0x270 to skip the disklabel,
superblock etc. But this could also be due to that I haven't sorted out
which requests are READ and which are WRITE(more below).

In the end I patched vndstart() (for WRITE operations) as:

#ifdef DEBUG
	if (vnddebug & VDB_IO)
		printf("vndstart(%ld): bp %p vp %p blkno 0x%x addr %p cnt 0x%lx\n",
		    (long) (vnd-vnd_softc), bp, bp->b_vp, bp->b_blkno,
		    bp->b_data, bp->b_bcount);
		printf("Flags are %lx\n", bp->b_flags);
		if ((bp->b_flags & B_READ) == 0) { // WRITE?
		  vnd_encode(bp->b_data, bp->b_bcount, bp->b_blkno);

and likewise I patched vndiodone() (for READ operations) as:

	if (vbp->vb_buf.b_error) {
#ifdef DEBUG
		if (vnddebug & VDB_IO)
			printf("vndiodone: vbp %p error %d\n", vbp,
		vnx->vx_error = vbp->vb_buf.b_error;

	printf("Flags are %lx\n", bp->b_flags);
	if ((bp->b_flags & B_READ) != 0) { // READ?
	  vnd_decode(vbp->vb_buf.b_data, vbp->vb_buf.b_bcount, 
		     vbp->vb_buf.b_blkno );

Which had some amusing results.

newfs'ed fine, no calls to encode/decode (blkno < 0x270). Mounted the
filesystem, and copied a text file "Trigger.Happy.TV.S02E03-CLH.nfo" to

ls -l /mnt/
-rw-r--r--  1 lundman  admin  2366 Feb  6 2001

So it clearly got encoded when it was written, but it is not decoded on
ls! Pretty bad.

I proceed to read the actual raw file to ensure that data on "disk" is
encoded, which it is.

I then less the file, only to find that it is also encoded when I read

However, vnd_decode() is called. So I can only assume it is decoding the
information at the wrong location? On second thoughts, decode seems to
be called only a third of the time as compared to encode.

I notice there are a hell of a lot more of the flags than I was (hoping)
expecting. Is it enough to look for B_READ or !B_READ? Do I need to
consider other circumstances?

Partial Success: In desperation (and wondering what would happen) I
changed the decode if to be just if (1) and I had alot more success.

root@netbsd(/usr/src/sys/lkm/dev/vnd)  ls -la /mnt
-rw-r--r--   1 root  wheel  2366 Oct 29 10:51

on disk raw:

000185B0:  2020205B 3D2B0D0A 202B3D5D 204C6173   |   [=+.. +=] Las|
000185C0:  74206E65 67687420 49206861 6C6C7563   |t neght I halluc|
000185D0:  656E6174 6F642077 68656C6F 20492068   |enatod whelo I h|
000185E0:  61642074 686F2066 6C752E20 49742077   |ad tho flu. It w|
000185F0:  6173206E 69742063 69696C2E 5B3D2B0D   |as nit ciil.[=+.|
00018600:  0A202B3D 5D202020 20202020 20202020   |. +=]           |

less'ing the file from /mnt

 +=] Last night I hallucinated while I had the flu. It was not cool.[=+

But well, I assume I'm probably calling decode on far too many packets?
Anyone got a good idea on which flags I should call it, and which I

I can't see the filename in the raw file? Should I? Creating a new
directory and copying the file into it is strange too. Can't see any
directory entries, nor do I see the file's data twice.

Sorry for the lengthy and probably dull post, but if someone out there
has a spare minute for me that would be very much appreciated.


Jorgen "Lord" Lundman <>
Technology Manager, Unix Administrator
Phone: +44 (0)20-86591860  Mobile: +44 (0)79-58642918
"Rare is the person who can weigh the faults of others 
 without putting his thumb on the scales": Byron J. Langenfeld