texlive is actually substitutable

  • Open
  • quality assurance status badge
Details
4 participants
  • Bengt Richter
  • Leo Famulari
  • Ludovic Courtès
  • Maxim Cournoyer
Owner
unassigned
Submitted by
Ludovic Courtès
Severity
important

Debbugs page

Ludovic Courtès wrote on 29 May 2020 17:15
texlive-texmf is actually subtitutable
(address . bug-guix@gnu.org)
878sha3h7n.fsf@inria.fr
Strangely, ‘texlive-texmf’ (the big one) is substitutable:

Toggle snippet (21 lines)
$ guix describe
Generacio 145 May 25 2020 00:37:58 (nuna)
guix 9744cc7
repository URL: https://git.savannah.gnu.org/git/guix.git
branch: master
commit: 9744cc7b4636fafb772c94adb8f05961b5b39f16
$ guix environment --ad-hoc texlive -- texdoc biblatex
2.6 MB will be downloaded:
/gnu/store/7ji4l3szj68b0r5w10bvvdx1vy6nhz5p-subversion-1.10.6
downloading from https://ci.guix.gnu.org/nar/lzip/7ji4l3szj68b0r5w10bvvdx1vy6nhz5p-subversion-1.10.6 ...
subversion-1.10.6 2.5MiB 7.2MiB/s 00:00 [##################] 100.0%

La jena derivo estos konstruata:
/gnu/store/55yx02hr0dz47px1aj0j14xll3bsrmml-texlive-texmf-20190410.drv
2,845.8 MB will be downloaded:
/gnu/store/nm6w84c9zj3yiylal3dk1sqzxq11sjzw-texlive-20190410-texmf.tar.xz
/gnu/store/xpkl70g3bls935h1zdlq7sn2j6rccp3k-texlive-20190410
downloading from https://ci.guix.gnu.org/nar/lzip/z4xvgiliw5baf1pr4z03c7n2hw3bm5x5-texlive-texmf-20190410 ...
texlive-texmf-20190410 2.61GiB

The info suggests it won’t be substituted, but it’s eventually
substituted. I wonder why, because the .drv has:

("allowSubstitutes","0")

and the daemon has:

bool substitutesAllowed(const Derivation & drv)
{
return get(drv.env, "allowSubstitutes", "1") == "1";
}

and:

if (settings.useSubstitutes && substitutesAllowed(drv))
foreach (PathSet::iterator, i, invalidOutputs)
addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));

Thoughts?

Ludo’.
Leo Famulari wrote on 29 May 2020 20:04
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 41602@debbugs.gnu.org)
20200529180411.GB3754@jasmine.lan
On Fri, May 29, 2020 at 05:15:40PM +0200, Ludovic Courtès wrote:
Toggle quote (20 lines)
> The info suggests it won’t be substituted, but it’s eventually
> substituted. I wonder why, because the .drv has:
>
> ("allowSubstitutes","0")
>
> and the daemon has:
>
> bool substitutesAllowed(const Derivation & drv)
> {
> return get(drv.env, "allowSubstitutes", "1") == "1";
> }
>
> and:
>
> if (settings.useSubstitutes && substitutesAllowed(drv))
> foreach (PathSet::iterator, i, invalidOutputs)
> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>
> Thoughts?

