Friday Oct 30, 2009
Friday Oct 30, 2009
This entry is mostly for newcomers to Solaris/OpenSolaris from UNIX-like systems. When I had been taught about signal() and sigaction() my understanding was that sigaction() is just a superset of signal() and also POSIX conformant but otherwise they accomplish the same thing. This is indeed the case for some of UNIX-like operating systems. In Solaris, as I only recently discovered (to my dismay :)), it's different.
Consider the following code (please ignore the fact it's not strictly checking return values and that the signal handler is not safe):
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
void sig_handler(int s) {
printf("Got signal! Sleeping.\n");
sleep(10);
printf("returning from signal handler\n");
}
int main(void) {
struct sigaction s_action;
printf("Setting signal handler: ");
#ifdef POSIX_SIGNALS
printf("sigaction\n");
(void) sigemptyset(&s_action.sa_mask);
s_action.sa_handler = sig_handler;
s_action.sa_flags = 0;
(void) sigaction(SIGHUP, &s_action, (struct sigaction *) NULL);
#else
printf("signal\n");
signal(SIGHUP, sig_handler);
#endif
printf("Waiting for signal\n");
while(1)
pause();
return (0);
}
Now try to compile and run with and without the -DPOSIX_SIGNALS and send 2 SIGHUP signals to the process within the 10 seconds window (so the second signal is received while the signal handler is still running). With sigaction(), the signal will be caught by the handler in both of the cases. With signal() however, the second signal will cause the process to exit. This is because kernel will reset the signal handler to default upon receiving the signal for the first time. This is described in the signal(3C) man page in a somewhat hidden sentence inside the second paragraph (it really pays out to read man pages slowly and with attention to detail):
If signal() is
used, disp is the address of a signal handler, and sig is
not SIGILL, SIGTRAP, or SIGPWR, the system first sets the
signal's disposition to SIG_DFL before executing the signal
handler.
The sigaction(2) man page has this section:
SA_RESETHAND If set and the signal is caught, the dispo-
sition of the signal is reset to SIG_DFL and
the signal will not be blocked on entry to
the signal handler (SIGILL, SIGTRAP, and
SIGPWR cannot be automatically reset when
delivered; the system silently enforces this
restriction).
sigaction() does not set the flag by default which results in the different behavior. I found out that this behavior has been present since Solaris 2.0 or so.
In fact, signal() routine from libc is implemented via sigaction(). From $SRC/lib/libc/port/sys/signal.c:
58 /*
59 * SVr3.x signal compatibility routines. They are now
60 * implemented as library routines instead of system
61 * calls.
62 */
63
64 void(*
65 signal(int sig, void(*func)(int)))(int)
66 {
67 struct sigaction nact;
68 struct sigaction oact;
69
70 CHECK_SIG(sig, SIG_ERR);
71
72 nact.sa_handler = func;
73 nact.sa_flags = SA_RESETHAND|SA_NODEFER;
74 (void) sigemptyset(&nact.sa_mask);
75
76 /*
77 * Pay special attention if sig is SIGCHLD and
78 * the disposition is SIG_IGN, per sysV signal man page.
79 */
80 if (sig == SIGCHLD) {
81 nact.sa_flags |= SA_NOCLDSTOP;
82 if (func == SIG_IGN)
83 nact.sa_flags |= SA_NOCLDWAIT;
84 }
85
86 if (STOPDEFAULT(sig))
87 nact.sa_flags |= SA_RESTART;
88
89 if (sigaction(sig, &nact, &oact) < 0)
90 return (SIG_ERR);
91
92 return (oact.sa_handler);
93 }
I am pretty sure that the SA_RESETHAND flag is set in signal() in order to preserve backwards compatibility.
This means that to solve this problem with signal(), one should set the signal handler again in the signal handler itself. However, this is not a complete solution since there is still a window where the signal can be delivered and the handler is set to SIG_DFL - the default handler which is exit in case of SIGHUP as the signal.h(3HEAD) man page explains in really useful table:
Name Value Default Event
SIGHUP 1 Exit Hangup (see termio(7I))
...
Now let's look at FreeBSD. Its SIGNAL(3) man page contains this separate paragraph:
The handled signal is unblocked when the function returns and the process
continues from where it left off when the signal occurred. Unlike previ-
ous signal facilities, the handler func() remains installed after a sig-
nal has been delivered.
The second sentence is actually printed in bold letters. I also tried on Linux and NetBSD and the behavior is the same as in FreeBSD.
So, to conclude all of the above: using signal() is really not portable.
tags:
opensolaris
sigaction
signal
signals
solaris
Linkage:
Technorati cosmos
Tuesday Sep 01, 2009
Recently I needed to test a bug fix in in.iked(1M) (should say libike.so with which in.iked is linked) after which the daemon should respond to IKEv2 requests with Notification message telling the peer to fall back to IKEv1 (previously it did not respond to IKEv2 packets at all). This can be tested by:
Surely, there should be easier way how to send a UDP paket with arbitrary (in my case ISAKMP) payload. It turns out this is very easy to do just from command line with nc(1) which is available in OpenSolaris (install it via 'pkg install SUNWnetcat'). Let's try to send some garbage first to see if it works:
perl -e 'print "\x41\x41";' | nc -u rpe-foo.czech 500
Yep, tshark(1) (in OpenSolaris shipped by default with Wireshark) reports an IKE packet, malformed one (which is not surprising):
Capturing on eri0 0.000000 10.18.144.12 -> 10.18.144.11 ISAKMP [Malformed Packet] 0000 00 0a e4 2f 61 eb 00 03 ba 4e 3d 38 08 00 45 00 .../a....N=8..E. 0010 00 1e 26 98 40 00 ff 11 20 fb 0a 12 90 0c 0a 12 ..&.@... ....... 0020 90 0b e2 66 01 f4 00 0a 34 57 41 41 ...f....4WAA
Our two A's are there just after the UDP header (Ethernet header 14 bytes, IP header 20 bytes, UDP 8 bytes, in sum 42 bytes and our 2 bytes are just after first 8 bytes on 3rd line).
With that we can go and construct IKEv1 packet first to see if the daemon will react upon it. We will need to construct the payload which is a IKEv1 header. IKEv1 is defined in RFC 2409 (The Internet Key Exchange (IKE)). IKEv1 uses ISAKMP header definition so we need to look into RFC 2408 (Internet Security Association and Key Management Protocol (ISAKMP)) for the actual header definition. It's there in section 3.1:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Initiator !
! Cookie !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Responder !
! Cookie !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Message ID !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
I'd like to construct a packet which resembles first packet sent by IKEv1 Initiator. So, our packet code (similar to shell code) will look like this (without thinking too much of what should the values look like):
\x11\x22\x33\x44\x55\x66\x77\x88
\x00\x00\x00\x00\x00\x00\x00\x00
\x00
\x10
Exchange Type Value
NONE 0
Base 1
Identity Protection 2
Authentication Only 3
Aggressive 4
Informational 5
ISAKMP Future Use 6 - 31
DOI Specific Use 32 - 239
Private Use 240 - 255
So let's try Base first:
\x01
\x00
\x66\x66\x66\x66
\x28
We need to massage our packet code into command line. The code:
\x11\x22\x33\x44\x55\x66\x77\x88 \x00\x00\x00\x00\x00\x00\x00\x00 \x00 \x10 \x01 \x00 \x66\x66\x66\x66 \x28
We want source port to be 500 as well because of section 2.5.1 in RFC 2408 so use the -p option (this requires the net_privaddr privilege so either become root or use pfexec(1)). Also, we do not need to wait for the response so use -w option:
perl -e 'print "\x11\x22\x33\x44\x55\x66\x77\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x01\x00\x66\x66\x66\x66\x28";' \
| nc -w 1 -p 500 -u rpe-foo.czech 500
The packet was received but there was no reply and tshark still considers this as Malformed Packet. Let's check the header again - oh yeah, the Length field has 4 bytes, not just one. Let's try again:
perl -e 'print "\x11\x22\x33\x44\x55\x66\x77\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x01\x00\x66\x66\x66\x66\x28\x00\x00\x00";' \
| nc -w 1 -p 500 -u rpe-foo.czech 500
Okay, this is our Base exchange but still not response:
294.029154 10.18.144.12 -> 10.18.144.11 ISAKMP Base 0000 00 0a e4 2f 61 eb 00 03 ba 4e 3d 38 08 00 45 00 .../a....N=8..E. 0010 00 38 26 a7 40 00 ff 11 20 d2 0a 12 90 0c 0a 12 .8&.@... ....... 0020 90 0b 01 f4 01 f4 00 24 34 71 11 22 33 44 55 66 .......$4q."3DUf 0030 77 88 00 00 00 00 00 00 00 00 00 10 01 00 66 66 w.............ff 0040 66 66 28 00 00 00
Let's try something more provocative and set the Exchange type to Identity protection:
perl -e 'print "\x11\x22\x33\x44\x55\x66\x77\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x02\x00\x66\x66\x66\x66\x28\x00\x00\x00";' \
| nc -w 1 -p 500 -u rpe-foo.czech 500
Oh yeah, this finally deserved a response:
383.050874 10.18.144.12 -> 10.18.144.11 ISAKMP Identity Protection (Main Mode) 0000 00 0a e4 2f 61 eb 00 03 ba 4e 3d 38 08 00 45 00 .../a....N=8..E. 0010 00 38 26 a8 40 00 ff 11 20 d1 0a 12 90 0c 0a 12 .8&.@... ....... 0020 90 0b 01 f4 01 f4 00 24 34 71 11 22 33 44 55 66 .......$4q."3DUf 0030 77 88 00 00 00 00 00 00 00 00 00 10 02 00 66 66 w.............ff 0040 66 66 28 00 00 00 ff(... 383.051672 10.18.144.11 -> 10.18.144.12 ISAKMP Informational 0000 00 03 ba 4e 3d 38 00 0a e4 2f 61 eb 08 00 45 00 ...N=8.../a...E. 0010 00 99 d3 8b 40 00 ff 11 73 8c 0a 12 90 0b 0a 12 ....@...s....... 0020 90 0c 01 f4 01 f4 00 85 ed 05 11 22 33 44 55 66 ..........."3DUf 0030 77 88 85 75 8e 0f fa a5 5d de 0b 10 05 00 69 a5 w..u....].....i. 0040 63 e4 00 00 00 7d 00 00 00 61 00 00 00 01 01 10 c....}...a...... 0050 00 1e 11 22 33 44 55 66 77 88 85 75 8e 0f fa a5 ..."3DUfw..u.... 0060 5d de 80 0c 00 01 00 06 00 39 55 44 50 20 50 61 ]........9UDP Pa 0070 63 6b 65 74 20 64 6f 65 73 20 6e 6f 74 20 63 6f cket does not co 0080 6e 74 61 69 6e 20 65 6e 6f 75 67 68 20 64 61 74 ntain enough dat 0090 61 20 66 6f 72 20 49 53 41 4b 4d 50 20 70 61 63 a for ISAKMP pac 00a0 6b 65 74 80 08 00 00 ket....
Now that we proved to ourselves that we can construct semi-valid packet it's time to try IKEv2. IKEv2 header is defined in RFC 4306, section 3.1:
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! IKE_SA Initiator's SPI !
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! IKE_SA Responder's SPI !
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Message ID !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
On a first sight, it looks the same (for backward compatibility). However, some of the values are different. For IKE header, the main differences are in the Exchange Type and Flags:
Exchange Type Value
RESERVED 0-33
IKE_SA_INIT 34
IKE_AUTH 35
CREATE_CHILD_SA 36
INFORMATIONAL 37
RESERVED TO IANA 38-239
Reserved for private use 240-255
IKE_SA_INIT is our guy ('echo 0t34=x | mdb' produces 0x22).
The flags are now used to indicate the exchange. Set 3rd bit to say we are the Initiator. We will retain the source port even though IKEv2 supports ports other than 500 and 4500 because we're dealing with IKEv1 implementation. Now slightly change our packet code (don't forget to change the Version field to 2.0):
perl -e 'print "\x11\x22\x33\x44\x55\x66\x77\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x22\x08\x66\x66\x66\x66\x28\x00\x00\x00";' \
| nc -w 1 -p 500 -u rpe-foo.czech 500
And we got a nice response (since the responder runs recent version libike.so):
1013.190867 10.18.144.12 -> 10.18.144.11 ISAKMP IKE_SA_INIT
0000 00 0a e4 2f 61 eb 00 03 ba 4e 3d 38 08 00 45 00 .../a....N=8..E.
0010 00 38 26 aa 40 00 ff 11 20 cf 0a 12 90 0c 0a 12 .8&.@... .......
0020 90 0b 01 f4 01 f4 00 24 34 71 11 22 33 44 55 66 .......$4q."3DUf
0030 77 88 00 00 00 00 00 00 00 00 00 20 22 08 66 66 w.......... ".ff
0040 66 66 28 00 00 00 ff(...
1013.192005 10.18.144.11 -> 10.18.144.12 ISAKMP Informational
0000 00 03 ba 4e 3d 38 00 0a e4 2f 61 eb 08 00 45 00 ...N=8.../a...E.
0010 00 83 d3 8d 40 00 ff 11 73 a0 0a 12 90 0b 0a 12 ....@...s.......
0020 90 0c 01 f4 01 f4 00 6f 66 da 11 22 33 44 55 66 .......of.."3DUf
0030 77 88 5c 36 e3 75 a2 7b 8e fe 0b 10 05 00 87 03 w.\6.u.{........
0040 0c f5 00 00 00 67 00 00 00 4b 00 00 00 01 01 10 .....g...K......
0050 00 05 11 22 33 44 55 66 77 88 5c 36 e3 75 a2 7b ..."3DUfw.\6.u.{
0060 8e fe 80 0c 00 01 00 06 00 23 49 6e 76 61 6c 69 .........#Invali
0070 64 20 49 53 41 4b 4d 50 20 6d 61 6a 6f 72 20 76 d ISAKMP major v
0080 65 72 73 69 6f 6e 20 6e 75 6d 62 65 72 80 08 00 ersion number...
0090 00
The only thing which is not nice is our terminal since nc(1) dumped the binary packet to it. Let's try again with some post-processing:
# perl -e 'print "\x11\x22\x33\x44\x55\x66\x77\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x22\x08\x66\x66\x66\x66\x28\x00\x00\x00";' | nc -w 1 -p 500 -u rpe-foo.czech 500 | od -c 0000000 021 " 3 D U f w 210 237 y 254 264 351 333 007 344 0000020 013 020 005 \0 [ 251 244 j \0 \0 \0 g \0 \0 \0 K 0000040 \0 \0 \0 001 001 020 \0 005 021 " 3 D U f w 210 0000060 237 y 254 264 351 333 007 344 200 \f \0 001 \0 006 \0 # 0000100 I n v a l i d I S A K M P m 0000120 a j o r v e r s i o n n u m 0000140 b e r 200 \b \0 \0 0000147
The fix is obviously in place.
tags:
construction
factory
ike
nc
netcat
packet
solaris
Linkage:
Technorati cosmos
Monday Aug 17, 2009
Some light intro first: OpenSSL has a concept of plugins/add-ons called 'engines' which can supply alternative implementation of crypto operations (digests, symmetric and asymmetric ciphers and random data generation). The main reason for the existence of the engines is the ability to offload crypto ops to hardware. (Open)Solaris ships with an engine called PKCS#11 engine which provides access to Solaris Cryptographic Framework which in turn can provide access to HW crypto.
I spent some time fixing bugs in OpenSSL PKCS#11 engine in Solaris so I got quite intimate with its internals. Recently while discussing an upcoming feature with Jan he asked me why one particular detail in the engine is done one way and not the other (it's the fork() detection not done via atfork handlers; for the curious). It took me some thinking to find the answer (I focused on the other changes at that time) which made us realize that it would be good to summarize the design choices behind the engine and also to document the internals so that others can quickly see what's going on inside and also be able to do changes in the engine without reverse engineer the thoughts behind it. The outcome is a set of slides which I hope succinctly describe both the overall picture and the gritty details.
The presentation can be downloaded here.
tags:
crypto
engine
opensolaris
openssl
pkcs11
Linkage:
Technorati cosmos
Wednesday Jun 03, 2009
I have spent some time fixing bugs in KSSL (kernel SSL proxy) implementation in Solaris and got familar with it (and the KSSL development team) so with delight I can co-announce that the KSSL project has been opened on opensolaris.org.
To me, KSSL is one of the unique projects in the (Open)Solaris security land in a sense it is tightly integrated into the system and is a consumer of several major subsystems (networking, crypto framework) which makes it interesting for study and also for extending it in creative ways.
We will start adding more content to the pages, including design documentation and description of KSSL internals. Also, this marks major milestone in a way how KSSL team does its job. From now on all non-confidential discussions, reviews etc. will happen in the open. Feel free to join the project and participate if you're interested ! (become an observer and join the mailing list)
tags:
kssl
opensolaris
security
Linkage:
Technorati cosmos
Monday May 04, 2009
I have just integrated couple of changes which I believe are the first contributed externally to the Testing community as an open-source contribution. The changes add couple of new tests to the nc test suite to cover the enhancement described in PSARC/2008/680 (which is present in Nevada since build 106). This is the stuff which allows you to run nc(1) in client mode with complex portlist specifications. Previously it was possible only to use simple port ranges like 22-80, with this change one can connect to e.g. 22,24,50-80,66,1024-2048. Little example how it might be useful:
$ nc -v -z grok.czech 22,25,80-88,8080 Connection to grok.czech 22 port [tcp/ssh] succeeded! nc: connect to 129.157.71.49 port 25 [host grok.czech] (tcp) failed: Connection refused Connection to grok.czech 80 port [tcp/*] succeeded! nc: connect to 129.157.71.49 port 81 [host grok.czech] (tcp) failed: Connection refused nc: connect to 129.157.71.49 port 82 [host grok.czech] (tcp) failed: Connection refused nc: connect to 129.157.71.49 port 83 [host grok.czech] (tcp) failed: Connection refused nc: connect to 129.157.71.49 port 84 [host grok.czech] (tcp) failed: Connection refused nc: connect to 129.157.71.49 port 85 [host grok.czech] (tcp) failed: Connection refused nc: connect to 129.157.71.49 port 86 [host grok.czech] (tcp) failed: Connection refused nc: connect to 129.157.71.49 port 87 [host grok.czech] (tcp) failed: Connection refused nc: connect to 129.157.71.49 port 88 [host grok.czech] (tcp) failed: Connection refused Connection to grok.czech 8080 port [tcp/*] succeeded!
Back to the testing part. The putback (yes, stcnv-gate is still using Teamware) log for this change looks like this (I have modified Erik's e-mail a bit):
6786859 portranges_complex_spec is missing the listener 6754842 extended port list specification needs to be tested Code contributed by Erik Trauschke <erik.trauschke AT freenet.de>
I think this is really nice example of the ideal state - the contributor not only did the feature part but also the testing part. It shows a great degree of responsibility - not just throwing some code "over the fence" but fully participating in the process to ensure the quality even in the long term.
The tests are both positive and negative. Each purpose in portranges directory is numbered and the following numbers match the test purpose numbers:
To be able to do such integration there is now a Test development process. It's similar to the process used in ON community but it's more lightweight. The main difference is that the request-sponsor part is done informally via the testing-discuss mailing list and there is no list of bugs to pick up from. But don't be shy, whether you're adding new functionality or completely new program, the Testing community is here to help you.
tags:
contribute
contributions
nc
netcat
opensolaris
solaris
testing
Linkage:
Technorati cosmos
Tuesday Apr 07, 2009
Each build of (Open)Solaris is tested with a variety of test suites on variety of platforms
and I wanted nc test suite to participate in these runs.
Eoin Hughes from PIT team (which runs those tests) was kind enough to workaround couple of bugs (which are fixed now)
in the test suite so it can be run in PIT environment. Later on, I got a report from Eoin
that as a result of nc test suite run
CR 6793191 (watchmalloc triggers system panic on sockfs copyin) was caught.
This bug is manifested by a panic:
Panic message (this particular panic is on a DomU, although this happens across the board): panic[cpu0]/thread=ffffff0150ce1540: copyin_noerr: argument not in kernel address space ffffff000416dcf0 unix:bcopy_ck_size+102 () ffffff000416ddb0 genunix:watch_xcopyin+151 () ffffff000416dde0 genunix:watch_copyin+1d () ffffff000416de50 sockfs:copyin_name+91 () ffffff000416deb0 sockfs:bind+90 () ffffff000416df00 unix:brand_sys_syscall32+328 ()
The bug is actually a regression caused by CR 6292199 (bcopy and kcopy should'nt use rep, smov) and was fixed by an engineer from Intel in OpenSolaris/Nevada code base.
This is instance of an event which I like so much - unintended positive consequence elsewhere. In contrast with so called collateral damage this is something which is beneficial in other areas. I've written nc test suite to test primarily nc(1) command but here it proved to be useful for testing other areas of the system as well. In this case it was thanks to the fact that the test suite is run with memory leak checking by default (see NC_PRELOADS variable in src/suites/net/nc/include/vars file).
And yes, CR 6793191 is fixed by now.
tags:
crash
nc
testing
Linkage:
Technorati cosmos
Tuesday Mar 31, 2009
Since the days when John Beck added command line editing to zonecfg Mark Phalan did similar thing to Kerberos utilities and Huie-Ying Lee to sftp. IPsec utilities (ipseckey(1M) and ikeadm(1M)) offered the ability to enter commands in interactive mode for a long time but only since Nevada build 112, the commands support command line editing and history too. Again, thanks to libtecla (shipped with Solaris/OpenSolaris).
Lessons learned:
static void
monitor_catch(int signal)
{
if (!interactive)
errx(signal, gettext("Bailing on signal %d."), signal);
}
void
doreadcycle(void)
{
...
/* Catch ^C. */
newsig.sa_handler = monitor_catch;
newsig.sa_flags = 0;
(void) sigemptyset(&newsig.sa_mask);
(void) sigaddset(&newsig.sa_mask, SIGINT);
(void) sigaction(SIGINT, &newsig, &oldsig);
for (; ; ) {
rc = read(keysock, samsg, sizeof (get_buffer));
/* handle the data */
}
/* restore old behavior */
if (interactive)
(void) sigaction(SIGINT, &oldsig, NULL);
}
tags:
command
history
ipsec
line
opensolaris
solaris
Linkage:
Technorati cosmos
Thursday Nov 20, 2008
After multiple rounds of code review the netcat (or nc) test suite is now finally in the onnv-stc2gate.
The test suite has its home in the OpenSolaris
Networking community (see
the networking tests page for the list of networking
test suites).
The source code is present in the
src/suites/net/nc/
directory and SUNWstc-netcat packages can be downloaded from
OpenSolaris Download center.
Before I go further, this is how it looks like when the test suite is run (the output is trimmed a bit):
vk:honeymooners:/opt/SUNWstc-nc$ run_test nc
Validating Arguments...
New TET_ROOT for this run : /var/tmp/honeymooners_27828
The results will be available in /var/tmp/results.27828
tcc: journal file is /var/tmp/results.27828/testlog
12:45:57 Execute /tests/dflag/tc_dflag
12:46:04 Execute /tests/hflag/tc_hflag
12:46:05 Execute /tests/kflag/tc_kflag
12:46:11 Execute /tests/nflag/tc_nflag
12:46:15 Execute /tests/portranges/tc_portranges
12:46:23 Execute /tests/pflag/tc_pflag
12:46:26 Execute /tests/sflag/tc_sflag
12:46:35 Execute /tests/Uflag/tc_Uflag
12:46:36 Execute /tests/vflag/tc_vflag
12:46:43 Execute /tests/zflag/tc_zflag
12:46:46 Execute /tests/iflag/tc_iflag
12:46:59 Execute /tests/lflag/tc_lflag
12:47:29 Execute /tests/rflag/tc_rflag
12:48:16 Execute /tests/Tflag/tc_Tflag
12:48:33 Execute /tests/uflag/tc_uflag
12:48:50 Execute /tests/wflag/tc_wflag
##################################################
TC /tests/dflag/tc_dflag
TP 1 tc_dflag PASS
##################################################
TC /tests/hflag/tc_hflag
TP 1 tc_hflag PASS
...
##################################################
SUMMARY
=======
Number of Tests : 50
PASS : 50
FAIL : 0
UNRESOLVED : 0
UNINITIATED : 0
OTHER : 0
##################################################
Test Logs are at /var/tmp/results.27828, Journal File = /var/tmp/results.27828/testlog
vk:honeymooners:/opt/SUNWstc-nc$
It's been almost a year since I started developing the test suite last Christmas (see the initial blog entry about nc-tet). Since then, I have lost part of the source code in hard drive crash, had to redo the source tree structure, fix ksh style, fix numerous bugs in test suite code and make the test suite more robust. One might ask whether having test suite for such a simple program like nc(1) was worth the hassle. I have only one answer to that: absolutely. First, it gives a confidence of not breaking (most of; see below) existing things when changing/adding functionality and second it helped me (and I hope the others participating/observing the code review on testing-discuss too) to explore what it takes to write a test suite from scratch (I will not go here into details whether I prefer CTI-TET over STF and vice versa).
The Beautiful code book (which I really recommend for anyone tinkering with any source code) contains a chapter called Beautiful tests by Alberto Savoia. I hope that at least some of the test purposes in nc test suite have some degree of beautifulness of at least one of the ways highlighted by Alberto (1. simplicity/efficiency, 2. help making the software being tested better in terms of quality and testability, 3. breadth/thoroughness).
One of the important questions for a test suite is code coverage level. Obviously, for software adhering to the OpenSolaris interface taxonomy model it is important that the test suite exercises all of the Committed interfaces and execution paths around those interfaces. For nc(1) this means a subset of the command line options and their arguments (see PSARC 2007/389 for the actual list). The key is certainly to test the features which are likely to break with an intrusive code change.
Very crude view of test coverage for nc(1) test suite (counting test purposes gives only very remote idea about real coverage but at least provides visual image) looks like this:
rflag: +
Tflag: +++++---
pflag: +
iflag: +-
vflag: ++
kflag: +
Uflag: +-
dflag: +
uflag: ++-
sflag: +-
hflag: +
nflag: +-
wflag: +
portranges: +---
lflag: ++++++++----------
One plus character stands for one positive test purpose, minus is negative test purpose.
Side note: the above ASCII graph was produced using test-coverage-graph.sh script (which presumes certain naming scheme for test purpose files). Just pipe a file listing into the script with test purpose filenames compliant to the scheme used in ontest-stc2 gate and it will spew out graph similar to the above.
In the above musing about code coverage I left out an important piece - why some of the features are not tested. For nc(1) the yet untested part is the SOCKS protocol support. Basically, this is because test suite environment does not contain SOCKS server to test against. There might not be many people using the -x/-X options but from my own experience nothing is more frustrating than discovering some old dusty corner which had to be fixed long time ago or removed completely. So for now, on my workstation which sits behind SOCKS proxy I have the following in ~/.ssh/config for a server outside corporate network which hosts my personal mailbox so it is accessed every day:
Host bar User foo Hostname outside.kewl.org # NOTE: for nc(1) testing ProxyCommand /usr/bin/nc -x socks-proxy.foothere.bar outside.kewl.org %p ForwardAgent no ForwardX11 no
This ensures (along with upgrades of the workstation to recent Nevada builds periodically) that SOCKS support gets tested as well. And yes, ssh-socks5-proxy-connect(1) and ssh-http-proxy-connect(1) are not really needed.
Now with the test suite in place, anybody modifying nc(1) (there are some RFEs for nc in the oss-bit-size list and other bugfixes or features are also welcome) can have pretty high confidence that his change will not break things. Yes, this means that more nc(1) features are coming.
tags:
code
coverage
nc
netcat
opensolaris
suite
test
testing
Linkage:
Technorati cosmos
Friday Nov 07, 2008
I will start this one a little bit generically..
Part of standard OpenSolaris/Solaris development process is code review. To facilitate a review, a so-called webrev is needed. A webrev is set of HTML/text/PDF pages and documents which display all the changes between local repository containing the changes and its parent repository. To produce a webrev, simply switch to a repository and run the webrev script (it is part of SUNWonbld package, which can be downloaded from OpenSolaris download center.):
$ cd /local/Source/bugfix-314159.onnv $ webrev
Assuming /opt/onbld/bin is present in your PATH a webrev will be generated under /local/Source/bugfix-314159.onnv/webrev/ directory.
For OpenSolaris changes, the webrev is usually uploaded to cr.opensolaris.org
(every OpenSolaris member has an account automatically created for him) which serves it under http://cr.opensolaris.org/~OSol_username/
(where OSol_username is your OpenSolaris username) and a request for review with a link to the webrev is sent
to one of the mailing lists relevant to the change.
Dan Price has written a script which produces
RSS feed out of recently uploaded webrevs which is pretty handy substitute for feeds from news/headlines/magazines :)
For a long time I was basically doing the following:
$ cd /local/Source/bugfix-foo.onnv && webrev $ scp -r webrev cr.opensolaris.org:bugfix-foo.onnv
This had two flaws: first it was slow (because of rcp protocol over SSH channel) and second I had to delete it via separate command (use sftp(1) and rename the old webrev to .trash directory) before uploading new version of the webrev (otherwise couple of permissions errors would follow).
To solve the first problem, rsync (with SSH transport) can be used which makes the upload nearly instantaneous. Second problem can be worked around by using incremental webrevs. Still, this does not seem good enough for code reviews with many iterations.
So, the change made in CR 6752000 introduces the following command line options for automatic webrev upload:
webrev.1 man page has been updated to explain the usage. For common OpenSolaris code reviews the usage will probably mostly look like this:
$ webrev -O -U
This will upload the webrev to cr.opensolaris.org under directory named according to local repository name. Further invocations
will replace the remote webrev with fresh version.
But it is possible to get more advanced. After the initial webrev is posted, an incremental webrev can be both generated and posted.
Assuming you're switched to the repository (via bldenv) and we're dealing with 4th round of code review the following
command will perform the task:
webrev_name=`basename $CODEMGR_WS`
webrev -O -U -o $CODEMGR_WS/${webrev_name}.rd4 \
-p $CODEMGR_WS/${webrev_name}.rd3
The above commands hide maybe not-so-obvious behavior so I'll try to explain it in the table:
+---------------------------+------------------------+-----------------------------------------------------+ | command | local webrev directory | remote webrev directory | +---------------------------+------------------------+-----------------------------------------------------+ | webrev -O -U | $CODEMGR_WS/webrev/ | cr.opensolaris.org/~OSOLuser/`basename $CODEMGR_WS` | +---------------------------+------------------------+-----------------------------------------------------+ | webrev -O -o \ | $CODEMGR_WS/my_webrev/ | cr.opensolaris.org/~OSOLuser/my_webrev | | $CODEMGR_WS/my_webrev | | | +---------------------------+------------------------+-----------------------------------------------------+ | webrev -O \ | $CODEMGR_WS/fix.rd2/ | cr.opensolaris.org/~OSOLuser/fix.rd2 | | -p $CODEMGR_WS/fix.rd1 \ | | | | -o $CODEMGR_WS/fix.rd2 | | | +---------------------------+------------------------+-----------------------------------------------------+
Basically, without the -o flag webrev will generate the webrev to local directory named 'webrev' but it will upload it to the directory named after basename of local repository. With the -o flag webrev will use the name of root directory of the repository it is called from for both local and remote storage. This is done to keep the default behavior of generating local webrev to directory named 'webrev'. At the same time, uploading different webrevs to the same remote directory named 'webrev' does not make sense.
NOTE: This behavior is also valid in the case when not enclosed in a repository via ws or bldenv, I have just used $CODEMGR_WS to express root directory of a workspace/repository.
Also, now it is possible to call webrev from within Cadmium Mercurial plugin, so all webrev commands can be prefixed with hg.
All in all, it was fun dealing with webrevs of webrev. I am looking forward to more entries in the RSS feed :)NOTE: It will take some time before the changes appear in SUNWonbld packages offered by the download center so it's better to update the sources from the ssh://anon@hg.opensolaris.org/hg/onnv/onnv-gate repository and build and upgrade the SUNWonbld package from there.
tags:
automatic
opensolaris
solaris
upload
webrev
Linkage:
Technorati cosmos
Wednesday Sep 03, 2008
As of today, strsep() function lives in Nevada's libc (tracked by CR 4383867 and PSARC 2008/305). This constitutes another step in the quest for more feature-full (in terms of compatibility) libc in OpenSolaris. In binary form, the changes will be available in build 99. The documentation will be part of the string(3C) man page.
Here's a small example of how to use it:
#include <stdio.h>
#include <string.h>
#include <err.h>
int parse(const char *str) {
char *p = NULL;
char *inputstring, *origstr;
int ret = 1;
if (str == NULL)
errx(1, "NULL string");
/*
* We have to remember original pointer because strsep()
* will change 'inputstr' pointer.
*/
if ((origstr = inputstring = strdup(str)) == NULL)
errx(1, "strdup() failed");
printf("=== parsing '%s'\n", inputstring);
for ((p = strsep(&inputstring, ",")); p != NULL;
(p = strsep(&inputstring, ","))) {
if (p != NULL && *p != '\0')
printf("%s\n", p);
else if (p != NULL) {
warnx("syntax error");
ret = 0;
goto bad;
}
}
bad:
printf("=== finished parsing\n");
free(origstr);
return (ret);
}
int main(int argc, char *argv[]) {
if (argc != 2)
errx(1, "usage: prog ");
if (!parse(argv[1]))
exit(1);
return (0);
}
This example was actually used as a unit test (use e.g. "1,22,33,44" and "1,22,,44,33" as input string) and it also nicely illustrates important properties of strsep() behavior:
There is a function in Solaris' libc which can do token splitting and does not modify the original string - strcspn(). The other notable property of strsep() is that (unlike strtok()) it does not conform to ANSI-C. Time to draw a table:
function(s) ISO C90 modifies detects
input empty fields
-------------+----------+----------+--------------+
strsep() No Yes Yes
strtok() Yes Yes No
strcspn() Yes No Sort of
None of the above functions is bullet-proof. The bottom line is the user should decide which is the most suitable for given task and use it with its properties in mind.
tags:
libc
onnv
opensolaris
strsep
Linkage:
Technorati cosmos
Thursday Aug 07, 2008
Part of the transition of Mercurial in OpenSolaris are changes in the integration processes. Every RTI has to contain output of hg outgoing -v so the CRT advocates can better see the impact of the changes in terms of changed files. However, the default output is not very readable:
$ hg outgoing -v comparing with /local/ws-mirrors/onnv-clone.hg searching for changes changeset: 7248:225922d15fe6 user: Vladimir Kotaldate: 2008-08-06 23:39 +0200 modified: usr/src/cmd/ldap/ns_ldap/ldapaddent.c usr/src/cmd/sendmail/db/config.h usr/src/cmd/ssh/include/config.h usr/src /cmd/ssh/include/openbsd-compat.h usr/src/cmd/ssh/include/strsep.h usr/src/cmd/ssh/libopenbsd-compat/Makefile.com usr/src /cmd/ssh/libopenbsd-compat/common/llib-lopenbsd-compat usr/src/cmd/ssh/libopenbsd-compat/common/strsep.c usr/src/cmd/ssh/libssh /common/llib-lssh usr/src/common/util/string.c usr/src/head/string.h usr/src/lib/libc/amd64/Makefile usr/src/lib/libc /i386/Makefile.com usr/src/lib/libc/port/gen/strsep.c usr/src/lib/libc/port/llib-lc usr/src/lib/libc/port/mapfile-vers usr/src /lib/libc/sparc/Makefile usr/src/lib/libc/sparcv9/Makefile usr/src/lib/passwdutil/Makefile.com usr/src/lib/passwdutil /bsd-strsep.c usr/src/lib/passwdutil/passwdutil.h usr/src/lib/smbsrv/libsmb/common/mapfile-vers usr/src/lib/smbsrv/libsmb /common/smb_util.c added: usr/src/lib/libc/port/gen/strsep.c deleted: usr/src/cmd/ssh/include/strsep.h usr/src/cmd/ssh/libopenbsd-compat/common/strsep.c usr/src/lib/passwdutil/bsd-strsep.c log:PSARC 2008/305 strsep() in libc 4383867 need strsep() in libc --------------------------------------------------------------------
In the above case, the list of modified files spans single line which makes the web form used for RTI go really wild in terms of width (I had to wrap the lines manually in the above example otherwise this page would suffer from the same problem). The following steps can be used to make the output a bit nicer:
from mercurial import templatefilters
def newlines(text):
return text.replace(' ', '\n')
def outgoing_hook(ui, repo, **kwargs):
templatefilters.filters["newlines"] = newlines
[extensions] outproc=~/bin/Mercurial/outproc.py [hooks] pre-outgoing=python:outproc.outgoing_hook
changeset = outgoing.template
changeset: {rev}:{node|short}
user: {author}
date: {date|isodate}
modified:
{files|stringify|newlines}
added:
{file_adds|stringify|newlines}
deleted:
{file_dels|stringify|newlines}
log:
{desc}
------------------------------------------------------------------------
alias outgoing='hg outgoing --style ~/bin/Mercurial/style.outgoing'
After that it works like this:
$ outgoing comparing with /local/ws-mirrors/onnv-clone.hg searching for changes changeset: 7248:225922d15fe6 user: Vladimir Kotaldate: 2008-08-06 23:39 +0200 modified: usr/src/cmd/ldap/ns_ldap/ldapaddent.c usr/src/cmd/sendmail/db/config.h usr/src/cmd/ssh/include/config.h usr/src/cmd/ssh/include/openbsd-compat.h usr/src/cmd/ssh/include/strsep.h usr/src/cmd/ssh/libopenbsd-compat/Makefile.com usr/src/cmd/ssh/libopenbsd-compat/common/llib-lopenbsd-compat usr/src/cmd/ssh/libopenbsd-compat/common/strsep.c usr/src/cmd/ssh/libssh/common/llib-lssh usr/src/common/util/string.c usr/src/head/string.h usr/src/lib/libc/amd64/Makefile usr/src/lib/libc/i386/Makefile.com usr/src/lib/libc/port/gen/strsep.c usr/src/lib/libc/port/llib-lc usr/src/lib/libc/port/mapfile-vers usr/src/lib/libc/sparc/Makefile usr/src/lib/libc/sparcv9/Makefile usr/src/lib/passwdutil/Makefile.com usr/src/lib/passwdutil/bsd-strsep.c usr/src/lib/passwdutil/passwdutil.h usr/src/lib/smbsrv/libsmb/common/mapfile-vers usr/src/lib/smbsrv/libsmb/common/smb_util.c added: usr/src/lib/libc/port/gen/strsep.c deleted: usr/src/cmd/ssh/include/strsep.h usr/src/cmd/ssh/libopenbsd-compat/common/strsep.c usr/src/lib/passwdutil/bsd-strsep.c log: PSARC 2008/305 strsep() in libc 4383867 need strsep() in libc ------------------------------------------------------------------------
I asked Richard Lowe (who has been very helpful with helping getting the transition process done) if next
Mercurial version can have newlines function already included and if there could be
outgoingtemplate which would be similar to logtemplate in hgrc(5).
In the meantime I will be using the above for my RTIs.
tags:
hg
mercurial
outgoing
template
Linkage:
Technorati cosmos
Monday Apr 28, 2008
In OpenSolaris world we very much care about correctness and hate regressions (of any kind). If I loosely paraphrase Bryan Cantrill the degree of devotion should be obvious:
"Have you tested your change in every way you know of ? If not, do not go any further with the integration unless you do so."This implies that ordinary bug fix should have a unit test accompanying it. But, unit tests are cumbersome when performed by hand and do not mean much if they are not accumulated over time.
For integration of Netcat into OpenSolaris I have developed number of unit tests (basically at least one for each command line option) and couple more after spotting some bugs in nc(1). This means that nc(1) is ripe for having a test suite so the tests can be performed automatically. This is tracked by RFE 6646967. The test suite will live in onnv-stc2 gate which is hosted and maintained by OpenSolaris Testing community.
To create a test suite one can choose between two frameworks: STF and CTI-TET. I have chosen the latter because I wanted to try something new and also because CTI-TET seems to be the recommended framework these days.
The work on nc test suite has started during Christmas break 2007 and after recovery from lost data it is now in pretty stable state and ready for code review. This is actually somewhat exciting because nc test suite is supposed to be the first OpenSolaris test suite developed in the open.
Fresh webrev is always stored on cr.opensolaris.org in nc-tet.onnv-stc2 directory. Everybody is invited to participate in the code review.
Code review should be performed via testing-discuss at opensolaris.org mailing list (subscribe via Testing / Discussions). It has web interface in the form of testing-discuss forum.
So, if you're familiar with ksh scripting or CTI-TET framework (both not necessary) you have unique chance to bash (not bash) my code ! Watch for official code review announcement on the mailing list in the next couple of days.
Lastly, another philosophical food for thought: Test suites are sets of programs and scripts which serve mainly one purpose - they should prevent bugs from happening in the software they test. But, test suites are software too. Presence of bugs in test suites is an annoying phenomenon. How to get rid of that one ?
tags:
cti-tet
nc
netcat
opensolaris
suite
test
testing
Linkage:
Technorati cosmos
Sunday Apr 13, 2008
During nc(1) preintegration testing, short time before it went back
I had found that 'cat /etc/passwd | nc localhost 4444' produced endless loop with
100% CPU utilization, looping in calls doing poll(2) (I still remember my laptop suddenly getting much warmer
than it should be and CPU fan cranking up).
'nc localhost 4444 < /etc/password' was not exhibiting that behavior.
The cause was a difference between poll(2) implementation on BSD and Solaris. Since I am working on Netcat
in Solaris again (adding more features, stay tuned), it's time to take a look back
and maybe even help people porting similar software from BSD to Solaris.
The issue appears because POLLHUP is set in read events bitfield for stdin after pipe is closed (or to be more precise - after the producer/write end is done) on Solaris. poll.c (which resembles readwrite() function from nc) illustrates the issue:
01 #include <stdio.h>
02 #include <poll.h>
03
04 #define LEN 1024
05
06 int main(void) {
07 int timeout = -1;
08 int n;
09 char buf[LEN];
10 int plen = LEN;
11
12 struct pollfd pfd;
13
14 pfd.fd = fileno(stdin);
15 pfd.events = POLLIN;
16
17 while (pfd.fd != -1) {
18 if ((n = poll(&pfd, 1, timeout)) < 0) {
19 err(1, "Polling Error");
20 }
21 fprintf(stderr, "revents = 0x%x [ %s %s ]\n",
22 pfd.revents,
23 pfd.revents & POLLIN ? "POLLIN" : "",
24 pfd.revents & POLLHUP ? "POLLHUP" : "");
25
26 if (pfd.revents & (POLLIN|POLLHUP)) {
27 if ((n = read(fileno(stdin), buf, plen)) < 0) {
28 fprintf(stderr,
29 "read() returned neg. val (%d)\n", n);
30 return;
31 } else if (n == 0) {
32 fprintf(stderr, "read() returned 0\n", n);
33 pfd.fd = -1;
34 pfd.events = 0;
35 } else {
36 fprintf(stderr, "read: %d bytes\n", n);
37 }
38 }
39 }
40 }
Running it on NetBSD (chosen because my personal non-work mailbox is hosted on a machine running it) produces the following:
otaku[~]% ( od -N 512 -X -v /dev/zero | sed 's/ [ \t]*/ /g'; sleep 3 ) | ./poll revents = 0x1 [ POLLIN ] read: 1024 bytes revents = 0x1 [ POLLIN ] read: 392 bytes revents = 0x11 [ POLLIN POLLHUP ] read() returned 0
I had to post-process the output of od(1) (because of difference between output of od(1) on NetBSD and Solaris) and slow the execution down a bit (via sleep) in order to make things more visible (try to run the command without the sleep and the pipe will be closed too quickly). On OpenSolaris the same program produces different pattern:
moose:~$ ( od -N 512 -X -v /dev/zero | sed 's/ [ \t]*/ /g' ; sleep 3 ) | ./poll revents = 0x1 [ POLLIN ] read: 1024 bytes revents = 0x1 [ POLLIN ] read: 392 bytes revents = 0x10 [ POLLHUP ] read() returned 0
So, the program is now obviously correct. Had the statement on line 26 checked only POLLIN, the command above (with or without the sleep) would go into endless loop on Solaris:
revents = 0x11 [ POLLIN POLLHUP ] read: 1024 bytes revents = 0x11 [ POLLIN POLLHUP ] read: 392 bytes revents = 0x10 [ POLLHUP ] revents = 0x10 [ POLLHUP ] revents = 0x10 [ POLLHUP ] ...
Both OSes set POLLHUP after the pipe is closed. The difference is that while BSD always
indicates POLLIN (even if there is nothing to read), Solaris strips it after data stream ended.
So, which one is correct ?
poll() function as
described by OpenGroup says that
"POLLHUP and POLLIN are not mutually exclusive
".
This means both implementations seem to conform to the IEEE Std 1003.1, 2004 Edition standard
(part of POSIX) in this respect.
However, the POSIX standard also says:
This might be still ok even though POLLIN flag remains to be set in NetBSD's poll() even after no data are available for reading (try to comment out lines 33,34 and run as above) because the standard says about POLLIN flag: For STREAMS, this flag is set in revents even if the message is of zero length.
Without further reading it is hard to tell how exactly should POSIX compliant poll() look like. On the Austin group mailing list there was a thread about poll() behavior w.r.t. POLLHUP suggesting this is fuzzy area.
Anyway, to see where exactly is POLLHUP set for pipes in OpenSolaris go to fifo_poll(). The function _sets_ the revents bit field to POLLHUP so the POLLIN flag is wiped off after that. fifo_poll() is part of fifofs kernel module which has been around in Solaris since late eighties (I was still in elementary school the year fifovnops.c appeared in SunOS code base :)). NetBSD has fifofs too but the POLLHUP flag gets set via bit logic operation in pipe_poll() which is part of syscall processing code. The difference between OpenSolaris and NetBSD (whoa, NetBSD project uses OpenGrok !) POLLHUP attitude (respectively) is now clear:
tags:
opengrok
opensolaris
poll
pollhup
posix
solaris
syscall
Linkage:
Technorati cosmos
Friday Apr 04, 2008
The flashback is still alive even weeks after: the day before my presentation at FIRST Technical
Colloquium in Prague I brought my 2 years old laptop with the work-in-progress slides to the office.
Since I wanted to finish the slides in the evening a live-upgrade
process was fired off on the laptop to get fresh Nevada
version. (of course, to show off during the presentation ;))
LU
is very I/O intensive process and the red Ferrari notebooks tend to get _very_ hot. In the afternoon I
noticed that the process failed. To my astonishment, the I/O operations started to fail.
After couple of reboots (and zpool status / fmadm faulty commands)
it was obvious that the disk cannot be trusted anymore. I was able to rescue some data
from the ZFS pool which was spanning the biggest slice of the internal disk but not all data.
(ZFS is not willing to get corrupted data out.) My slides were lost as well as other data.
After some time I stumbled upon James Gosling's
blog entry about ZFS mirroring on laptop.
This get me started (or more precisely I was astonished and wondered how is it possible
that this idea escaped me because at that time ZFS had been in Nevada for a long time)
and I have discovered several similar and more
in-depth
blog entries about the topic.
After some experiments with borrowed USB disk it was time to make it reality
on a new laptop.
The process was a multi-step one:
Part Tag Flag Cylinders Size Blocks 0 root wm 3 - 1277 9.77GB (1275/0/0) 20482875 1 unassigned wm 1278 - 2552 9.77GB (1275/0/0) 20482875 2 backup wm 0 - 19442 148.94GB (19443/0/0) 312351795 3 swap wu 2553 - 3124 4.38GB (572/0/0) 9189180 4 unassigned wu 0 0 (0/0/0) 0 5 unassigned wu 0 0 (0/0/0) 0 6 unassigned wu 0 0 (0/0/0) 0 7 home wm 3125 - 19442 125.00GB (16318/0/0) 262148670 8 boot wu 0 - 0 7.84MB (1/0/0) 16065 9 alternates wu 1 - 2 15.69MB (2/0/0) 32130
AVAILABLE DISK SELECTIONS:
0. c0d0
/pci@0,0/pci-ide@12/ide@0/cmdk@0,0
1. c5t0d0
/pci@0,0/pci1025,10a@13,2/storage@4/disk@0,0
# zpool create -f data mirror c0d0s7 c5t0d0For a while I have struggled with finding a name for the pool (everybody seems either to stick to the 'tank' name or come up with some double-cool-stylish name which I wanted to avoid because of the likely degradation of the excitement from that name) but then chosen the ordinary data (it's what it is, after all).
root:moose:/data# mkfile 10g /data/test & [1] 10933 root:moose:/data# zpool status pool: data state: ONLINE scrub: none requested config: NAME STATE READ WRITE CKSUM data ONLINE 0 0 0 mirror ONLINE 0 0 0 c0d0s7 ONLINE 0 0 0 c5t0d0 ONLINE 0 0 0 errors: No known data errorsIt survived it without a hitch (okay, I had to wait for the zpool command to complete a little bit longer due to the still ongoing I/O but that was it) and resynced the contents automatically after the USB disk was reconnected:
root:moose:/data# zpool status pool: data state: DEGRADED status: One or more devices are faulted in response to persistent errors. Sufficient replicas exist for the pool to continue functioning in a degraded state. action: Replace the faulted device, or use 'zpool clear' to mark the device repaired. scrub: resilver in progress for 0h0m, 3.22% done, 0h5m to go config: NAME STATE READ WRITE CKSUM data DEGRADED 0 0 0 mirror DEGRADED 0 0 0 c0d0s7 ONLINE 0 0 0 c5t0d0 FAULTED 0 0 0 too many errors errors: No known data errorsAlso, with heavy I/O it is needed to mark the zpool as clear after the resilver completes via zpool clear data because the USB drive is marked as faulty. Normally this will not happen (unless the drive really failed) because I will be connecting and disconnecting the drive only when powering on or shutting down the laptop, respectively.
# chmod A+user:vk:add_subdirectory:fd:allow /data # zfs allow -s @major_perms clone,create,destroy,mount,snapshot data # zfs allow -s @major_perms send,receive,share,rename,rollback,promote data # zfs allow -s @major_props copies,compression,quota,reservation data # zfs allow -s @major_props snapdir,sharenfs data # zfs allow vk @major_perms,@major_props dataAll of the commands had to be done under root.
$ zfs create data/vk
dataset properties comment +-------------------+--------------------------------+------------------------+ | data/vk/Documents | copies=2 | presentations | | data/vk/Saved | compression=on exec=off | stuff from web | | data/vk/DVDs | compression=gzip-8 exec=off | Nevada ISOs for LU | | data/vk/CRs | compression=on copies=2 | precious source code ! | +-------------------+--------------------------------+------------------------+So the commands will be:
$ zfs create -o copies=2 data/vk/Documents $ zfs create -o compression=gzip-3 -o exec=off data/vk/Saved ...
However, this is not the end of it but just beginning. There are many things to make the setup even better, to name a few:
With all the above the data should be safe from disk failure (after all disks are often called "spinning rust" so they are going to fail sooner or later) and also the event of loss of both laptop and USB disk.
Lastly, a philosophical thought: One of my colleagues considers hardware as a necessary (and very faulty) layer which is only needed to make it possible to express the ideas in software. This might seem extreme but come to think of it. ZFS is special in this sense - being a software which provides that bridge, it's core idea to isolate the hardware faults.
tags:
laptop
mirror
notebook
opensolaris
raid
solaris
usb
zfs
Linkage:
Technorati cosmos
Friday Feb 15, 2008
Two weeks ago (yeah, I am a slacker) FIRST technical colloquium was held in Prague and we (me and Sasha) were given the opportunity to attend (the fact the Derrick serves as FIRST chair in the steering comittee has of course something to do with it).
I only attended one day of the technical colloquium (Tuesday 29th).
The day was filled with various talks and presentations. Most of them were
performed by various CERT teams members from around the world. This was because
this event was a joint meeting of FIRST and TF-CSIRT.
It was definitely
interesting to see very different approaches to the shared problem set (dealing with
incidents, setting up honey pots, building forensic analysis labs, etc.).
Not only these differences stemmed from sizes of the networks and organizations
but also (and that was kind of funny) from nationalities.
In the morning I talked about the integration of
Netcat into Solaris,
describing the process, current features and planned enhancements and extensions.
The most anticipated talk was by Adam Laurie who is entertaining guy involved in many hacker-like activities (see e.g. A hacker games the hotel
article by Wired) directed at proving insecurities in
many publicly used systems.
Adam (brother of Ben Laurie, author of Apache-SSL
and OpenSSL contributor) first started with intro about satellite scanning, insecure hotel safes
(with backdoors installed by the manufacturers which can be overcome by a screwdriver).
Then he proceeded to talk about RFID chips, mainly about cloning.
Also, at the "social event" in the evening I had the pleasure to share a table with Ken van Wyk who is overall cool fellow and the author of Secure coding and Incident response books from O'Reilly.
In overall, it was interesting to see so many security types in a room and get to know some of them.
tags:
cert
conference
first
netcat
prague
security
solaris
tf-csirt
Linkage:
Technorati cosmos