From: Matthias Bolte Date: Mon, 30 May 2011 10:58:57 +0000 (+0200) Subject: remote generator: Legacy support for hyper to long mappings X-Git-Tag: CVE-2011-2178~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=32abd5ee265a6d06df42dff903f74c886a939e58;p=thirdparty%2Flibvirt.git remote generator: Legacy support for hyper to long mappings Remove some special case code that took care of mapping hyper to the correct C types. As the list of procedures that is allowed to map hyper to long is fixed put it in the generator instead annotations in the .x files. This results in simpler .x file parsing code. Use macros for hyper to long assignments that perform overflow checks when long is smaller than hyper. Map hyper to long long by default. Suggested by Eric Blake. --- diff --git a/configure.ac b/configure.ac index b2ba930d48..62cd17742a 100644 --- a/configure.ac +++ b/configure.ac @@ -117,6 +117,7 @@ if test "x$have_cpuid" = xyes; then fi AC_MSG_RESULT([$have_cpuid]) +AC_CHECK_SIZEOF([long]) dnl Availability of various common functions (non-fatal if missing), dnl and various less common threadsafe functions diff --git a/daemon/remote.c b/daemon/remote.c index 1897be8b50..64478cc7a2 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -68,6 +68,24 @@ virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \ __FUNCTION__, __LINE__, __VA_ARGS__) +#if SIZEOF_LONG < 8 +# define HYPER_TO_TYPE(_type, _to, _from) \ + do { \ + if ((_from) != (_type)(_from)) { \ + virNetError(VIR_ERR_INTERNAL_ERROR, \ + _("conversion from hyper to %s overflowed"), #_type); \ + goto cleanup; \ + } \ + (_to) = (_from); \ + } while (0) + +# define HYPER_TO_LONG(_to, _from) HYPER_TO_TYPE(long, _to, _from) +# define HYPER_TO_ULONG(_to, _from) HYPER_TO_TYPE(unsigned long, _to, _from) +#else +# define HYPER_TO_LONG(_to, _from) (_to) = (_from) +# define HYPER_TO_ULONG(_to, _from) (_to) = (_from) +#endif + static virDomainPtr get_nonnull_domain(virConnectPtr conn, remote_nonnull_domain domain); static virNetworkPtr get_nonnull_network(virConnectPtr conn, remote_nonnull_network network); static virInterfacePtr get_nonnull_interface(virConnectPtr conn, remote_nonnull_interface iface); diff --git a/daemon/remote_generator.pl b/daemon/remote_generator.pl index ac808fb0c6..f85cc6b04b 100755 --- a/daemon/remote_generator.pl +++ b/daemon/remote_generator.pl @@ -174,6 +174,58 @@ while () { close(PROTOCOL); +# this hash contains the procedures that are allowed to map [unsigned] hyper +# to [unsigned] long for legacy reasons in their signature and return type. +# this list is fixed. new procedures and public APIs have to map [unsigned] +# hyper to [unsigned] long long +my $long_legacy = { + DomainGetMaxMemory => { ret => { memory => 1 } }, + DomainGetInfo => { ret => { maxMem => 1, memory => 1 } }, + DomainMigrate => { arg => { flags => 1, resource => 1 } }, + DomainMigrate2 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateBegin3 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateConfirm3 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateDirect => { arg => { flags => 1, resource => 1 } }, + DomainMigrateFinish => { arg => { flags => 1 } }, + DomainMigrateFinish2 => { arg => { flags => 1 } }, + DomainMigrateFinish3 => { arg => { flags => 1 } }, + DomainMigratePeer2Peer => { arg => { flags => 1, resource => 1 } }, + DomainMigratePerform => { arg => { flags => 1, resource => 1 } }, + DomainMigratePerform3 => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepare => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepare2 => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepare3 => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepareTunnel => { arg => { flags => 1, resource => 1 } }, + DomainMigratePrepareTunnel3 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateToURI => { arg => { flags => 1, resource => 1 } }, + DomainMigrateToURI2 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateVersion1 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateVersion2 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateVersion3 => { arg => { flags => 1, resource => 1 } }, + DomainMigrateSetMaxSpeed => { arg => { bandwidth => 1 } }, + DomainSetMaxMemory => { arg => { memory => 1 } }, + DomainSetMemory => { arg => { memory => 1 } }, + DomainSetMemoryFlags => { arg => { memory => 1 } }, + GetLibVersion => { ret => { lib_ver => 1 } }, + GetVersion => { ret => { hv_ver => 1 } }, + NodeGetInfo => { ret => { memory => 1 } }, +}; + +sub hyper_to_long +{ + my $proc_name = shift; + my $ret_or_arg = shift; + my $member = shift; + + if ($long_legacy->{$proc_name} and + $long_legacy->{$proc_name}->{$ret_or_arg} and + $long_legacy->{$proc_name}->{$ret_or_arg}->{$member}) { + return 1; + } else { + return 0 + } +} + #---------------------------------------------------------------------- # Output @@ -378,12 +430,29 @@ elsif ($opt_b) { } push(@args_list, "args->$1"); - } elsif ($args_member =~ m/^(unsigned )?(int|hyper) (\S+);/) { + } elsif ($args_member =~ m/^(unsigned )?int (\S+);/) { if (! @args_list) { push(@args_list, "conn"); } - push(@args_list, "args->$3"); + push(@args_list, "args->$2"); + } elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) { + if (! @args_list) { + push(@args_list, "conn"); + } + + my $arg_name = $2; + + if (hyper_to_long($call->{ProcName}, "arg", $arg_name)) { + my $type_name = $1; $type_name .= "long"; + my $sign = ""; $sign = "U" if ($1); + + push(@vars_list, "$type_name $arg_name"); + push(@getters_list, " HYPER_TO_${sign}LONG($arg_name, args->$arg_name);\n"); + push(@args_list, "$arg_name"); + } else { + push(@args_list, "args->$arg_name"); + } } elsif ($args_member =~ m/^(\/)?\*/) { # ignore comments } else { @@ -411,6 +480,10 @@ elsif ($opt_b) { foreach my $ret_member (@{$call->{ret_members}}) { if ($multi_ret) { if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) { + if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) { + die "legacy [u]long hyper arrays aren't supported"; + } + push(@ret_list, "memcpy(ret->$3, tmp.$3, sizeof ret->$3);"); } elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+);/) { push(@ret_list, "ret->$3 = tmp.$3;"); @@ -502,6 +575,10 @@ elsif ($opt_b) { } } } elsif ($ret_member =~ m/^(?:unsigned )?hyper (\S+)<(\S+)>;\s*\/\*\s*insert@(\d+)\s*\*\//) { + if (hyper_to_long($call->{ProcName}, "ret", $1)) { + die "legacy [u]long hyper arrays aren't supported"; + } + push(@vars_list, "int len"); push(@ret_list, "ret->$1.$1_len = len;"); push(@free_list_on_error, "VIR_FREE(ret->$1.$1_val);"); @@ -523,14 +600,22 @@ elsif ($opt_b) { # error out on unannotated arrays die "hyper array without insert@ annotation: $ret_member"; } elsif ($ret_member =~ m/^(unsigned )?hyper (\S+);/) { - my $type_name; + my $type_name = $1; my $ret_name = $2; + my $ret_assign; - $type_name = $1 if ($1); - $type_name .= "long"; + if (hyper_to_long($call->{ProcName}, "ret", $ret_name)) { + my $sign = ""; $sign = "U" if ($1); + + $type_name .= "long"; + $ret_assign = "HYPER_TO_${sign}LONG(ret->$ret_name, $ret_name);"; + } else { + $type_name .= "long long"; + $ret_assign = "ret->$ret_name = $ret_name;"; + } push(@vars_list, "$type_name $ret_name"); - push(@ret_list, "ret->$ret_name = $ret_name;"); + push(@ret_list, $ret_assign); $single_ret_var = $ret_name; if ($call->{ProcName} eq "DomainGetMaxMemory" or @@ -888,22 +973,20 @@ elsif ($opt_k) { push(@setters_list, "args.$arg_name.${arg_name}_val = (char *)$arg_name;"); push(@setters_list, "args.$arg_name.${arg_name}_len = ${arg_name}len;"); push(@args_check_list, { name => "\"$arg_name\"", arg => "${arg_name}len", limit => $limit }); - } elsif ($args_member =~ m/^(unsigned )?(int|hyper) (\S+);/) { - my $type_name; - my $arg_name = $3; - - $type_name = $1 if ($1); - $type_name .= $2; - $type_name =~ s/hyper/long/; - - # SPECIAL: some hyper parameters map to long longs - if (($call->{ProcName} eq "DomainMigrateSetMaxDowntime" and - $arg_name eq "downtime") or - ($call->{ProcName} eq "StorageVolUpload" and - ($arg_name eq "offset" or $arg_name eq "length")) or - ($call->{ProcName} eq "StorageVolDownload" and - ($arg_name eq "offset" or $arg_name eq "length"))) { - $type_name .= " long"; + } elsif ($args_member =~ m/^(unsigned )?int (\S+);/) { + my $type_name = $1; $type_name .= "int"; + my $arg_name = $2; + + push(@args_list, "$type_name $arg_name"); + push(@setters_list, "args.$arg_name = $arg_name;"); + } elsif ($args_member =~ m/^(unsigned )?hyper (\S+);/) { + my $type_name = $1; + my $arg_name = $2; + + if (hyper_to_long($call->{ProcName}, "arg", $arg_name)) { + $type_name .= "long"; + } else { + $type_name .= "long long"; } push(@args_list, "$type_name $arg_name"); @@ -961,13 +1044,23 @@ elsif ($opt_k) { foreach my $ret_member (@{$call->{ret_members}}) { if ($multi_ret) { if ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+)\[\S+\];/) { + if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) { + die "legacy [u]long hyper arrays aren't supported"; + } + push(@ret_list, "memcpy(result->$3, ret.$3, sizeof result->$3);"); } elsif ($ret_member =~ m/<\S+>;/ or $ret_member =~ m/\[\S+\];/) { # just make all other array types fail die "unhandled type for multi-return-value for " . "procedure $call->{name}: $ret_member"; } elsif ($ret_member =~ m/^(unsigned )?(char|short|int|hyper) (\S+);/) { - push(@ret_list, "result->$3 = ret.$3;"); + if ($2 eq "hyper" and hyper_to_long($call->{ProcName}, "ret", $3)) { + my $sign = ""; $sign = "U" if ($1); + + push(@ret_list, "HYPER_TO_${sign}LONG(result->$3, ret.$3);"); + } else { + push(@ret_list, "result->$3 = ret.$3;"); + } } else { die "unhandled type for multi-return-value for " . "procedure $call->{name}: $ret_member"; @@ -1039,22 +1132,22 @@ elsif ($opt_k) { $single_ret_var = "int rv = -1"; $single_ret_type = "int"; } elsif ($ret_member =~ m/^unsigned hyper (\S+);/) { - my $arg_name = $1; + my $ret_name = $1; if ($call->{ProcName} =~ m/Get(Lib)?Version/) { - push(@args_list, "unsigned long *$arg_name"); - push(@ret_list, "if ($arg_name) *$arg_name = ret.$arg_name;"); + push(@args_list, "unsigned long *$ret_name"); + push(@ret_list, "if ($ret_name) HYPER_TO_ULONG(*$ret_name, ret.$ret_name);"); push(@ret_list, "rv = 0;"); $single_ret_var = "int rv = -1"; $single_ret_type = "int"; - } elsif ($call->{ProcName} eq "NodeGetFreeMemory") { - push(@ret_list, "rv = ret.$arg_name;"); - $single_ret_var = "unsigned long long rv = 0"; - $single_ret_type = "unsigned long long"; - } else { - push(@ret_list, "rv = ret.$arg_name;"); + } elsif (hyper_to_long($call->{ProcName}, "ret", $ret_name)) { + push(@ret_list, "HYPER_TO_ULONG(rv, ret.$ret_name);"); $single_ret_var = "unsigned long rv = 0"; $single_ret_type = "unsigned long"; + } else { + push(@ret_list, "rv = ret.$ret_name;"); + $single_ret_var = "unsigned long long rv = 0"; + $single_ret_type = "unsigned long long"; } } elsif ($ret_member =~ m/^(\/)?\*/) { # ignore comments diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 8e3cd89bf2..ac0c6f7aef 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -87,6 +87,24 @@ #define VIR_FROM_THIS VIR_FROM_REMOTE +#if SIZEOF_LONG < 8 +# define HYPER_TO_TYPE(_type, _to, _from) \ + do { \ + if ((_from) != (_type)(_from)) { \ + remoteError(VIR_ERR_INTERNAL_ERROR, \ + _("conversion from hyper to %s overflowed"), #_type); \ + goto done; \ + } \ + (_to) = (_from); \ + } while (0) + +# define HYPER_TO_LONG(_to, _from) HYPER_TO_TYPE(long, _to, _from) +# define HYPER_TO_ULONG(_to, _from) HYPER_TO_TYPE(unsigned long, _to, _from) +#else +# define HYPER_TO_LONG(_to, _from) (_to) = (_from) +# define HYPER_TO_ULONG(_to, _from) (_to) = (_from) +#endif + static int inside_daemon = 0; struct remote_thread_call;