I wonder if the content-addressed fallbacks take a different code path
that doesn't respect "allowSubstitutes"?
Bengt Richter wrote on 30 May 2020 06:06
(name . Ludovic Courtès)(address . ludo@gnu.org)(address . 41602@debbugs.gnu.org)
20200530040609.GA2810@LionPure
On +2020-05-29 17:15:40 +0200, Ludovic Courtès wrote:
Toggle quote (44 lines)
> Strangely, ‘texlive-texmf’ (the big one) is substitutable:
>
> --8<---------------cut here---------------start------------->8---
> $ guix describe
> Generacio 145 May 25 2020 00:37:58 (nuna)
> guix 9744cc7
> repository URL: https://git.savannah.gnu.org/git/guix.git
> branch: master
> commit: 9744cc7b4636fafb772c94adb8f05961b5b39f16
> $ guix environment --ad-hoc texlive -- texdoc biblatex
> 2.6 MB will be downloaded:
> /gnu/store/7ji4l3szj68b0r5w10bvvdx1vy6nhz5p-subversion-1.10.6
> downloading from https://ci.guix.gnu.org/nar/lzip/7ji4l3szj68b0r5w10bvvdx1vy6nhz5p-subversion-1.10.6 ...
> subversion-1.10.6 2.5MiB 7.2MiB/s 00:00 [##################] 100.0%
>
> La jena derivo estos konstruata:
> /gnu/store/55yx02hr0dz47px1aj0j14xll3bsrmml-texlive-texmf-20190410.drv
> 2,845.8 MB will be downloaded:
> /gnu/store/nm6w84c9zj3yiylal3dk1sqzxq11sjzw-texlive-20190410-texmf.tar.xz
> /gnu/store/xpkl70g3bls935h1zdlq7sn2j6rccp3k-texlive-20190410
> downloading from https://ci.guix.gnu.org/nar/lzip/z4xvgiliw5baf1pr4z03c7n2hw3bm5x5-texlive-texmf-20190410 ...
> texlive-texmf-20190410 2.61GiB
> --8<---------------cut here---------------end--------------->8---
>
> The info suggests it won’t be substituted, but it’s eventually
> substituted. I wonder why, because the .drv has:
>
> ("allowSubstitutes","0")
>
> and the daemon has:
>
> bool substitutesAllowed(const Derivation & drv)
> {
> return get(drv.env, "allowSubstitutes", "1") == "1";
> }
>
> and:
>
> if (settings.useSubstitutes && substitutesAllowed(drv))
> foreach (PathSet::iterator, i, invalidOutputs)
> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>
> Thoughts?

This is the kind of "wonder why" that makes me wonder about trojan horse bug fixes
as described in [1], which is a really interesting and scary read, especially since [1]
could very conceivably be an example of what it itself is talking about (though they
don't sound malicious, so I can hope trusting okular to display it was not giving
them a pdf or image parser to exploit with malice).

Anyway, please note that the "pdf" file starts with these lines:

Toggle snippet (5 lines)
# I'm a shell script :-) so please make me executable!
# No shebang but I work equally well with Bash, Dash and Zsh
# The script embeds link-grammar, a x86-64 ELF so it requires to be run on a x86-64 linux system

What looks like the beginning of a normal pdf file starts at line 30 counting from 1 as first line.
okular will display the original as if it were pdf (bug??) though "file" just sees it as "data."

Trim off the first 29 lines and file sees it as pdf, and pdfinfo will find its way too.

Idk, you might want at least to cut out the first 29 lines before looking at it with e.g. okular,
(which I trustingly used to open the file): note that okular got past the 29-line script part, (which
is a bit promiscuous for my taste), and displayed the pdf.

It was really interesting, esp the sections around

Toggle snippet (5 lines)
3
Deniable Backdoors Using Compiler Bugs
by Scott Bauer, Pascal Cuoq, and John Regehr

Maybe you can view it in a sandbox :) But don't blame me if you don't.
YOU WERE WARNED.

So read it -- and wonder what might come with a mysterious substitute ;-P


Toggle quote (6 lines)
>
> Ludo’.
>
>
>

--
Regards,
Bengt Richter
Ludovic Courtès wrote on 30 May 2020 16:07
(name . Leo Famulari)(address . leo@famulari.name)(address . 41602@debbugs.gnu.org)
87sgfhtt1f.fsf@gnu.org
Hi,

Leo Famulari <leo@famulari.name> skribis:

Toggle quote (24 lines)
> On Fri, May 29, 2020 at 05:15:40PM +0200, Ludovic Courtès wrote:
>> The info suggests it won’t be substituted, but it’s eventually
>> substituted. I wonder why, because the .drv has:
>>
>> ("allowSubstitutes","0")
>>
>> and the daemon has:
>>
>> bool substitutesAllowed(const Derivation & drv)
>> {
>> return get(drv.env, "allowSubstitutes", "1") == "1";
>> }
>>
>> and:
>>
>> if (settings.useSubstitutes && substitutesAllowed(drv))
>> foreach (PathSet::iterator, i, invalidOutputs)
>> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>>
>> Thoughts?
>
> I wonder if the content-addressed fallbacks take a different code path
> that doesn't respect "allowSubstitutes"?

