Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 348416 - sys-apps/openrc: avoidable use of `sleep` at boot time when /proc is already mounted
Summary: sys-apps/openrc: avoidable use of `sleep` at boot time when /proc is already ...
Status: RESOLVED FIXED
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: [OLD] Core system (show other bugs)
Hardware: All Linux
: High normal (vote)
Assignee: OpenRC Team
URL:
Whiteboard:
Keywords:
: 360017 360027 360919 362635 (view as bug list)
Depends on:
Blocks:
 
Reported: 2010-12-11 12:34 UTC by Chris Coleman
Modified: 2011-04-08 19:36 UTC (History)
3 users (show)

See Also:
Package list:
Runtime testing required: ---


Attachments
checkproc.patch (checkproc.patch,1.43 KB, text/plain)
2011-03-24 04:32 UTC, William Hubbs
Details
checkproc.patch (checkproc.patch,1.46 KB, patch)
2011-03-24 13:12 UTC, William Hubbs
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Coleman 2010-12-11 12:34:39 UTC
At boot time, OpenRC checks whether it needs to mount /proc by doing this (in sh/init.sh.Linux.in):

mountproc=true
if [ -e /proc/uptime ]; then
        up="$(cat /proc/uptime)"
        sleep 1
        if [ "$up" = "$(cat /proc/uptime)" ]; then
                eerror "You have cruft in /proc that should be deleted"
        else
                einfo "/proc is already mounted, skipping"
                mountproc=false
        fi
fi

It reads /proc/uptime twice to make sure that /proc contains a real proc filesystem and not just some old files. That's a good way of doing it, but it adds a delay of 1 second to every boot if /proc is already mounted.

I thought of another way that uses /proc/self/environ instead of /proc/uptime:

mountproc=true
if [ -e /proc/self/environ ]; then
	if VAR=1 grep -qz "^VAR=1\$" /proc/self/environ && \
	   VAR=2 grep -qz "^VAR=2\$" /proc/self/environ; then
		einfo "/proc is already mounted, skipping"
		mountproc=false
	else
		eerror "You have cruft in /proc that should be deleted"
	fi
fi
Comment 1 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2010-12-12 07:28:03 UTC
Chris:
- Care to look at some other parts of openrc for more excess sleep?
- What is there is a cruft file at that location that happens to have both of those settings? Use $RANDOM maybe instead?

WilliamH:
This concept looks good to me. Opinions?


