15

The problem was resolved by upgrading the C library.


I would like to use the syscall getrandom (http://man7.org/linux/man-pages/man2/getrandom.2.html)

gcc-5 -std=c11 test.c

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <linux/random.h>
#include <sys/syscall.h>

int main(void)
{
        void *buf = NULL;
        size_t l = 5;
        unsigned int o = 1;
        int r = syscall(SYS_getrandom, buf, l, o);
        return 0;
}

or

 int main(void)
    {
            void *buf = NULL;
            size_t l = 5;
            unsigned int o = 1;
            int r = getrandom(buf, l, o);
            return 0;
    }

Anyway when I try to compile it with gcc-5:

test.c: In function ‘main’:
test.c:14:17: warning: implicit declaration of function ‘getrandom’ [-Wimplicit-function-declaration]
         int r = getrandom(buf, l, o);
                 ^
/tmp/ccqFdJAJ.o: In function `main':
test.c:(.text+0x36): undefined reference to `getrandom'
collect2: error: ld returned 1 exit status

I am using Ubuntu 14.04, what can I do to use getrandom? As it is a "new" syscall, how can I use it?

edit:

uname -r
-> 4.0.3-040003-generic #201505131441 SMP Wed May 13 13:43:16 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

when I replace r by int r = syscall(SYS_getrandom, buf, l, o); or r = getrandom(buf, l, o) it is the same..

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
anothertest
  • 979
  • 1
  • 9
  • 24
  • 1
    Referring your edit: Add the prototype to `syscall()` when using it! It's in `` The `SYS_getrandom` should be available also then. – alk Jun 12 '15 at 12:27
  • Why don't you use [random(4)](http://man7.org/linux/man-pages/man4/random.4.html) i.e. read some bytes from `/dev/random` ? – Basile Starynkevitch Jun 12 '15 at 13:20
  • No, but you'll need a much newer kernel .... – Basile Starynkevitch Jun 12 '15 at 13:29
  • 1
    Did you try also the `syscall` version with a 4.0 kernel? – Basile Starynkevitch Jun 12 '15 at 13:37
  • Did you also update the kernel headers to suite the kernel in use? – alk Jun 12 '15 at 14:01
  • 3
    Please do not destroy a question, especially not after you've had answers and received help from multiple people. I've reinstated the final 'full' version, and added the resolution at the top. This is fairer to those who helped you. – Jonathan Leffler Jun 12 '15 at 22:09
  • Now in 2020, there is still an issue. If you compile some application with a syscall with -std=c98 there is no warning and if you compile the same code with std=c11 or c17 or c18 for that matter, the warning shows up. So it has less to do with the kernel version, I think. More with some potentially superfluous c-standard version checks in some header files. (I used clang on debian bullseye with these findings, btw.) – BitTickler Aug 30 '20 at 20:17

5 Answers5

12

getrandom and getentropy were added to glibc in version 2.25. As of July 2017, most Linux distributions have not yet updated to this version (e.g. Debian's most recent release, which just came out, has 2.24) but they should soon.

Here is how to use the glibc wrappers if available and fall back to the raw system call if not:

#define _GNU_SOURCE 1
#include <sys/types.h>
#include <unistd.h>

#if defined __GLIBC__ && defined __linux__

# if __GLIBC__ > 2 || __GLIBC_MINOR__ > 24
#  include <sys/random.h>

int
my_getentropy(void *buf, size_t buflen)
{
    return getentropy(buf, buflen);
}

# else /* older glibc */
#  include <sys/syscall.h>
#  include <errno.h>

int
my_getentropy(void *buf, size_t buflen)
{
    if (buflen > 256) {
        errno = EIO;
        return -1;
    }
    return syscall(SYS_getrandom, buf, buflen, 0);
}

# endif

#else /* not linux or not glibc */
#error "Need implementation for whatever operating system this is"

#endif

(As pointed out in other answers, it is also necessary to ensure you have kernel 3.17 or newer. Both the above versions of my_getentropy will fail and set errno to ENOSYS if run on an older kernel.)

zwol
  • 135,547
  • 38
  • 252
  • 361
11

So, it seems that getrandom is not a function, just a syscall.

Hence this is needed:

/* Note that this define is required for syscalls to work. */
#define _GNU_SOURCE

#include <unistd.h>
#include <sys/syscall.h>
#include <linux/random.h>

int main(int arg, char *argv[])
{
        void *buf = NULL;
        size_t l = 5;
        unsigned int o = 1;
        int r = syscall(SYS_getrandom, buf, l, o);
        return 0;
}
Florian Margaine
  • 58,730
  • 15
  • 91
  • 116
  • 1
    Should 'buf' be initialized? I would think the `syscall()` will seg fault because your asking it to write 5 bytes to address zero. – Jamie Jun 03 '16 at 01:47
6

The getrandom() syscall was introduced in the linux kernel 3.17. Ubuntu 14.04 gets shipped with kernel 3.13, so you have to update to a more recent kernel to get the syscall.

To get .deb packages of the linux kernel for Ubuntu, have a look at kernel.ubuntu.com. This problem was also discussed at askubuntu.com.

Community
  • 1
  • 1
lkamp
  • 193
  • 1
  • 10
  • 1
    @anothertest: You want to update libc as well. Or try `int r = syscall(SYS_getrandom, buf, l, o);` instead. – alk Jun 12 '15 at 12:05
3

I think with your program you will get a segmentation fault. The following code should work:

#include <iostream>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/random.h>

int main() {
  unsigned long int s;
  syscall(SYS_getrandom, &s, sizeof(unsigned long int), 0);
  std::cout << "The seed is: " << s << "." << std::endl;
}
Dominik Schrempf
  • 827
  • 8
  • 14
1

Here, I compiled some code shown before, and corrected the bugs, included is my output from gcc -v for comparison.

// $ gcc -v
// Using built-in specs.
// COLLECT_GCC=gcc
// COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
// Target: x86_64-linux-gnu
// Configured with: ../src/configure -v --with-pkgversion='Ubuntu
//   5.4.0-6ubuntu1~16.04.9' --with-bugurl=file:///usr/share/doc/gcc-5/README.Bugs
//   --enable-languages=c,ada,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr
//   --program-suffix=-5 --enable-shared --enable-linker-build-id
//   --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix
//   --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu
//   --enable-libstdcxx-debug --enable-libstdcxx-time=yes
//   --with-default-libstdcxx-abi=new --enable-gnu-unique-object
//   --disable-vtable-verify --enable-libmpx --enable-plugin --with-system-zlib
//   --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo
//   --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-5-amd64/jre --enable-java-home
//   --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-5-amd64
//   --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-5-amd64
//   --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar
//   --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686
//   --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib
//   --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu
//   --host=x86_64-linux-gnu --target=x86_64-linux-gnu
// Thread model: posix
// gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)

//#define _GNU_SOURCE

#include <stdio.h>

#include <unistd.h>
#include <sys/syscall.h>
#include <linux/random.h>

int main (int arg, char **argv)
{
  size_t length = 5;
  unsigned char buf[length];
  int r = syscall(SYS_getrandom, buf, length, 0);

  if (r != 0)
  {
    int iIter;
    printf ("random %zu bytes = ",length);
    for (iIter = 0 ; iIter < length-1 ; iIter++)
    {
      printf ("%02x:", buf[iIter]);
    }
    printf ("%02x\n", buf[iIter]);
  }
  else
  {
    perror ("syscall (SYS_getrandom, ...)");
  }
  return 0;
}