It does, but this texlive-texmf.drv is not a fixed-output derivation.

Ludo’.
Leo Famulari wrote on 30 May 2020 19:10
(no subject)
(address . control@debbugs.gnu.org)
20200530171007.GA25305@jasmine.lan
severity 41602 important
Maxim Cournoyer wrote on 3 Apr 2024 04:08
control message for bug #41602
(address . control@debbugs.gnu.org)
878r1vw637.fsf@gmail.com
retitle 41602 texlive is actually substitutable
quit
Maxim Cournoyer wrote on 3 Apr 2024 04:09
Re: bug#41602: texlive-texmf is actually subtitutable
(name . Ludovic Courtès)(address . ludo@gnu.org)
874jcjw621.fsf@gmail.com
Hello,

Ludovic Courtès <ludo@gnu.org> writes:

Toggle quote (30 lines)
> Hi,
>
> Leo Famulari <leo@famulari.name> skribis:
>
>> On Fri, May 29, 2020 at 05:15:40PM +0200, Ludovic Courtès wrote:
>>> The info suggests it won’t be substituted, but it’s eventually
>>> substituted. I wonder why, because the .drv has:
>>>
>>> ("allowSubstitutes","0")
>>>
>>> and the daemon has:
>>>
>>> bool substitutesAllowed(const Derivation & drv)
>>> {
>>> return get(drv.env, "allowSubstitutes", "1") == "1";
>>> }
>>>
>>> and:
>>>
>>> if (settings.useSubstitutes && substitutesAllowed(drv))
>>> foreach (PathSet::iterator, i, invalidOutputs)
>>> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>>>
>>> Thoughts?
>>
>> I wonder if the content-addressed fallbacks take a different code path
>> that doesn't respect "allowSubstitutes"?
>
> It does, but this texlive-texmf.drv is not a fixed-output derivation.

I just verified; this still happens:

Toggle snippet (19 lines)
$ guix build texlive -n
substitute: mise à jour des substituts depuis « https://ci.guix.gnu.org »... 100.0 %
La dérivation suivante serait compilée :
/gnu/store/ym96pipknrh6khzc3ws8ychiy6224y61-texlivetexmf-20230313.drv
3 880,6 Mo seraient téléchargés :
/gnu/store/rzczwmmkvpkahy0mgpahav0yx37ci61b-texlive-20230313-texmf.tar.xz
/gnu/store/bcc5071mvprhp4yj1jimlhyyi499d2ba-texlivebin-20230313
/gnu/store/bd4mzanvv7q2plm2b6zld8cz3fy0x34a-texlive-20230313
maxim@hurd ~/src/guix [env]$ guix build /gnu/store/bd4mzanvv7q2plm2b6zld8cz3fy0x34a-texlive-20230313
substitute: mise à jour des substituts depuis « https://ci.guix.gnu.org »... 100.0 %
substitution de /gnu/store/bcc5071mvprhp4yj1jimlhyyi499d2ba-texlivebin-20230313...
téléchargement depuis https://ci.guix.gnu.org/nar/lzip/bcc5071mvprhp4yj1jimlhyyi499d2ba-texlivebin-20230313...
texlivebin-20230313 13.5MiB 527KiB/s 00:26 ▕██████████████████▏ 100.0%

substitution de /gnu/store/4hr3i6p7g2miwhy9gn64mxp1haix36dq-texlivetexmf-20230313...
téléchargement depuis https://ci.guix.gnu.org/nar/lzip/4hr3i6p7g2miwhy9gn64mxp1haix36dq-texlivetexmf-20230313...
texlivetexmf-20230313 3.63GiB 360KiB/s 00:17 ▕ ▏ 0.2%^C

--
Thanks,
Maxim
Maxim Cournoyer wrote 3 days ago
Re: bug#41602: texlive is actually substitutable
(name . Ludovic Courtès)(address . ludo@gnu.org)
874j0rxmjs.fsf_-_@gmail.com
Hi,

Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:

Toggle quote (29 lines)
> Hello,
>
> Ludovic Courtès <ludo@gnu.org> writes:
>
>> Hi,
>>
>> Leo Famulari <leo@famulari.name> skribis:
>>
>>> On Fri, May 29, 2020 at 05:15:40PM +0200, Ludovic Courtès wrote:
>>>> The info suggests it won’t be substituted, but it’s eventually
>>>> substituted. I wonder why, because the .drv has:
>>>>
>>>> ("allowSubstitutes","0")
>>>>
>>>> and the daemon has:
>>>>
>>>> bool substitutesAllowed(const Derivation & drv)
>>>> {
>>>> return get(drv.env, "allowSubstitutes", "1") == "1";
>>>> }
>>>>
>>>> and:
>>>>
>>>> if (settings.useSubstitutes && substitutesAllowed(drv))
>>>> foreach (PathSet::iterator, i, invalidOutputs)
>>>> addWaitee(worker.makeSubstitutionGoal(*i, buildMode == bmRepair));
>>>>
>>>> Thoughts?

It's odd, when using --dry-run, it seems the expected situation would
happen:

Toggle snippet (9 lines)
$ guix build --no-grafts -n texlive
guix build --no-grafts -n texlive
La dérivation suivante serait compilée :
/gnu/store/v10c5wzji81pkwq2fhj123gw3d8il0ic-texlivetexmf-20240312.drv
4 270,0 Mo seraient téléchargés :
/gnu/store/pb6z5d5fx6s13cjzmvlw7dykpafp9x97-texlive-20240312-texmf.tar.xz
/gnu/store/0gkx9q1kyys8cis93cw9qhlzyx584dr6-texlive-20240312

Only the private texlivetexmf is marked as non-substitutable, so the
above looks correct (though we see the intention of preserving bandwidth
wouldn't be achieved, given the source is as large as the final
package).

When removing the --dry-run, what happens though is that the output of
the texlivetexmf package, which is marked as non-substitutable, is downloaded:

Toggle snippet (11 lines)
$ guix build --no-grafts texlive
La dérivation suivante sera compilée :
/gnu/store/v10c5wzji81pkwq2fhj123gw3d8il0ic-texlivetexmf-20240312.drv
4 270,0 Mo seront téléchargés :
/gnu/store/pb6z5d5fx6s13cjzmvlw7dykpafp9x97-texlive-20240312-texmf.tar.xz
/gnu/store/0gkx9q1kyys8cis93cw9qhlzyx584dr6-texlive-20240312
substitution de /gnu/store/b5sn5ha961hab37r7vl5p2n6sf46x582-texlivetexmf-20240312...
téléchargement depuis https://bordeaux.guix.gnu.org/nar/lzip/b5sn5ha961hab37r7vl5p2n6sf46x582-texlivetexmf-20240312...
texlivetexmf-20240312 3.95GiB 2.8MiB/s 00:06 ▕ ▏ 0.4% C-c C-c^C

I've had some success as stopping in the daemon right before the downlod
starts, with this sequence:

Start the locally built guix-daemon in gdb, with a command like:

Toggle snippet (3 lines)
sudo -E ./pre-inst-env gdb --args ./guix-daemon --debug --build-users-group=guixbuild --max-silent-time 3600 --timeout 86400 --log-compression none --discover=no --substitute-urls='https://bordeaux.guix.gnu.org https://ci.guix.gnu.org'

Then, to be able to reach the point in the execution where the downloads
are about to start, we need to break in the first fork (but not the 2nd,
which is the guile substituter), like follows at the GDB prompt:

Toggle snippet (41 lines)
set follow-fork-mode child

# To break inside the first child process
break LocalStore::querySubstitutablePathInfos

run

## from a terminal, 'guix build texlive' to hit breakpoint

delete 1

# avoid entering the guile substituter fork
set follow-fork-mode parent

break LocalStore::buildPaths

continue

-> should break in
Thread 2.1 "guix-daemon" hit Breakpoint 2.1, nix::LocalStore::buildPaths
(this=0x51f4d0, drvPaths=std::set with 1 element = {...},
buildMode=nix::bmNormal) at nix/libstore/build.cc:3627