Comment 2 Chris Coleman 2010-12-12 11:04:12 UTC
(In reply to comment #1)
> Care to look at some other parts of openrc for more excess sleep?

I might take a look at the other sleeps at some point.

> What if there is a cruft file at that location that happens to have both of
> those settings? Use $RANDOM maybe instead?

It seemed unlikely to me that there would be two variables in /proc/self/environ with the same name, but it can happen if `environ` is modified directly. Or if the file is corrupt.

I did think of using $RANDOM. The probability of the string "VAR=$RANDOM" being in a stale /proc/self/environ seems low, but it could happen.

How about launching a command with nothing in the environment except for the magic variable. Then check that the entire contents of /proc/self/environ is as expected. Or just the first few bytes would do:

mountproc=true
if [ -e /proc/self/environ ]; then
	if env - VAR=1 head -c 5 /proc/self/environ | grep -q VAR=1 && \
	   env - VAR=2 head -c 5 /proc/self/environ | grep -q VAR=2; then
		einfo "/proc is already mounted, skipping"
		mountproc=false
	else
		eerror "You have cruft in /proc that should be deleted"
	fi
fi
Comment 3 SpanKY gentoo-dev 2010-12-12 16:25:01 UTC
the dual grep doesnt gain much i dont think as it isnt like you unset one var and make sure it isnt then in the environ.  this test is supposed to be a sanity check rather a sure fire fix, so a single grep should be sufficient.

_OPENRC_ENV_="a magic string" grep -q '_OPENRC_ENV_=a magic string' /proc/self/environ
Comment 4 Chris Coleman 2010-12-12 16:48:45 UTC
Possibly the dual grep approach is overkill. But, like the /proc/uptime hack, it does verify that /proc is definitely alive. Checking a single magic value would only verify that /proc is probably alive.

Then again, someone would have to be amazingly good at buggering up their system to get the magic string, whatever it may be, into their duff /proc.
Comment 5 SpanKY gentoo-dev 2010-12-12 17:56:54 UTC
the code is pretty much always going to be a trade off.  a single grep is sufficient imo to cover all likely cases.  if you've got a crazy setup which this violates, then fix your setup.
Comment 6 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2010-12-12 20:09:46 UTC
chris: my concern is somebody that does rsync -avP /proc /fakeproc and then has /fakeproc mounted at /proc.

Here's a variable I came up with:
text='VAR=1' ; [ "$(env - $text cat /proc/self/environ)" == "$text" ] ; rc1=$?
text='VAR=2' ; [ "$(env - $text cat /proc/self/environ)" == "$text" ] ; rc2=$?
if [ $rc1 -eq 0 -a $rc2 -eq 0 ]; then
 # /proc is alive
fi
unset text rc1 rc2
Comment 7 Chris Coleman 2010-12-12 21:08:02 UTC
(In reply to comment #6)
> chris: my concern is somebody that does rsync -avP /proc /fakeproc and then has
> /fakeproc mounted at /proc.

I do understand that. Although I was imagining someone tarring up their entire system as a backup, including /proc, and later restoring it, including /proc.

Mike's idea of a magic string would work. With the rsync command you mentioned, rsync's environment would end up in /proc/self/environ. The odds are slim that it would contain "_OPENRC_ENV_=FJv2jFiLyddmPDJhDuP6waxy".

But, personally, I do prefer the two step approach. It's the only way to be absolutely sure that the contents of /proc are not static.

> 
> Here's a variable I came up with:
> text='VAR=1' ; [ "$(env - $text cat /proc/self/environ)" == "$text" ] ; rc1=$?
> text='VAR=2' ; [ "$(env - $text cat /proc/self/environ)" == "$text" ] ; rc2=$?
> if [ $rc1 -eq 0 -a $rc2 -eq 0 ]; then
>  # /proc is alive
> fi
> unset text rc1 rc2
>
 
Yes, that'll do it. And no need to invoke grep. Good call.
Comment 8 SpanKY gentoo-dev 2010-12-12 22:55:40 UTC
`test` uses =, not ==.  do it in a single if statement to avoid the variables.
Comment 9 Chris Coleman 2010-12-12 23:05:07 UTC
(In reply to comment #8)
> `test` uses =, not ==.  do it in a single if statement to avoid the variables.

SpanK'd!
Comment 10 Chris Coleman 2010-12-12 23:25:54 UTC
Incidentally, is the use of [[ acceptable in openrc?
Comment 11 William Hubbs gentoo-dev 2010-12-13 00:28:18 UTC
(In reply to comment #10)
> Incidentally, is the use of [[ acceptable in openrc?

As far as I know, it isn't, because that breaks openrc if the shell is not bash.
Comment 12 Chris Coleman 2010-12-13 00:55:29 UTC
(In reply to comment #11)
> (In reply to comment #10)
> > Incidentally, is the use of [[ acceptable in openrc?
> 
> As far as I know, it isn't, because that breaks openrc if the shell is not
> bash.
> 

Which other shells should be supported?
Comment 13 Jory A. Pratt gentoo-dev 2010-12-13 00:58:08 UTC
(In reply to comment #12)
> (In reply to comment #11)
> > (In reply to comment #10)
> > > Incidentally, is the use of [[ acceptable in openrc?
> > 
> > As far as I know, it isn't, because that breaks openrc if the shell is not
> > bash.
> > 
> 
> Which other shells should be supported?
> 
any posix compliant shell will be supported. There will be no exceptions.
Comment 14 Chris Coleman 2010-12-13 01:31:55 UTC
(In reply to comment #13)
> any posix compliant shell will be supported. There will be no exceptions.
> 

That's cool. Are you the lead developer?
Comment 15 William Hubbs gentoo-dev 2010-12-13 03:34:18 UTC
(In reply to comment #14)
> (In reply to comment #13)
> > any posix compliant shell will be supported. There will be no exceptions.
> > 
> That's cool. Are you the lead developer?

I'm not Jory, but I think I can answer this. Jory, please correct me if I am wrong.

We are a subproject of the base system project, and the lead of base system is Mike. As far as I know, openrc doesn't have a separate lead.
Comment 16 Jory A. Pratt gentoo-dev 2010-12-13 03:44:00 UTC
(In reply to comment #15)
> (In reply to comment #14)
> > (In reply to comment #13)
> > > any posix compliant shell will be supported. There will be no exceptions.
> > > 
> > That's cool. Are you the lead developer?
> 
> I'm not Jory, but I think I can answer this. Jory, please correct me if I am
> wrong.
> 
> We are a subproject of the base system project, and the lead of base system is
> Mike. As far as I know, openrc doesn't have a separate lead.
> 
William this is correct, I let Mike run the lead as we did move openrc under baselayout, I just picked up the code and have had very little time to work on it at moment due to schooling. This will change in a few weeks and will be moving openrc in a much cleaner forward march.
Comment 17 SpanKY gentoo-dev 2010-12-13 07:44:43 UTC
we aim for POSIX shell-ish.  we require "local" which isnt in POSIX.
Comment 18 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2011-01-17 22:57:23 UTC
I'm wondering if we can remove all forks entirely and still keep the same result.

If we can rely on the minor fault counter always changing between entries to kernelspace and userspace, then I propose this check:
====
f=/proc/self/stat
v=a ; exec 9<$f ; read $v <&9 ; exec 9>&-
v=b ; exec 9<$f ; read $v <&9 ; exec 9>&-
[ "$a" = "$b" ] ; echo $?
====
The minor fault counter increases by at least 2 between the runs.
It's pure POSIX sh, has no execs, and is faster than the grep call.
Comment 19 SpanKY gentoo-dev 2011-01-17 23:08:00 UTC
you dont need the "v" variable there, and the stat file provides times with different units.  so fault counts shouldnt be a blocking issue.
Comment 20 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2011-01-18 00:02:58 UTC
vapier:
Err, I don't care about the actual counts. Just that the file changes.

All this bug needs is ANY file in /proc that:
- changes between sequential reads
- is world-readable (not hardened kernel blocked)
- ideally is on a single line (means the entire check is doable without any exec/fork).

The v variable was just for ease of showing the code.
If the minor faults number in /proc/$PID/stat is always going to change, then it fills the above requirements for detecting a live procfs.

/proc/uptime doesn't work with the sleep statement dropped because it only changes every 10ms approximately (the resolution of times in it).

Local timing:
The original sleep code takes ~1010ms.
The grep of environ takes 2.2-2.5ms (mostly fork overhead)
My check of /proc/self/stat takes 1.1-1.4ms.
Comment 21 SpanKY gentoo-dev 2011-01-18 00:50:17 UTC
you missed the point of my comment.  let's skip the crap and jump to the end: your proposal looks fine.  feel free to convert to that.
Comment 22 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2011-01-18 01:29:58 UTC
Fix committed.
Comment 23 Chris Coleman 2011-01-18 02:52:26 UTC
Thanks, Robin. Thanks, Mike. You improved my already good idea.
Comment 24 SpanKY gentoo-dev 2011-03-22 22:49:58 UTC
*** Bug 360017 has been marked as a duplicate of this bug. ***
Comment 25 Chris Coleman 2011-03-24 01:02:12 UTC
(In reply to comment #18)
> If we can rely on the minor fault counter always changing between entries to
> kernelspace and userspace, then I propose this check:
> ====
> f=/proc/self/stat
> v=a ; exec 9<$f ; read $v <&9 ; exec 9>&-
> v=b ; exec 9<$f ; read $v <&9 ; exec 9>&-
> [ "$a" = "$b" ] ; echo $?
> ====
> The minor fault counter increases by at least 2 between the runs.
> It's pure POSIX sh, has no execs, and is faster than the grep call.

I hate to poke this bug again, but the above method isn't working on my system. I was using my patch until openrc 0.8.0. Now I'm getting "You have cruft...".

My processor is an Intel Core i7 920. It has 4 cores and hyperthreading.

$ f=/proc/self/stat
$ v=a ; exec 9<$f ; read $v <&9 ; exec 9>&-; v=b ; exec 9<$f ; read $v <&9 ; exec 9>&-; [ "$a" = "$b" ] && echo 'a=b' || echo 'a!=b'
a=b

sleep first:
$ sleep 1; v=a ; exec 9<$f ; read $v <&9 ; exec 9>&-; v=b ; exec 9<$f ; read $v <&9 ; exec 9>&-; [ "$a" = "$b" ] && echo 'a=b' || echo 'a!=b'
a!=b

sleep between:
$ v=a ; exec 9<$f ; read $v <&9 ; exec 9>&-; sleep 1; v=b ; exec 9<$f ; read $v <&9 ; exec 9>&-; [ "$a" = "$b" ] && echo 'a=b' || echo 'a!=b'
a!=b

What is the minor fault counter?
Comment 26 SpanKY gentoo-dev 2011-03-24 01:24:07 UTC
there is already an open bug on the topic
Comment 27 William Hubbs gentoo-dev 2011-03-24 01:39:37 UTC
Re-opening per robbat2,

We need to find a better solution for this since it caused bug #360027.
Comment 28 William Hubbs gentoo-dev 2011-03-24 01:43:50 UTC
*** Bug 360027 has been marked as a duplicate of this bug. ***
Comment 29 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2011-03-24 01:50:08 UTC
(In reply to comment #25)
> My processor is an Intel Core i7 920. It has 4 cores and hyperthreading.
(snip testcase)

Your testcase gives me different results:
no sleep
a!=b
sleep first:
a=b
sleep between:
a!=b

> What is the minor fault counter?
The fault counter basically counts when things get moved to and from memory.

So we need to go back to my original requirements in comment 20.
I would like this to be done WITHOUT any call to sleep.
Comment 30 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2011-03-24 02:22:02 UTC
Ok, I think the best we can do is go back to /proc/self/environ. 
====
text="VAR=1"
[ "$(env - $text cat /proc/self/environ)" == "$text" ] ; rc1=$?
text="VAR=2"
[ "$(env - $text cat /proc/self/environ)" == "$text" ] ; rc2=$?
if [ $rc1 -eq 0 -a $rc2 -eq 0 ]; then
     echo '# /proc is alive'
else
     echo '# /proc is dead'
fi
====
Any final complaints about this? Yes, it takes 2-14ms, and not the 1ms of the stat variant, but that's still better than the 1 second we had before.
Comment 31 SpanKY gentoo-dev 2011-03-24 02:32:57 UTC
compare the two results to each other and you wont need the env step.
[ "$(VAR=a cat /proc/self/environ)" = "$(VAR=b cat /proc/self/environ)" ]

make sure you use = and not ==
Comment 32 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2011-03-24 02:43:04 UTC
(In reply to comment #31)
> compare the two results to each other and you wont need the env step.
> [ "$(VAR=a cat /proc/self/environ)" = "$(VAR=b cat /proc/self/environ)" ]
> 
> make sure you use = and not ==
======
[ "$(VAR=a cat /proc/self/environ)" != "$(VAR=b cat /proc/self/environ)" ]
if [ $? -eq 0 ]; then
     echo '# /proc is alive'
else
     echo '# /proc is dead'
fi
======

8ms, and I think that should work, other people want to test it please? We should also test for existence of /proc/self/environ before we read it.
Comment 33 Chris Coleman 2011-03-24 02:54:15 UTC
(In reply to comment #32)
> (In reply to comment #31)
> > compare the two results to each other and you wont need the env step.
> > [ "$(VAR=a cat /proc/self/environ)" = "$(VAR=b cat /proc/self/environ)" ]
> > 
> > make sure you use = and not ==
> ======
> [ "$(VAR=a cat /proc/self/environ)" != "$(VAR=b cat /proc/self/environ)" ]
> if [ $? -eq 0 ]; then
>      echo '# /proc is alive'
> else
>      echo '# /proc is dead'
> fi
> ======
> 
> 8ms, and I think that should work, other people want to test it please? We
> should also test for existence of /proc/self/environ before we read it.
Comment 34 William Hubbs gentoo-dev 2011-03-24 04:32:23 UTC
Created attachment 267045 [details]
checkproc.patch

This patch is based on comment #31.

What do the rest of you think?
Comment 35 Chris Coleman 2011-03-24 04:54:54 UTC
(In reply to comment #34)
> Created attachment 267045 [details]
> checkproc.patch
> 
> This patch is based on comment #31.
> 
> What do the rest of you think?

Thanks, William. I'll test it tomorrow. I'm too tired now.

Sorry about my previous post. I clicked accidentally.
Comment 36 Xake 2011-03-24 08:54:05 UTC
Comment on attachment 267045 [details]
checkproc.patch

>+	if [ "$(VAR=a cat $f)" = "$(VAR=b cat $f)" ]; then

Why not just:
	if [ "$(VAR=a cat $f)" = "$(cat $f)" ]; then

It may not have a big impact, but lets not do unnecessary memory operations, shall we?;)
Comment 37 William Hubbs gentoo-dev 2011-03-24 13:12:02 UTC
Created attachment 267081 [details, diff]
checkproc.patch

This patch is modified according to the suggestion in comment #36.

It appears to work for me; what do the rest of you think?
Comment 38 SpanKY gentoo-dev 2011-03-24 13:54:15 UTC
Comment on attachment 267081 [details, diff]
checkproc.patch

on the off chance that the file in question does have VAR=a, that version fails.  this is the same reason people didnt want to use my magic string idea.

just go with the previous patch you posted.
Comment 39 Chris Coleman 2011-03-24 19:35:25 UTC
(In reply to comment #34)
> Created attachment 267045 [details]
> checkproc.patch
> 
> This patch is based on comment #31.
> 
> What do the rest of you think?

This patch works for me.
Comment 40 William Hubbs gentoo-dev 2011-03-25 00:22:07 UTC
This is now in git, commit 1d63e85.

Thanks for the report.
Comment 41 SpanKY gentoo-dev 2011-03-28 15:42:34 UTC
*** Bug 360919 has been marked as a duplicate of this bug. ***
Comment 42 Robin Johnson archtester Gentoo Infrastructure gentoo-dev Security 2011-04-08 19:36:54 UTC
*** Bug 362635 has been marked as a duplicate of this bug. ***