Because RAND_MAX is equal to INT_MAX, the following expression
contained in the manpage for rand(3) is slightly incorrect.
j=1+(int) (10.0*rand()/(RAND_MAX+1.0));
The correct expression should use parentheses to group the division
before the multiplication, thus yielding:
j=1+(int) (10.0*(rand()/(RAND_MAX+1.0)));
This is not an error where 10.0 is a floating point number, however
where 10.0 is replaced with an integer, this will cause the expression
to always evaluate to 1. (The addition of two parentheses would make
this bug a lot more difficult to make.)
Regarding man page documentation of the problem of short sleeps
for setiteimer(2)...
> > -- pointers to those threads
>
> http://bugzilla.kernel.org/show_bug.cgi?id=4569
> http://lkml.org/lkml/2005/4/29/163
>
> > -- indications of which kernel versions show this bahaviour
>
> AFAIK, all versions as far as x86 is concerned.
> Dunno if it is hardware specific.
>
> > -- a (short) test program to demonstrate it, if you have one.
>
> See the bugzilla bug's attachments
Sorry for the long delay in following this up, but I've got to
it now. I tweaked your suggestions slightly:
{{
Timers will never expire before the requested time,
-instead expiring some short, constant time afterwards, dependent
-on the system timer resolution (currently 10ms).
+but may expire some (short) time afterwards, which depends
+on the system timer resolution and on the system load.
+Upon expiration, a signal will be generated and the timer reset.
+If the timer expires while the process is active (always true for
+On certain systems (including x86), the Linux kernel has a bug which will
+produce premature timer expirations of up to one jiffy under some
+circumstances.
}}
Thanks for this bug reporet,
Nishanth: if and when your changes are accepted, and the problem
is thus fixed, could you please send me a notification of that
fact, and I can then further amend the manual pages.
Cheers,
Michael
/* itimer_short_interval_bug.c
June 2005
In current Linux kernels, an interval timer set using setitimer()
can sometimes sleep *less* than the specified interval.
This program demonstrates the behaviour by looping through all
itimer values from 1 microsecond upwards, in one microsecond steps.
*/
/* Adapted from a program by Olivier Croquette, June 2005 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
typedef unsigned long long int u_time_t; /* in microsecs */
static int handler_flag;
/* return time as a number of microsecs */
static u_time_t
gettime(void )
{
struct timeval tv;
if ( gettimeofday(&tv, NULL) == -1) {
perror("gettimeofday()");
return 0;
}
return (tv.tv_usec + tv.tv_sec * 1000000LL);
}
static void
handler (int sig, siginfo_t *siginfo, void *context)
{
handler_flag++;
return ;
}
/* Sleep for 'time' microsecs. */
static int
isleep(u_time_t time)
{
struct itimerval newtv;
sigset_t sigset;
struct sigaction sigact;
if (time == 0)
return 0;
/* block SIGALRM */
sigemptyset (&sigset);
sigaddset (&sigset, SIGALRM);
sigprocmask (SIG_BLOCK, &sigset, NULL);
/* set up our handler */
sigact.sa_sigaction = handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_SIGINFO;
sigaction (SIGALRM, &sigact, NULL);
newtv.it_interval.tv_sec = 0;
newtv.it_interval.tv_usec = 0;
newtv.it_value.tv_sec = time / 1000000;
newtv.it_value.tv_usec = time % 1000000;
if (setitimer(ITIMER_REAL,&newtv,NULL) == -1) {
perror("setitimer(set)");
return 1;
}
sigemptyset (&sigset);
sigsuspend (&sigset);
return 0;
}
int
main(int argc, char *argv[]) {
u_time_t wait;
int loop, numLoops;
u_time_t t1, t2;
u_time_t actual;
long long minDiff, maxDiff, totDiff, diff;
int numFail = 0;
if (argc != 2) {
fprintf(stderr, "Usage: %s num-loops\n", argv[0]);
exit(EXIT_FAILURE);
} /* if */
numLoops = atoi(argv[1]);
setbuf(stdout, NULL);
for (wait = 1; ; wait++) {
maxDiff = 0;
numFail = 0;
totDiff = 0;
minDiff = -wait;
if (wait % 10000 == 0)
printf("%llu\n", wait);
for (loop = 0; loop < numLoops; loop++) {
t1 = gettime();
handler_flag = 0;
isleep(wait);
if ( handler_flag != 1 )
printf("Problem with the handler flag (%d)!\n", handler_flag);
t2 = gettime();
actual = t2 - t1;
if ( actual < wait ) {
diff = actual - wait;
if (diff < maxDiff)
maxDiff = diff;
if (diff > minDiff)
minDiff = diff;
totDiff += diff;
numFail++;
} /* if */
} /* for */
if (numFail > 0)
printf("%llu: %3d fail (%4lld %4lld; avg=%6.1f)\n",
wait, numFail, minDiff, maxDiff,
(double) totDiff / numFail);
} /* for */
return 0;
} /* main */
> The question came up whether execve of a suid binary while being ptraced
> would fail or ignore the suid part. The answer today seems to be the
> latter:
>
> E.g. (in 2.6.11) security/dummy.c:
>
> static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int
> unsafe)
> {
> if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
> if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) &&
> !capable(CAP_SETUID)) {
> bprm->e_uid = current->uid;
> bprm->e_gid = current->gid;
> }
> }
> }
>
> and fs/exec.c:
>
> void compute_creds(struct linux_binprm *bprm) {
> int unsafe;
>
> unsafe = unsafe_exec(current);
> security_bprm_apply_creds(bprm, unsafe);
> }
>
> static inline int unsafe_exec(struct task_struct *p) {
> int unsafe = 0;
> if (p->ptrace & PT_PTRACED) {
> if (p->ptrace & PT_PTRACE_CAP)
> unsafe |= LSM_UNSAFE_PTRACE_CAP;
> else
> unsafe |= LSM_UNSAFE_PTRACE;
> }
> return unsafe;
> }
>
> That is: if the process that calls execve() is being traced,
> the LSM_UNSAFE_PTRACE bit is et in unsafe and security_bprm_apply_creds()
> will make sure the suid/sgid bits are ignored.
>
> ---
>
> In my man page I do not read anything like that. It says
>
> EPERM The process is being traced, the user is not the superuser and
> the file has an SUID or SGID bit set.
> and
>
> If the current program is being ptraced, a SIGTRAP is sent to it after
> a successful execve().
>
> If the set-uid bit is set on the program file pointed to by filename
> the effective user ID of the calling process is changed to that of the
> owner of the program file.
>
> So, maybe this sentence should be amended to read
>
> If the set-uid bit is set on the program file pointed to by filename
> and the current process is not being ptraced, the effective user ID
> of the calling process is changed to ...
I changed your "current" to "calling" (to be consistent with the
rest of the page), but otherwise applied as you suggest.
The revision will appear in man-pages-2.03, which I can release
any time now. Are you avialable to do an upload tomorrow?