Thread 2.1 "guix-daemon" hit Breakpoint 2.1, nix::LocalStore::buildPaths (this=0x51f4d0, drvPaths=std::set with 1 element = {...}, buildMode=nix::bmNormal) at nix/libstore/build.cc:3627
3627 {
(gdb) bt
#0 nix::LocalStore::buildPaths (this=0x51f4d0, drvPaths=std::set with 1 element = {...}, buildMode=nix::bmNormal) at nix/libstore/build.cc:3627
#1 0x00000000004253b6 in performOp (from=..., to=..., op=<optimized out>, clientVersion=356, trusted=false) at nix/nix-daemon/nix-daemon.cc:481
#2 processConnection (trusted=<optimized out>, userId=<optimized out>) at nix/nix-daemon/nix-daemon.cc:841
#3 0x000000000042805f in operator() (__closure=0x4e8f50) at nix/nix-daemon/nix-daemon.cc:1003
#4 0x00000000004280ac in std::__invoke_impl<void, acceptConnection(int)::<lambda()>&> (__f=...) at /gnu/store/hzsq64kmn9bmnkhhywav83miaaapl4m1-profile/include/c++/bits/invoke.h:61
#5 std::__invoke_r<void, acceptConnection(int)::<lambda()>&> (__fn=...) at /gnu/store/hzsq64kmn9bmnkhhywav83miaaapl4m1-profile/include/c++/bits/invoke.h:154
#6 std::_Function_handler<void(), acceptConnection(int)::<lambda()> >::_M_invoke(const std::_Any_data &) (__functor=...) at /gnu/store/hzsq64kmn9bmnkhhywav83miaaapl4m1-profile/include/c++/bits/std_function.h:290
#7 0x0000000000495dbb in std::function<void()>::operator() (this=0x7fffffffbb00) at /gnu/store/hzsq64kmn9bmnkhhywav83miaaapl4m1-profile/include/c++/bits/std_function.h:590
#8 nix::startProcess (fun=..., dieWithParent=dieWithParent@entry=false, errorPrefix="unexpected build daemon error: ", runExitHandlers=runExitHandlers@entry=true) at nix/libutil/util.cc:1025
#9 0x00000000004237c2 in acceptConnection (fdSocket=<optimized out>) at nix/nix-daemon/nix-daemon.cc:977
#10 daemonLoop (sockets=std::vector of length 1, capacity 1 = {...}) at nix/nix-daemon/nix-daemon.cc:1055
#11 0x00000000004241b9 in run (sockets=std::vector of length 1, capacity 1 = {...}) at nix/nix-daemon/nix-daemon.cc:1064
#12 0x0000000000420635 in main (argc=<optimized out>, argv=<optimized out>) at nix/nix-daemon/guix-daemon.cc:569

I haven't investigated where in this execution path the
substitutesAllowed procedure is called, if at all, but this is what I
will try to understand next.

--
Thanks,
Maxim
Maxim Cournoyer wrote 3 days ago
(name . Ludovic Courtès)(address . ludo@gnu.org)
87zfiiwrra.fsf@gmail.com
Hello,

Maxim Cournoyer <maxim.cournoyer@gmail.com> writes:

[...]

Toggle quote (4 lines)
> I haven't investigated where in this execution path the
> substitutesAllowed procedure is called, if at all, but this is what I
> will try to understand next.

This gets called, in the case of texlive, only for the texlive .drv
itself, not for its referenced .drvs, which the daemon attempts to
substitute without checking for their allowSubstitutes variable first,
as this gdb screen grab attempts to show:

Toggle snippet (19 lines)
2: *goal = {<std::enable_shared_from_this<nix::Goal>> = {_M_weak_this = std::weak_ptr<nix::Goal> (use count 2, weak count 3) = {get() = 0x5e29a0}}, _vptr.Goal = 0x4c75e0 <vtable for nix::SubstitutionGoal+16>, worker = @0x7fffffff85c0, waitees = std::set with 0 elements, waiters = std::__cxx11::list = {[0] = std::weak_ptr<nix::Goal> (use count 1, weak count 5) = {get() = 0x5b08f0}}, nrFailed = 0, nrNoSubstituters = 0, nrIncompleteClosure = 0, name = "substitution of `/gnu/store/b5sn5ha961hab37r7vl5p2n6sf46x582-texlivetexmf-20240312'", exitCode = nix::Goal::ecBusy}

(gdb) where
#0 nix::Worker::run (this=0x7fffffff85c0, _topGoals=std::set with 1 element = {...}) at nix/libstore/build.cc:3448
#1 0x00000000004659c9 in nix::LocalStore::buildPaths (this=0x55b4d0, drvPaths=std::set with 1 element = {...}, buildMode=nix::bmNormal) at nix/libstore/build.cc:3642
#2 0x000000000040ad6c in performOp (trusted=false, clientVersion=356, from=..., to=..., op=9) at nix/nix-daemon/nix-daemon.cc:481
#3 0x000000000040e01b in processConnection (trusted=false, userId=1000) at nix/nix-daemon/nix-daemon.cc:841
#4 0x000000000040e754 in operator() (__closure=0x524f50) at nix/nix-daemon/nix-daemon.cc:1003
#5 0x0000000000410fda in std::__invoke_impl<void, acceptConnection(int)::<lambda()>&>(std::__invoke_other, struct {...} &) (__f=...) at /gnu/store/d50i890p2lg97kvc131p62wy52krapbd-profile/include/c++/bits/invoke.h:61
#6 0x000000000040f718 in std::__invoke_r<void, acceptConnection(int)::<lambda()>&>(struct {...} &) (__fn=...) at /gnu/store/d50i890p2lg97kvc131p62wy52krapbd-profile/include/c++/bits/invoke.h:154
#7 0x000000000040f5db in std::_Function_handler<void(), acceptConnection(int)::<lambda()> >::_M_invoke(const std::_Any_data &) (__functor=...) at /gnu/store/d50i890p2lg97kvc131p62wy52krapbd-profile/include/c++/bits/std_function.h:290
#8 0x0000000000441f00 in std::function<void()>::operator() (this=0x7fffffffaf10) at /gnu/store/d50i890p2lg97kvc131p62wy52krapbd-profile/include/c++/bits/std_function.h:590
#9 0x00000000004ab2ef in nix::startProcess (fun=..., dieWithParent=false, errorPrefix="unexpected build daemon error: ", runExitHandlers=true) at nix/libutil/util.cc:1025
#10 0x000000000040ed6b in acceptConnection (fdSocket=3) at nix/nix-daemon/nix-daemon.cc:977
#11 0x000000000040f40e in daemonLoop (sockets=std::vector of length 1, capacity 1 = {...}) at nix/nix-daemon/nix-daemon.cc:1055
#12 0x000000000040f4bd in run (sockets=std::vector of length 1, capacity 1 = {...}) at nix/nix-daemon/nix-daemon.cc:1064
#13 0x000000000041a262 in main (argc=12, argv=0x7fffffffc208) at nix/nix-daemon/guix-daemon.cc:569

But perhaps it is futile that the *client* should enforce this. If we
do not want to distribute something in binary form, we shouldn't bake a
.nar for it and make it available in the first place, as pointed by
Emily in #nix-dev:nixos.org (on their Matrix server).

I'll investigate this idea next.

--
Thanks,
Maxim
Ludovic Courtès wrote 8 hours ago
(name . Maxim Cournoyer)(address . maxim.cournoyer@gmail.com)
87cyfba719.fsf@gnu.org
Hi,

Maxim Cournoyer <maxim.cournoyer@gmail.com> skribis:

Toggle quote (5 lines)
> But perhaps it is futile that the *client* should enforce this. If we
> do not want to distribute something in binary form, we shouldn't bake a
> .nar for it and make it available in the first place, as pointed by
> Emily in #nix-dev:nixos.org (on their Matrix server).

Agreed, probably something to fix in ‘guix publish’ & co.

Thanks for addressing this longstanding issue!

Ludo’.
?
Your comment

Commenting via the web interface is currently disabled.

To comment on this conversation send an email to 41602@debbugs.gnu.org

To respond to this issue using the mumi CLI, first switch to it
mumi current 41602
Then, you may apply the latest patchset in this issue (with sign off)
mumi am -- -s
Or, compose a reply to this issue
mumi compose
Or, send patches to this issue
mumi send-email *.patch