<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Vidar's Blog</title>
	<atom:link href="http://www.vidarholen.net/contents/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.vidarholen.net/contents/blog</link>
	<description>Linux and technology in general</description>
	<lastBuildDate>Wed, 30 Jan 2013 19:03:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Making bash run DOS/Windows CRLF EOL scripts</title>
		<link>http://www.vidarholen.net/contents/blog/?p=236</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=236#comments</comments>
		<pubDate>Wed, 30 Jan 2013 18:10:05 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Basic Linux-related things]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[shell script]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=236</guid>
		<description><![CDATA[If you for any reason use a Windows editor to write scripts, it can be annoying to remember to convert them and bash fails in mysterious ways when you don&#8217;t. Let&#8217;s just get rid of that problem once and for all: cat > $'/bin/bash\r']]></description>
			<content:encoded><![CDATA[<p>If you for any reason use a Windows editor to write scripts, it can be annoying to remember to convert them and bash fails in mysterious ways when you don&#8217;t. Let&#8217;s just get rid of that problem once and for all:</p>
<p><code><br />
cat > $'/bin/bash\r' << "EOF"<br />
#!/usr/bin/env bash<br />
script=$1<br />
shift<br />
exec bash <(tr -d '\r' < "$script") "$@"<br />
EOF<br />
</code></p>
<p>This allows you to execute scripts with DOS/Windows \r\n line endings with <code>./yourscript</code> (but it will fail if the script specifies parameters on the shebang, or if you run it with <code>bash yourscript</code>). It works because from a UNIX point of view, DOS/Windows files specify the interpretter as "bash^M", and we override that to clean the script and run bash on the result. </p>
<p>Of course, you can also replace the helpful exec bash part with <code>echo "Run dos2unix on your file!" >&#038;2</code> if you'd rather give your users a helpful reminder rather than compatibility or a crazy error.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=236</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ShellCheck: shell script analysis</title>
		<link>http://www.vidarholen.net/contents/blog/?p=221</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=221#comments</comments>
		<pubDate>Sat, 08 Dec 2012 03:23:22 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Basic Linux-related things]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[shell script]]></category>
		<category><![CDATA[why-bash-is-like-that]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=221</guid>
		<description><![CDATA[Shell scripting is notoriously full of pitfalls, unintuitive behavior and poor error messages. Here are some things you might have experienced: find -exec fails on commands that are perfectly valid 0==1 is apparently true Comparisons are always false, and write files while failing Variable values are available inside loops, but reset afterwards Looping over filenames [...]]]></description>
			<content:encoded><![CDATA[<p>Shell scripting is notoriously full of pitfalls, unintuitive behavior and poor error messages. Here are some things you might have experienced:</p>
<ul>
<li>find -exec fails on commands that are perfectly valid</li>
<li>0==1 is apparently true</li>
<li>Comparisons are always false, and write files while failing</li>
<li>Variable values are available inside loops, but reset afterwards</li>
<li>Looping over filenames with spaces fails, and quoting doesn&#8217;t help</li>
</ul>
<p>&nbsp;</p>
<p>
<a href="http://www.vidarholen.net/contents/shellcheck/">ShellCheck</a> is my latest project. It will check shell scripts for all of the above, and also tries to give helpful tips and suggestions for otherwise working ones. You can paste your script and have it checked it online, or you can downloaded it and run it locally.
</p>
<p>
Other things it checks for includes reading from and redirecting to a file in the same pipeline, useless uses of cat, apparent variable use that won&#8217;t expand, too much or too little quoting in [[ ]], not quoting globs passed to find, and instead of just saying &#8220;syntax error near unexpected token `fi&#8217;&#8221;, it points to the relevant if statement and suggests that you might be missing a &#8216;then&#8217;.
</p>
<p>It&#8217;s still in the early stages, but has now reached the point where it can be useful. The online version has a feedback button (in the top right of your annotated script), so feel free to <a href="http://www.vidarholen.net/contents/shellcheck/">try it out</a> and submit suggestions!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=221</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Approaches to data recovery</title>
		<link>http://www.vidarholen.net/contents/blog/?p=195</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=195#comments</comments>
		<pubDate>Sat, 08 Sep 2012 14:37:48 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Basic Linux-related things]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[fs]]></category>
		<category><![CDATA[recovery]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=195</guid>
		<description><![CDATA[There are a lot of howtos and tutorials for using data recovery tools in Linux, but far less on how to choose a recovery tool or approach in the first place. Here&#8217;s an overview with suggestions for which route to go or tool to use: Cause Outlook Tools Forgotten login password Fantastic Any livecd This [...]]]></description>
			<content:encoded><![CDATA[<p>There are a lot of howtos and tutorials for using data recovery tools in Linux, but far less on how to choose a recovery tool or approach in the first place. Here&#8217;s an overview with suggestions for which route to go or tool to use:</p>
<table>
<tr>
<th>Cause</th>
<th>Outlook</th>
<th>Tools</th>
</tr>
<tr>
<td>Forgotten login password</td>
<td>Fantastic</td>
<td>Any livecd</td>
</tr>
<tr>
<td></td>
<td colspan="2">This barely qualifies as data recovery, but is included for completeness. If you forget the login password, you can just boot a livecd and mount the drive to access the files. You can also chroot into it and reset the password. Google &#8220;linux forgot password&#8221;.</td>
</tr>
<tr>
<td>Accidentally deleting files in use</td>
<td>Excellent</td>
<td>lsof, cp</td>
</tr>
<tr>
<td></td>
<td colspan="2">When accidentally deleting a file that is still in use by some process &#8212; like an active log file or the source of a video you&#8217;re encoding &#8212; make sure the process doesn&#8217;t exit (sigstop if necessary) and copy the file from the /proc file handle. Google &#8220;lsof recover deleted files&#8221;</td>
</tr>
<tr>
<td>Accidentally deleting other files</td>
<td>Fair for harddisks, bad for SSDs</td>
<td>testdisk, ext3grep, extundelete</td>
</tr>
<tr>
<td></td>
<td colspan="2">When deleting a file that&#8217;s not currently being held open, stop as much disk activity as you can to prevent the data from being overwritten. If you&#8217;re using an SSD, the data was probably irrevocably cleared within seconds, so bad luck there. Proceed with an fs specific undeletion tool:  Testdisk can undelete NTFS, VFAT and ext2, extundelete/ext3grep can help with ext3 and ext4. Google &#8220;YourFS undeletion&#8221;. If you can&#8217;t find an undeletion tool for your file systems, or if it fails, try PhotoRec.</td>
</tr>
<tr>
<td>Trashing the MBR or deleting partitions</td>
<td>Excellent</td>
<td>gpart (note: not gpart<strong>ed</strong>), testdisk</td>
</tr>
<tr>
<td></td>
<td colspan="2">If you delete a partition with fdisk or recover the MBR from a backup while forgetting that it also contains a partition table, gpart or testdisk will usually easily recover them. If you overwrite any more than the first couple of kilobytes though, it&#8217;s a different ballgame. Just don&#8217;t confuse gpart (guess partitions) with gparted (gtk/graphical partition editor). Google &#8220;recover partition table&#8221;.</td>
</tr>
<tr>
<td>Reformatting a file system</td>
<td>Depends on fs</td>
<td>e2fsck, photorec, testdisk</td>
</tr>
<tr>
<td></td>
<td colspan="2">If you format the wrong partition, recovery depends on the old and new file system. Try finding unformat/recovery tools for your old fs. Accidentally formatting a ext3 fs to ntfs (like Windows helpfully suggests when it detects a Linux fs) can often be almost completely reverted by running fsck with an alternate superblock. Google &#8220;ext3 alternate superblock recovery&#8221; or somesuch. </p>
<p />
Reformatting ext2/3/4 with ext2/3/4 will tend to overwrite the superblocks, making this harder. Consider PhotoRec.
</td>
</tr>
<tr>
<td>Repartition and reinstall</td>
<td>Depends on progress</td>
<td></td>
</tr>
<tr>
<td></td>
<td colspan="2">If you ran a distro installer and accidentally repartitioned and reformatted a disk, try treating it as a case of deleted partitions plus reformatted partitions as described above. Chances of recovery are smaller the more files the installer copied to the partitions. If all else fails, PhotoRec.</td>
</tr>
<tr>
<td>Bad sectors and drive errors</td>
<td>Ok, depending on extent</td>
<td>ddrescue</td>
</tr>
<tr>
<td></td>
<td colspan="2">If the drive has errors, use ddrescue to get as much of the data as possible onto another drive, then treat it as a corrupted file system. Try the fs&#8217; fsck tool, or if the drive is highly corrupted, PhotoRec.</td>
</tr>
<tr>
<td>Lost encryption key</td>
<td>Very bad</td>
<td>bash, cryptsetup</td>
</tr>
<tr>
<td></td>
<td colspan="2">I don&#8217;t know of any tools made for attempting to crack a LUKS password, though you can generate permutations and script a simple cracker if you have limited number of permutations (&#8220;it was Swordfish with some l33t, and a few numbers at the end&#8221;). If you have no idea, or if your encryption software uses TPM (rare for Linux), you&#8217;re screwed.</td>
</tr>
<tr>
<td>Reformatted or partially overwritten LUKS partition</td>
<td>Horrible</td>
<td></td>
</tr>
<tr>
<td></td>
<td colspan="2">LUKS uses your passphrase to encrypt a master key, and stores this info at the start of the partition. If this gets overwritten, you&#8217;re screwed even if you know the passphrase.</td>
</tr>
<tr>
<td>Other kinds of corruptions or unknown FS</td>
<td>Indeterminable</td>
<td>PhotoRec, strings, grep</td>
</tr>
<tr>
<td></td>
<td colspan="2">PhotoRec searches by file signature, and can therefore recover files from a boatload of FS and scenarios, though you&#8217;ll often lose filenames and hierarchies. If you have important ASCII data, strings can dump ASCII text regardless of FS, and you can grep that as a last resort.</td>
</tr>
</table>
<p>If you have other suggestions for scenarios, tools or approaches, leave a commment. Otherwise, I&#8217;ll wish you a speedy recovery!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=195</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Why Bash is like that: Subshells</title>
		<link>http://www.vidarholen.net/contents/blog/?p=178</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=178#comments</comments>
		<pubDate>Wed, 22 Aug 2012 11:50:32 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Basic Linux-related things]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[why-bash-is-like-that]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=178</guid>
		<description><![CDATA[Bash can seem pretty random and weird at times, but most of what people see as quirks have very logical (if not very good) explanations behind them. This series of posts looks at some of them. # I run this script, but afterwards my PATH and current dir hasn't changed! #!/bin/bash export PATH=$PATH:/opt/local/bin cd /opt/games/ [...]]]></description>
			<content:encoded><![CDATA[<p>Bash can seem pretty random and weird at times, but most of what people see as quirks have very logical (if not very good) explanations behind them. This series of posts looks at some of them.</p>
<pre>
# I run this script, but afterwards my PATH and current dir hasn't changed!

#!/bin/bash
export PATH=$PATH:/opt/local/bin
cd /opt/games/
</pre>
<p>or more interestingly</p>
<pre>
# Why does this always say 0?
n=0
cat file | while read line; do (( n++ )); done
echo $n
</pre>
<p>In the first case, you can add a <code>echo "Path is now $PATH"</code>, and see the expected path. In the latter case, you can put a <code>echo $n</code> in the loop, and it will count up as you&#8217;d expect, but at the end you&#8217;ll still be left with 0.</p>
<p>To make things even more interesting, here are the effects of running these two examples (or equivalents) in different shells:</p>
<table>
<tr>
<td></td>
<td>set in script</td>
<td>set in pipeline</td>
</tr>
<tr>
<td>Bash</td>
<td style='background-color: #FFC0C0'>No effect</td>
<td style='background-color: #FFC0C0'>No effect</td>
</tr>
<tr>
<td>Ksh/Zsh</td>
<td style='background-color: #FFC0C0'>No effect</td>
<td style='background-color: #C0FFC0'>Works</td>
</tr>
<tr>
<td>cmd.exe</td>
<td style='background-color: #C0FFC0'>Works</td>
<td style='background-color: #FFC0C0'>No effect</td>
</tr>
</table>
<p>What we&#8217;re experiencing are subshells, and different shells have different policies on what runs in subshells.</p>
<p>Environment variables, as well as the current directory, is only inherited parent-to-child. Changes to a child&#8217;s environment are not reflect in the parent. Any time a shell forks, changes done in the forked process are confined to that process and its children. </p>
<p>In Unix, all normal shells will fork to execute other shell scripts, so setting PATH or cd&#8217;ing in a script will never have an effect after the command is done (instead, use <code>"source file"</code> aka <code>". file"</code> to read and execute the commands without forking). </p>
<p>However, shells can differ in when subshells are invoked. In Bash, all elements in a pipeline will run in a subshell. In Ksh and Zsh, all <i>except the last</i> will run in a subshell. POSIX leaves it undefined.</p>
<p>This means that <code>echo "2 + 3" | bc | read sum</code> will work in Ksh and Zsh, but fail to set the variable <code>sum</code> in Bash. </p>
<p>To work around this in Bash, you can usually use redirection and process substition instead:</p>
<p><code>read sum < <(echo "2 + 3" | bc) </code></p>
<p>So, where do we find subshells? Here are a list of commands that in some way fails to set foo=bar for subsequent commands (note that all the examples set it in some subshell, and can use it until the subshell ends):</p>
<pre>
# Executing other programs or scripts
./setmyfoo
foo=bar ./something

# Anywhere in a pipeline in Bash
true | foo=bar | true

# In any command that executes new shells
awk '{ system("foo=bar") }'h
find . -exec bash -c 'foo=bar' \;

# In backgrounded commands and coprocs:
foo=bar &#038;
coproc foo=bar

# In command expansion
true "$(foo=bar)"

# In process substitution
true < <(foo=bar)

# In commands explicitly subshelled with ()
( foo=bar )
</pre>
<p>and probably some more that I'm forgetting.</p>
<p>Trying to set a variable, option or working dir in any of these contexts will result in the changes not being visible for following commands. </p>
<p>Knowing this, we can use it to our advantage:</p>
<pre>
# cd to each dir and run make
for dir in */; do ( cd "$dir" &#038;&#038; make ); done

# Compare to the more fragile
for dir in */; do cd "$dir"; make; cd ..; done

# mess with important variables
fields=(a b c); ( IFS=':'; echo ${fields[*]})

# Compare to the cumbersome
fields=(a b c); oldIFS=$IFS; IFS=':'; echo ${fields[*]}; IFS=$oldIFS; 

# Limit scope of options
( set -e; foo; bar; baz; )
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=178</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>On Windows 8</title>
		<link>http://www.vidarholen.net/contents/blog/?p=39</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=39#comments</comments>
		<pubDate>Sun, 22 Jul 2012 20:13:38 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[win8]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=39</guid>
		<description><![CDATA[When someone with a modern, online, multi-gigabyte, multi-core tablet says "Oh darn, I can't. I don't have a computer with me", something is tragically wrong. That's why I can't wait for Windows 8. ]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m excited about Windows 8.</p>
<p>There, I said it.</p>
<p>I have five Linux devices in my home, I write Python in Vim on Ubuntu professionally, and I have rolled my eyes at every major shift in Windows since 3.11. </p>
<p>But I&#8217;m excited about Windows 8.</p>
<p>Before I ruin your day with my fanboy ramblings, let me clear up some reasons for why I don&#8217;t hate it (if you don&#8217;t either, feel free to <a href="#theend">skip towards the end</a>). </p>
<p><strong>&#8220;I don&#8217;t want a nerfed touch interface on my desktop!&#8221;</strong></p>
<div class="wp-caption alignright" style="width: 260px"><img alt="A crowded desktop with Chrome and The Gimp running" src="/imgs/blog/win8desktop.png" width="250" height="180" /><p class="wp-caption-text">My actual Windows 8 desktop</p></div>
<p>Agreed. Fortunately, as you can see from this screenshot, a Windows 8 desktop session looks just like a Windows 7 one, with efficient, dense, touch hostile apps. </p>
<p>Believe me, I&#8217;ll be the first to scream bloody murder if I have to develop Windows software in a touch UI with only two apps on screen.</p>
<p>On that note, ARM based Windows 8 devices won&#8217;t support normal desktop sessions, so x86 is implied for the rest of the article. The reason for this should become apparent later.</p>
<div style="clear: both"></div>
<p><strong>&#8220;I want a start menu!&#8221;</strong></p>
<div class="wp-caption alignleft" style="width: 110px"><img alt="A long, disorganized start menu showing 40-odd items with a scroll bar" src="/imgs/blog/startmenu.png" width="100" height="210" /><p class="wp-caption-text">Oh, that wonderful start menu</p></div>
<p>The start menu was awesome in 1998, when having 15 apps installed made you a power user. But now my entertainment PC (pictured) has 55 top level entries, and my development box has 92! In a tiny list with a huge scroll bar!</p>
<p>&#8220;But&#8221;, I hear you say, &#8220;that&#8217;s the full list! No uses that!&#8221;.</p>
<p>Quite right. The apps you love, you pin on the taskbar. <i>This works exactly the same in Windows 8.</i></p>
<p>With your hands on the keyboard, you find by keyboard search. <i>This works exactly the same in Windows 8.</i></p>
<p>This leaves the apps you use fairly often, which are either pinned to the start menu, or have bubbled their way up through frequent use. </p>
<div class="wp-caption alignright" style="width: 202px"><img alt="An outline of the thin, fickle start menu on a huge full HD display" src="/imgs/blog/startmenuarea.png" width="192" height="108" /><p class="wp-caption-text">Default 1080p start menu area</p></div>
<p>On a full HD display, the default is 20 items, with a maximum of 24. Shown in a linear list. The default uses literally less than a tenth of the available screen real estate (pictured). </p>
<p>On a smaller screen, you get 12-14 items, which is a very snug fit, and definitely not enough if you want shortcuts to web sites like I have on my Android and iOS devices. </p>
<p>So what do you do? Instead of having a short, narrow list on the left, we could lay them out in a grid (like desktop icons) to fit more of them. </p>
<p>And that pretty much describes the Windows 8 start screen!</p>
<p>Of course, you have tiles instead of icons, but I&#8217;ll get to those in a bit. </p>
<div style="clear: both"></div>
<p><strong>&#8220;Secure boot will block Linux and other OS!&#8221;</strong></p>
<p>Maybe. I hope it doesn&#8217;t. I&#8217;m not saying it&#8217;s all cream and peaches, but hopefully it&#8217;ll continue to be optional on all devices. </p>
<div style="clear: both"></div>
<p><strong>Slimmer and faster!</strong></p>
<p>There&#8217;s a running joke that both processing power and Windows boot time doubles every 18 months. </p>
<p>Windows 8, however, cold boots in 10 seconds on my low end, portable test hardware. It also uses about 30% less RAM than Windows 7. </p>
<p>No one is more surprised than me.</p>
<div style="clear: both"></div>
<p><a name="tiles"></a><br />
<strong>Tiles &#8212; Icons++</strong></p>
<p>I no longer &#8220;check my email&#8221;, I get a notification when new mail is received. I no longer visit web sites regularly, I use RSS to tell me when there&#8217;s something new. Why should I still open my apps to see what&#8217;s happening?</p>
<p>Sure, my RSS reader <i>could</i> be an icon saying &#8220;RSS Reader&#8221;, but it would be more convenient if it said &#8220;Bitcoin market crashes, and 14 more&#8221;. <i>Windows 8 does this.</i></p>
<p>My ebook reader <i>could</i> say &#8220;eBook reader&#8221;. Or it could say &#8220;Reading Dune, page 134 of 245&#8243;, with cover art instead of a generic icon. <i>Windows 8 does this.</i></p>
<p>My video player <i>could</i> say &#8220;VLC&#8221;, or it could show a screenshot of where I stopped a video last night. Wait, *cough*, that&#8217;s a terrible idea. <i>Windows 8 lets you disable this tile-by-tile!</i></p>
<div class="wp-caption alignright" style="width: 195px"><img alt="A 2x1 tile titled People, along with two 1x1 tiles, each representing a certain person" src="/imgs/blog/multitiles.png" width="185" height="192" /><p class="wp-caption-text">A People app tile, plus two tiles representing two specific friends</p></div>
<p>One app can have multiple tiles. Just like how you can have two books on your desktop that open in the same reader, you can have two tiles. They&#8217;ll show the book title and page number separately.</p>
<p>For non-file based links, Win7 users can create shortcuts to invoke a program with different command line arguments (but no one does). With Windows 8, you can pin application specific contents, e.g. a Facebook contact, and have a tile representing them.</p>
<p>This tile will then show photos of that particular person (pictured), plus their recent activity and messages they send you. Great for close friends and people you&#8217;re dating (or stalking). When opened, you&#8217;ll go immediately to their page. </p>
<p>Likewise, you can have an icon for a specific Wordfeud game, showing current score and status. An often used playlist? A news source you follow closely? A specific alt in a mmorpg? Separate work and private email accounts? All available at a glance.</p>
<div style="clear: both"></div>
<p><a name="theend"></a><br />
<strong>Is it worth an upgrade?</strong></p>
<p>Honestly? While I think Windows 8 is an improvement in some ways, I probably won&#8217;t be upgrading my Windows 7 desktop/laptop systems any time soon. </p>
<p>However, (and here&#8217;s the twist), I will camp out a cold winter&#8217;s night to get a Microsoft Surface or similar Windows 8 tablet PC. Because you see, I consider Windows 8:</p>
<div style="clear: both"></div>
<p><strong>The hands down, best tablet PC OS to date</strong></p>
<p>I don&#8217;t even care about Windows 8 vs GNU+Linux, I see Windows 8 tablets vs Windows desktops and iOS/Android tablets. </p>
<p>Why? </p>
<p>I hope I&#8217;ve convincingly argued that Windows 8 is not nerfed, but a complete desktop OS (&#8220;as far as Windows goes&#8221;, hurr durr). </p>
<p>Now, imagine that on a tablet: </p>
<p><i>Fully usable desktop</i> &#8212; Bring it to the office, dock it with keyboard, mouse and external monitor. You can now use it as a regular PC running Visual Studio, Excel, and all that jazz! </p>
<p><i>Fully usable tablet</i> &#8212; Bring it with you on the bus, and use it as a small, touch friendly browser and time waster, just like an iPad or Android tablet! </p>
<p><i>&#8230;in one device</i> &#8212; Inspiration strikes? Switch back to your Visual Studio project and fix, test and commit while still on the bus.</p>
<p><i>Useful, new features</i> &#8212; I&#8217;m sure <a href="#tiles">tiles</a> can come in handy on a desktop system, but on a tablet I think they&#8217;ll set a new standard for convenience.</p>
<p><i>No software limitations</i> &#8212; Encounter something stupid, like not being able to run an app in the background, or not being able to search on a web page (looking at you, iPad!!)? You have a full desktop OS to fall back on! </p>
<p><i>Both toy and tool</i> &#8212; It&#8217;s no longer just a fun but useless toy. Bittorrent a Ubuntu iso, checksum it, and write it out to a thumb drive? Sure thing!</p>
<p>Want to demo something? Want to script something? You got it. </p>
<p>I would ditch my iPad 2 in a second. </p>
<div style="clear: both"></div>
<p><strong>Seriously?</strong></p>
<p>Seriously. </p>
<p>And yes, I think it will work in practice. You see, it already has:</p>
<p>I loved Maemo, the Debian based cell phone OS featuring xterm and a GNU toolset in the factory default. Like Windows 8, Maemo had a touch UI for normal operation, but also allowed you to go behind the scenes and run &#8220;proper&#8221; software. </p>
<p>While I obviously spent most of my time in the touch UI, Maemo was there for me when I needed more. Granted, not everyone feels they have to strip and encode the audio track from a youtube video on their phones, but the core point remains:</p>
<p><i>When someone with a modern, online, multi-gigabyte, multi-core tablet says &#8220;Oh darn, I can&#8217;t. I don&#8217;t have a computer with me&#8221;, something is tragically wrong. </i></p>
<p>And that&#8217;s why I can&#8217;t wait for Windows 8. </p>
<hr />
PS: I&#8217;ve written &#8220;Windows 8&#8243; a total of twenty-three times in this article. I promise that nothing like this will ever happen again. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=39</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Technically correct: Inversed regex</title>
		<link>http://www.vidarholen.net/contents/blog/?p=36</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=36#comments</comments>
		<pubDate>Mon, 02 Apr 2012 10:47:04 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Advanced Linux-related things]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[compsci]]></category>
		<category><![CDATA[regex]]></category>
		<category><![CDATA[technically correct]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=36</guid>
		<description><![CDATA[How do I write a regex that matches lines that do not contain hi? That&#8217;s a frequently asked question if I ever saw one. Of course, the proper answer is: you don&#8217;t. You write a regex that does match hi and then invert the matching logic, ostensibly with grep -v. But where&#8217;s the fun in [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>How do I write a regex that matches lines that do <strong>not</strong> contain <code>hi</code>?</p></blockquote>
<p>That&#8217;s a frequently asked question if I ever saw one.</p>
<p>Of course, the proper answer is: you don&#8217;t. You write a regex that <strong>does</strong> match <code>hi</code> and then invert the matching logic, ostensibly with <code>grep -v</code>. But where&#8217;s the fun in that?</p>
<p>One interesting theorem that pops up in any book or class on formal grammars is that regular languages are closed under complement: the inverse of a regular expression is also a regular expression. This means that writing inverted regular expressions is theoretically possible, though it turns out to be quite tricky </p>
<p>Just try writing a regex that matches strings that does not contain &#8220;hi&#8221;, and test it against &#8220;hi&#8221;, &#8220;hhi&#8221; and &#8220;ih&#8221;, &#8220;iih&#8221; and such variations. Some solutions are coming up. </p>
<p>A way to cheat is using PCRE negative lookahead: <code>^(?!.*foo)</code> matches all strings not containing the substring &#8220;foo&#8221;. However, lookahead assertions require a stack, and thus can&#8217;t be modelled as a finite state machine. In other words, they don&#8217;t fit the mathematical definition of a regular expression, and therefore disqualify.</p>
<p>There are simple, well-known algorithms for turning regular expressions into non-deterministic finite automata, and from there to deterministic FA. Less commonly used and known are algorithms for inverting a DFA and for generating familiar textual regex from it. </p>
<p>You can find these described in <a href="http://www.cs.ucf.edu/courses/cop3402/sum2010/R3%20Regular%20Expressions%20and%20DFAs.ppt">various</a> lecture <a href="http://www.cs.rochester.edu/u/nelson/courses/csc_173/fa/re.html">notes and slides</a>, so I won&#8217;t recite them. </p>
<p>What I had a harder time finding was software that actually did this. So <a href="/contents/junk/files/invert.hs">here</a> is a Haskell program. It&#8217;s highly suboptimal but it does the job. When executed, it will ask for a regex and will then output a grep command that matches everything the regex does not (without <code>-v</code>, obviously). </p>
<p>The expressions it produces are quite horrific; it&#8217;s computer generated code, after all. </p>
<p>A regular expression for matching strings that do not match <code>.*hi.*</code> could be <code>grep -E '^([^h]|h+$|h+[^hi])*$'</code>.</p>
<p>This app, however, suggests <code>grep -E '^([^h]([^h]|)*||([^h][^h]*h|h)|([^h][^h]*(h(hh*[^hi]|[^hi]))|(h(hh*[^hi]|[^hi])))((hh*[^hi]|[^h])|)*|([^h][^h]*(h([^hi][^h]*h|h))|(h([^hi][^h]*h|h)))(([^hi][^h]*h|h)|)*)$'</code></p>
<p>It still works exactly as stated though!</p>
<p>The app just supports a small subset of regex, just enough to convince someone that it works, and as a party trick lets you answer the original question exactly as stated. </p>
<p>Technically correct is the best kind of correct. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=36</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Implementation of SHA512-crypt vs MD5-crypt</title>
		<link>http://www.vidarholen.net/contents/blog/?p=33</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=33#comments</comments>
		<pubDate>Tue, 16 Aug 2011 14:00:10 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Advanced Linux-related things]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[hashing]]></category>
		<category><![CDATA[md5]]></category>
		<category><![CDATA[password]]></category>
		<category><![CDATA[sha512]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=33</guid>
		<description><![CDATA[If you have a new installation, you&#8217;re probably using SHA512-based passwords instead of the older MD5-based passwords described in detail in the previous post, which I&#8217;ll assume you&#8217;ve read. sha512-crypt is very similar to md5-crypt, but with some interesting differences. Since the implementation of sha512 is really less interesting than the comparison with md5-crypt, I&#8217;ll [...]]]></description>
			<content:encoded><![CDATA[<p>If you have a new installation, you&#8217;re probably using SHA512-based passwords instead of the older MD5-based passwords described in detail in the <a href="/contents/blog/?p=32">previous post</a>, which I&#8217;ll assume you&#8217;ve read. sha512-crypt is very similar to md5-crypt, but with some interesting differences.</p>
<p>Since the implementation of sha512 is really less interesting than the comparison with md5-crypt, I&#8217;ll describe it by striking out the relevant parts of the md5-crypt description and writing in what sha512-crypt does instead.</p>
<p>Like md5-crypt, it can be divided into three phases. Initialization, loop, and finalization. </p>
<ol>
<li>Generate a simple <strike>md5</strike> <i>sha512</i> hash based on the salt and password</li>
<li>Loop <strike>1000</strike> <i>5000</i> times, calculating a new sha512 hash based on the previous hash concatenated with alternatingly the <i>hash of the</i> password and the salt. <i>Additionally, sha512-crypt allows you to specify a custom number of rounds, from 1000 to 999999999</i></li>
<li>Use a special base64 encoding on the final hash to create the password hash string</li>
</ol>
<p>&nbsp;</p>
<p>The main differences are the higher number of rounds, which can be user selected for better (or worse) security, the use of the hashed password and salt in each round, rather than the unhashed ones, and a few tweaks of the initialization step.</p>
<p>&nbsp;</p>
<p>Here&#8217;s the real sha512-crypt initialization.</p>
<ol>
<li>Let &#8220;password&#8221; be the user&#8217;s ascii password, &#8220;salt&#8221; the ascii salt (truncated to <strike>8</strike> <i>16</i> chars) <strike>, and &#8220;magic&#8221; the string &#8220;$1$&#8221;</strike></li>
<li>Start by computing the Alternate sum, <code>sha512(password + salt + password)</code></li>
<li>Compute the Intermediate<sub>0</sub> sum by hashing the concatenation of the following strings:
<ol>
<li>Password</li>
<li><strike>Magic</strike></li>
<li>Salt</li>
<li>length(password) bytes of the Alternate sum, repeated as necessary</li>
<li>For each bit in length(password), from low to high and stopping after the most significant set bit
<ul>
<li>If the bit is set, append <strike>a NUL byte</strike> <i>the Alternate sum</i></li>
<li>If it&#8217;s unset, append <strike>the first byte of</strike> the password</li>
</ul>
</li>
</ol>
<li><i>New: Let S_factor be 16 + the first byte of Intermediate<sub>0</sub></i></li>
<li><i>New: Compute the S bytes, length(salt) bytes of sha512(salt, concatenated S_factor times). </i></li>
<li><i>New: Compute the P bytes, length(password) bytes of sha512(password), repeated as necessary</i></li>
</ol>
<p>&nbsp;</p>
<p>Step 3.5 &#8212; which was very strange in md5-crypt &#8212; now makes a little more sense. We also calculated the S bytes and P bytes, which from here on will be used just like salt and password was in md5-crypt.</p>
<p>From this point on, the calculations will only involve the <strike>password</strike> <i>P bytes</i>, <strike>salt</strike> <i>S bytes</i>, and the Intermediate<sub>0</sub> sum. Now we loop 5000 times (by default), to stretch the algorithm.</p>
<ul>
<li>For i = 0 to <i>4</i>999 (inclusive), compute Intermediate<sub>i+1</sub> by concatenating and hashing the following:
<ol>
<li>If i is even, Intermediate<sub>i</sub></li>
<li>If i is odd, <strike>password</strike> <i>P bytes</i></li>
<li>If i is not divisible by 3, <strike>salt</strike> <i>S bytes</i></li>
<li>If i is not divisible by 7, <strike>password</strike> <i>P bytes</i></li>
<li>If i is even, <strike>password</strike> <i>P bytes</i></li>
<li>If i is odd, Intermediate<sub>i</sub></li>
</ol>
<p>At this point you don&#8217;t need Intermediate<sub>i</sub> anymore.
</li>
</ul>
<p>You will now have ended up with Intermediate<sub>5000</sub>. Let&#8217;s call this the Final sum. Since sha512 is 512bit, this is 64 bytes long.</p>
<p>The bytes will be rearranged, and then encoded as 86 ascii characters using the same base64 encoding as md5-crypt.</p>
<ol>
<li>Output the magic, &#8220;$6$&#8221;</li>
<li><i>New: If using a custom number of rounds, output &#8220;rounds=12345$&#8221;</i></li>
<li>Output the salt</li>
<li>Output a &#8220;$&#8221; to separate the salt from the encrypted section</li>
<li>Pick out the 64 bytes in this order: 63  62 20 41  40 61 19  18 39 60  59 17 38  37 58 16  15 36 57  56 14 35  34 55 13  12 33 54  53 11 32  31 52 10   9 30 51  50  8 29  28 49  7  6 27 48  47  5 26  25 46  4   3 24 45  44  2 23  22 43  1   0 21 42
<ul>
<li>For each group of 6 bits (there&#8217;s 86 groups), starting with the least significant
<ul>
<li>Output the corresponding base64 character with this index</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>&nbsp;</p>
<p>And yes, I do have a shell script for this as well: <a href="/contents/junk/files/sha512crypt.bash">sha512crypt</a>. This one takes about a minute to generate a hash, due to the higher number of rounds. However, it doesn&#8217;t support custom rounds.</p>
<p>I hope these two posts have provided an interesting look at two exceedingly common, but often overlooked, algorithms!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=33</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Password hashing with MD5-crypt in relation to MD5</title>
		<link>http://www.vidarholen.net/contents/blog/?p=32</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=32#comments</comments>
		<pubDate>Tue, 09 Aug 2011 14:00:39 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Advanced Linux-related things]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[hashing]]></category>
		<category><![CDATA[md5]]></category>
		<category><![CDATA[password]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=32</guid>
		<description><![CDATA[If you haven&#8217;t reinstalled recently, chances are you&#8217;re using MD5-based passwords. However, the password hashes you find in /etc/shadow look nothing like what md5sum returns. Here&#8217;s an example: /etc/shadow: $1$J7iYSKio$aEY4anysz.gtXxg7XlL6v1 md5sum: 7c6483ddcd99eb112c060ecbe0543e86 What&#8217;s the difference in generating these hashes? Why are they different at all? Just running md5sum on a password and storing that is [...]]]></description>
			<content:encoded><![CDATA[<p>If you haven&#8217;t reinstalled recently, chances are you&#8217;re using MD5-based passwords. However, the password hashes you find in /etc/shadow look nothing like what <code>md5sum</code> returns. </p>
<p>Here&#8217;s an example:</p>
<pre>
/etc/shadow:
$1$J7iYSKio$aEY4anysz.gtXxg7XlL6v1

md5sum:
7c6483ddcd99eb112c060ecbe0543e86
</pre>
<p>What&#8217;s the difference in generating these hashes? Why are they different at all?</p>
<p>Just running md5sum on a password and storing that is just marginally more secure than storing the plaintext password. </p>
<p>Thanks to GPGPUs, a modern gaming rig can easily try 5 billion such passwords per second, or go over the entire 8-character alphanumeric space in a day. With <a href="http://en.wikipedia.org/wiki/Rainbow_table">rainbow tables</a>, a beautiful time&#8211;space tradeoff, you can do pretty much the same in 15 minutes.</p>
<p>MD5-crypt employs <a href="http://en.wikipedia.org/wiki/Salt_%28cryptography%29">salting</a> to make precomputational attacks exponentially more difficult. Additionally, it uses <a href="http://en.wikipedia.org/wiki/Key_stretching">stretching</a> to make brute force attacks harder (but just linearly so). </p>
<p>As an aside, these techniques were used in the original crypt from 1979, so there&#8217;s really no excuse to do naive password hashing anymore. However, at that time the salt was 12 bits and the number of rounds 25 &#8212; quite adorable in comparison with today&#8217;s absolute minimum of 64 bits and 1000 rounds.</p>
<p>The original crypt was <a href="http://en.wikipedia.org/wiki/Data_Encryption_Standard">DES</a> based, but used a modified algorithm to prevent people from using existing DES cracking hardware. MD5-crypt doesn&#8217;t do any such tricks, and can be implemented in terms of any MD5 library, or even the md5sum util. </p>
<p>As regular reads might suspect, I&#8217;ve written a shell script to demonstrate this: <a href="/contents/junk/files/md5crypt.bash">md5crypt</a>. There are a lot of workarounds for Bash&#8217;s inability to handle NUL bytes in strings. It takes 10 seconds to generate a hash, and is generally awful..ly funny! </p>
<p>Let&#8217;s first disect a crypt hash. man 3 crypt has some details. </p>
<pre>
If salt is a character string starting with the characters
"$id$" followed by a string terminated by "$":

       $id$salt$encrypted

then instead of using the DES machine, id  identifies  the
encryption  method  used  and this then determines how the
rest of the password string is interpreted.  The following
values of id are supported:

       ID  | Method
       -------------------------------------------------
       1   | MD5
       2a  | Blowfish (on some Linux distributions)
       5   | SHA-256 (since glibc 2.7)
       6   | SHA-512 (since glibc 2.7)
</pre>
<p>Simple and easy. Split by $, and then your fields are Algorithm, Salt and Hash. </p>
<p>md5-crypt is a function that takes a plaintext password and a salt, and generate such a hash.</p>
<p>To set a password, you&#8217;d generate a random salt, input the user&#8217;s password, and write the hash to /etc/shadow. To check a password, you&#8217;d read the hash from /etc/shadow, extract the salt, run the algorithm on this salt and the candidate password, and then see if the resulting hash matches what you have.</p>
<p>md5-crypt can be divided into three phases. Initialization, loop, and finalization. Here&#8217;s a very high level description of what we&#8217;ll go through in detail:</p>
<ol>
<li>Generate a simple md5 hash based on the salt and password</li>
<li>Loop 1000 times, calculating a new md5 hash based on the previous hash concatenated with alternatingly the password and the salt.</li>
<li>Use a special base64 encoding on the final hash to create the password hash string</li>
</ol>
<p>&nbsp;</p>
<p>Put like this, it relatively elegant. However, there are a lot of details that turn this from elegant to eyerolling. </p>
<p>Here&#8217;s the real initialization.</p>
<ol>
<li>Let &#8220;password&#8221; be the user&#8217;s ascii password, &#8220;salt&#8221; the ascii salt (truncated to 8 chars), and &#8220;magic&#8221; the string &#8220;$1$&#8221;</li>
<li>Start by computing the Alternate sum, <code>md5(password + salt + password)</code></li>
<li>Compute the Intermediate<sub>0</sub> sum by hashing the concatenation of the following strings:
<ol>
<li>Password</li>
<li>Magic</li>
<li>Salt</li>
<li>length(password) bytes of the Alternate sum, repeated as necessary</li>
<li>For each bit in length(password), from low to high and stopping after the most significant set bit
<ul>
<li>If the bit is set, append a NUL byte</li>
<li>If it&#8217;s unset, append the first byte of the password</li>
</ul>
</li>
</ol>
</ol>
<p>&nbsp;</p>
<p>I know what you&#8217;re thinking, and yes, it&#8217;s very arbitrary. The latter part was most likely a bug in the original implementation, carried along as UNIX issues often are. Remember to stay tuned next week, when we&#8217;ll compare this to SHA512-crypt as used on new installations!</p>
<p>From this point on, the calculations will only involve the password, salt, and Intermediate<sub>0</sub> sum. Now we loop 1000 times, to stretch the algorithm.</p>
<ul>
<li>For i = 0 to 999 (inclusive), compute Intermediate<sub>i+1</sub> by concatenating and hashing the following:
<ol>
<li>If i is even, Intermediate<sub>i</sub></li>
<li>If i is odd, password</li>
<li>If i is not divisible by 3, salt</li>
<li>If i is not divisible by 7, password</li>
<li>If i is even, password</li>
<li>If i is odd, Intermediate<sub>i</sub></li>
</ol>
<p>At this point you don&#8217;t need Intermediate<sub>i</sub> anymore.
</li>
</ul>
<p>You will now have ended up with Intermediate<sub>1000</sub>. Let&#8217;s call this the Final sum. Since MD5 is 128bit, this is 16 bytes long.</p>
<p>The bytes will be rearranged, and then encoded as 22 ascii characters with a special base64-type encoding. This is not the same as regular base64:</p>
<pre>
Normal base64 set:
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/

Crypt base64 set:
./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
</pre>
<p>Additionally, there is no padding. The leftover byte will be encoded into 2 base64 ascii characters.</p>
<ol>
<li>Output the magic</li>
<li>Output the salt</li>
<li>Output a &#8220;$&#8221; to separate the salt from the encrypted section</li>
<li>Pick out the 16 bytes in this order: 11 4 10 5 3 9 15 2 8 14 1 7 13 0 6 12.
<ul>
<li>For each group of 6 bits (there are 22 groups), starting with the least significant
<ul>
<li>Output the corresponding base64 character with this index</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>Congratulations, you now have a compatible md5-crypt hash!</p>
<p>As you can see, it&#8217;s quite far removed from a naive <code>md5(password)</code> attempt. </p>
<p>Fortunately, one will only ever need this algorithm for compatibility. New applications can use the standard PBKDF2 algorithm, implemented by most cryptography libraries, which does the same thing only in a standardized and parameterized way.</p>
<p>As if this wasn&#8217;t bad enough, the next post next week will be more of the same, but with SHA512-crypt!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=32</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Why Bash is like that: Signal propagation</title>
		<link>http://www.vidarholen.net/contents/blog/?p=34</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=34#comments</comments>
		<pubDate>Wed, 03 Aug 2011 11:30:32 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Advanced Linux-related things]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[shell script]]></category>
		<category><![CDATA[signal]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[why-bash-is-like-that]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=34</guid>
		<description><![CDATA[Bash can seem pretty random and weird at times, but most of what people see as quirks have very logical (if not very good) explanations behind them. This series of posts looks at some of them. How do I simulate pressing Ctrl-C when running this: while true; do echo sleeping; sleep 30; done Are you [...]]]></description>
			<content:encoded><![CDATA[<p>Bash can seem pretty random and weird at times, but most of what people see as quirks have very logical (if not very good) explanations behind them. This series of posts looks at some of them.</p>
<pre>How do I simulate pressing Ctrl-C when running this:
while true; do echo sleeping; sleep 30; done</pre>
<p>Are you thinking &#8220;SIGINT, duh!&#8221;? Hold your horses!</p>
<pre>I tried kill -INT pid, but it doesn't work the same:

Ctrl-C    kills the sleep and the loop
SIGINTing the shell does nothing
SIGINTing sleep makes the loop continue with the next iteration

HOWEVER, if I run the script in the background and <code>kill -INT %1</code>
instead of <code>kill -INT pid</code>, THEN it works :O</pre>
<p>Why does Ctrl-C terminate the loop, while SIGINT doesn&#8217;t?</p>
<pre>Additionally, if I run the same loop with ping or top instead of sleep,
Ctrl-C doesn't terminate the loop either!</pre>
<p>Yeah. Well&#8230; Yeah&#8230;</p>
<p>This behaviour is due to an often overlooked feature in UNIX: process groups. These are important for getting terminals and shells to work the way they do.</p>
<p>A process group is exactly what it sounds like: a group of processes. They have a leader, which is the process that created it using setsid(2). The leader&#8217;s pid is also the process group id. Child processes are in the same group as their parent by default.</p>
<p>Terminals keep track of the foreground process group (set by the shell using tcsetpgrp(3)). <strong>When receiving a Ctrl-C, they send the SIGINT to the entire foreground group.</strong> This means that all members of the group will receive SIGINT, not just the immediate process.</p>
<p><strong><code>kill -INT %1</code> sends the signal to the job&#8217;s process group, not the backgrounded pid!</strong> This explains why it works like Ctrl-C.</p>
<p>You can do the same thing with <code>kill -INT <strong>-</strong>pgrpid</code>. Since the process group id is the same as the process group leader, you can kill the group by killing the pid with a minus in front.</p>
<p>But why do you have to kill both?</p>
<p>When the shell is interrupted, it will wait for the running command to exit. If this child&#8217;s status indicates it exited abnormally due to that signal, the shell cleans up, removes its signal handler, and kills itself again to trigger the OS default action (abnormal exit). Alternatively, it runs the script&#8217;s signal handler as set with <code>trap</code>, and continues.</p>
<p>If the shell is interrupted and the child&#8217;s status says it exited normally, then Bash assumes the child handled the signal and did something useful, so it continues executing. <strong>Ping and top both trap SIGINT and exit normally</strong>, which is why Ctrl-C doesn&#8217;t kill the loop when calling them.</p>
<p>This also explains why interrupting just the shell does nothing: the child exits normally, so <strong>the shell thinks the child handled the signal, though in reality it was never received.</strong></p>
<p>Finally, <strong>if the shell isn&#8217;t interrupted and a child exits, Bash just carries on</strong> regardless of whether the signal died abnormally or not. This is why interrupting the sleep just continues with the loop.</p>
<p>In case one would like to handle such cases, Bash sets the exit code to <code>128+signal</code> when the process exits abnormally, so interrupting sleep with SIGINT would give the exit code 130 (<code>kill -l</code> lists the signal values).</p>
<p>Bonus problem:</p>
<pre>I have this C app, testpg:
int main() {
    setsid();
    return sleep(10);
}

I run <code>bash -c './testpg'</code> and press Ctrl-C. The app is killed.
Shouldn't testpg be excluded from SIGINT, since it used setsid?</pre>
<p>A quick strace unravels this mystery: with a single command to execute, bash execve&#8217;s it directly &#8212; a little optimization trick. Since the pid is the same and already had its own process group, creating a new one doesn&#8217;t have any effect.</p>
<p>Using a compound command prevents this: <code>bash -c 'true; ./testpg'</code> can&#8217;t be killed with Ctrl-C.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=34</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Why Bash is like that: suid</title>
		<link>http://www.vidarholen.net/contents/blog/?p=30</link>
		<comments>http://www.vidarholen.net/contents/blog/?p=30#comments</comments>
		<pubDate>Tue, 26 Jul 2011 12:39:15 +0000</pubDate>
		<dc:creator>Vidar</dc:creator>
				<category><![CDATA[Advanced Linux-related things]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[shell script]]></category>
		<category><![CDATA[why-bash-is-like-that]]></category>

		<guid isPermaLink="false">http://www.vidarholen.net/contents/blog/?p=30</guid>
		<description><![CDATA[Bash can seem pretty random and weird at times, but most of what people see as quirks have very logical (if not very good) explanations behind them. This series of posts looks at some of them. Why can't bash scripts be SUID? Bash scripts can&#8217;t run with the suid bit set. First of all, Linux [...]]]></description>
			<content:encoded><![CDATA[<p>Bash can seem pretty random and weird at times, but most of what people see as quirks have very logical (if not very good) explanations behind them. This series of posts looks at some of them.</p>
<pre>Why can't bash scripts be SUID?</pre>
<p>Bash scripts can&#8217;t run with the suid bit set. First of all, Linux doesn&#8217;t allow any scripts to be setuid, though some other OS do. Second, bash will detect being run as setuid, and immediately drop the privileges.</p>
<p>This is because shell script security is extremely dependent on the environment, much more so than regular C apps.</p>
<p>Take this script, for example, addmaildomain:</p>
<pre>#!/bin/sh
[[ $1 ]] || { man -P cat $0; exit 1; } 

if grep -q "^$(whoami)\$" /etc/accesslist
then
    echo "$1" &gt; /etc/mail/local-host-names
else
    echo "You don't have permissions to add hostnames"
fi</pre>
<p>The intention is to allow users in /etc/accesslist to run <code>addmaildomain example.com</code> to write new names to local-host-names, the file which defines which domains sendmail should accept mail for.</p>
<p>Let&#8217;s imagine it runs as suid root. What can we do to abuse it?</p>
<p>We can start by setting the path:</p>
<pre>echo "rm -rf /" &gt; ~/hax/grep &amp;&amp; chmod a+x ~/hax/grep
PATH=~/hax addmaildomain</pre>
<p>Now the script will run our grep instead of the system grep, and we have full root access.</p>
<p>Let&#8217;s assume the author was aware of that, had set <code>PATH=/bin:/usr/bin</code> as the first line in the script. What can we do now?</p>
<p>We can override a library used by grep</p>
<pre>gcc -shared -o libc.so.6 myEvilLib.c
LD_LIBRARY_PATH=. addmaildomain</pre>
<p>When grep is invoked, it&#8217;ll link with our library and run our evil code.</p>
<p>Ok, so let&#8217;s say LD_LIBRARY_PATH is closed up.</p>
<p>If the shell is statically linked, we can set LD_TRACE_LOADED_OBJECTS=true. This will cause dynamically linked executables to print out a list of library dependencies and return true. This would cause our grep to always return true, subverting the test. The rest is builtin and wouldn&#8217;t be affected.</p>
<p>Even if the shell is statically compiled, all variables starting with LD_* will typically be stripped by the kernel for suid executables anyways.</p>
<p>There is a delay between the kernel starting the interpretter, and the interpretter opening the file. We can try to race it:</p>
<pre>while true
do
    ln /usr/bin/addmaildomain foo
    nice -n 20 ./foo &amp;
    echo 'rm -rf /' &gt; foo
done</pre>
<p>But let&#8217;s assume the OS uses a /dev/fd/* mechanism for passing a fd, instead of passing the file name.</p>
<p>We can rename the script to confuse the interpretter:</p>
<pre>ln /usr/bin/addmaildomain ./-i
PATH=.
-i</pre>
<p>Now we&#8217;ve created a link, which retains suid, and named it &#8220;-i&#8221;. When running it, the interpretter will run as &#8220;/bin/sh -i&#8221;, giving us an interactive shell.</p>
<p>So let&#8217;s assume we actually had &#8220;#!/bin/sh &#8211;&#8221; to prevent the script from being interpretted as an option.</p>
<p>If we don&#8217;t know how to use the command, it helpfully lists info from the man page for us. We can compile a C app that executes the script with &#8220;$0&#8243; containing &#8220;-P /hax/evil ls&#8221;, and then man will execute our evil program instead of cat.</p>
<p>So let&#8217;s say &#8220;$0&#8243; is quoted. We can still set MANOPT=-H/hax/evil.</p>
<p>Several of these attacks were based on the inclusion of &#8216;man&#8217;. Is this a particularly vulnerable command?</p>
<p>Perhaps a bit, but a whole lot of apps can be affected by the environment in more and less dramatic ways.</p>
<ul>
<li>POSIXLY_CORRECT can make some apps fail or change their output</li>
<li>LANG/LC_ALL can thwart interpretation of output</li>
<li>LC_CTYPE and LC_COLLATE can modify string comparisons</li>
<li>Some apps rely on HOME and USER</li>
<li>Various runtimes have their own paths, like RUBY_PATH, LUA_PATH and PYTHONPATH</li>
<li>Many utilities have variables for adding default options, like RUBYOPT and MANOPT</li>
<li>Tools invoke EDITOR, VISUAL and PAGER under various circumstances</li>
</ul>
<p>So yes, it&#8217;s better not to write suid shell scripts. Sudo is better than you at running commands safely.</p>
<p>Do remember that a script can invoke itself with sudo, if need be, for a simulated suid feel.</p>
<p>So wait, can&#8217;t perl scripts be suid?</p>
<p>They can indeed, but there the interpretter will run as the normal user and detect that the file is suid. It will then run a suid interpretter to deal with it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.vidarholen.net/contents/blog/?feed=rss2&#038;p=30</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
