db-d2/primevul-codebert-embeddings huggingface dataset:
Commit message: MDEV-25994: Crash with union of my_decimal type in ORDER BY clause

When single-row subquery fails with "Subquery reutrns more than 1 row"
error, it will raise an error and return NULL.

On the other hand, Item_singlerow_subselect sets item->maybe_null=0
for table-less subqueries like "(SELECT not_null_value)"  (*)

This discrepancy (item with maybe_null=0 returning NULL) causes the
code in Type_handler_decimal_result::make_sort_key_part() to crash.

Fixed this by allowing inference (*) only when the subquery is NOT a
UNION.
CVE: CVE-2022-27380
CWE: CWE-89
Vulnerability description: An issue in the component my_decimal::operator= of MariaDB Server v10.6.3 and below was discovered to allow attackers to cause a Denial of Service (DoS) via specially crafted SQL statements.

Project: server

bool Item_singlerow_subselect::fix_length_and_dec()
{
  if ((max_columns= engine->cols()) == 1)
  {
    if (engine->fix_length_and_dec(row= &value))
      return TRUE;
  }
  else
  {
    if (!(row= (Item_cache**) current_thd->alloc(sizeof(Item_cache*) *
                                                 max_columns)) ||
        engine->fix_length_and_dec(row))
      return TRUE;
    value= *row;
  }
  unsigned_flag= value->unsigned_flag;
  /*
    If there are not tables in subquery then ability to have NULL value
    depends on SELECT list (if single row subquery have tables then it
    always can be NULL if there are not records fetched).
  */
  if (engine->no_tables())
    maybe_null= engine->may_be_null();
  else
  {
    for (uint i= 0; i < max_columns; i++)
      row[i]->maybe_null= TRUE;
  }
  return FALSE;
}
Commit message: MDEV-26574 An improper locking bug due to unreleased lock in the ds_xbstream.cc

release lock in all as cases n xbstream_open, also fix the case where malloc would return NULL.
CVE: CVE-2022-31621
CWE: CWE-703
Vulnerability description: MariaDB Server before 10.7 is vulnerable to Denial of Service. In extra/mariabackup/ds_xbstream.cc, when an error occurs (stream_ctxt->dest_file == NULL) while executing the method xbstream_open, the held lock is not released correctly, which allows local users to trigger a denial of service due to the deadlock.

Project: server

xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
{
	ds_file_t		*file;
	ds_stream_file_t	*stream_file;
	ds_stream_ctxt_t	*stream_ctxt;
	ds_ctxt_t		*dest_ctxt;
	xb_wstream_t		*xbstream;
	xb_wstream_file_t	*xbstream_file;


	xb_ad(ctxt->pipe_ctxt != NULL);
	dest_ctxt = ctxt->pipe_ctxt;

	stream_ctxt = (ds_stream_ctxt_t *) ctxt->ptr;

	pthread_mutex_lock(&stream_ctxt->mutex);
	if (stream_ctxt->dest_file == NULL) {
		stream_ctxt->dest_file = ds_open(dest_ctxt, path, mystat);
		if (stream_ctxt->dest_file == NULL) {
			return NULL;
		}
	}
	pthread_mutex_unlock(&stream_ctxt->mutex);

	file = (ds_file_t *) my_malloc(sizeof(ds_file_t) +
				       sizeof(ds_stream_file_t),
				       MYF(MY_FAE));
	stream_file = (ds_stream_file_t *) (file + 1);

	xbstream = stream_ctxt->xbstream;

	xbstream_file = xb_stream_write_open(xbstream, path, mystat,
		                             stream_ctxt,
					     my_xbstream_write_callback);

	if (xbstream_file == NULL) {
		msg("xb_stream_write_open() failed.");
		goto err;
	}

	stream_file->xbstream_file = xbstream_file;
	stream_file->stream_ctxt = stream_ctxt;
	file->ptr = stream_file;
	file->path = stream_ctxt->dest_file->path;

	return file;

err:
	if (stream_ctxt->dest_file) {
		ds_close(stream_ctxt->dest_file);
		stream_ctxt->dest_file = NULL;
	}
	my_free(file);

	return NULL;
}
Commit message: MDEV-26561 mariabackup release locks

The previous threads locked need to be released too.

This occurs if the initialization of any of the non-first
mutex/conditition variables errors occurs.
CVE: CVE-2022-31623
CWE: CWE-703
Vulnerability description: MariaDB Server before 10.7 is vulnerable to Denial of Service. In extra/mariabackup/ds_compress.cc, when an error occurs (i.e., going to the err label) while executing the method create_worker_threads, the held lock thd->ctrl_mutex is not released correctly, which allows local users to trigger a denial of service due to the deadlock.

Project: server

create_worker_threads(uint n)
{
	comp_thread_ctxt_t	*threads;
	uint 			i;

	threads = (comp_thread_ctxt_t *)
		my_malloc(sizeof(comp_thread_ctxt_t) * n, MYF(MY_FAE));

	for (i = 0; i < n; i++) {
		comp_thread_ctxt_t *thd = threads + i;

		thd->num = i + 1;
		thd->started = FALSE;
		thd->cancelled = FALSE;
		thd->data_avail = FALSE;

		thd->to = (char *) my_malloc(COMPRESS_CHUNK_SIZE +
						   MY_QLZ_COMPRESS_OVERHEAD,
						   MYF(MY_FAE));

		/* Initialize the control mutex and condition var */
		if (pthread_mutex_init(&thd->ctrl_mutex, NULL) ||
		    pthread_cond_init(&thd->ctrl_cond, NULL)) {
			goto err;
		}

		/* Initialize and data mutex and condition var */
		if (pthread_mutex_init(&thd->data_mutex, NULL) ||
		    pthread_cond_init(&thd->data_cond, NULL)) {
			goto err;
		}

		pthread_mutex_lock(&thd->ctrl_mutex);

		if (pthread_create(&thd->id, NULL, compress_worker_thread_func,
				   thd)) {
			msg("compress: pthread_create() failed: "
			    "errno = %d", errno);
			pthread_mutex_unlock(&thd->ctrl_mutex);
			goto err;
		}
	}

	/* Wait for the threads to start */
	for (i = 0; i < n; i++) {
		comp_thread_ctxt_t *thd = threads + i;

		while (thd->started == FALSE)
			pthread_cond_wait(&thd->ctrl_cond, &thd->ctrl_mutex);
		pthread_mutex_unlock(&thd->ctrl_mutex);
	}

	return threads;

err:
	my_free(threads);
	return NULL;
}
Commit message: target/loongarch: Clean up tlb when cpu reset

We should make sure that tlb is clean when cpu reset.

Signed-off-by: Song Gao <gaosong@loongson.cn>
Message-Id: <20220705070950.2364243-1-gaosong@loongson.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
CVE: CVE-2022-35414
CWE: CWE-908
Vulnerability description: softmmu/physmem.c in QEMU through 7.0.0 can perform an uninitialized read on the translate_fail path, leading to an io_readx or io_writex crash. NOTE: a third party states that the Non-virtualization Use Case in the qemu.org reference applies here, i.e., "Bugs affecting the non-virtualization use case are not considered security bugs at this time.

Project: qemu

static void loongarch_cpu_reset(DeviceState *dev)
{
    CPUState *cs = CPU(dev);
    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
    LoongArchCPUClass *lacc = LOONGARCH_CPU_GET_CLASS(cpu);
    CPULoongArchState *env = &cpu->env;

    lacc->parent_reset(dev);

    env->fcsr0_mask = FCSR0_M1 | FCSR0_M2 | FCSR0_M3;
    env->fcsr0 = 0x0;

    int n;
    /* Set csr registers value after reset */
    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, 0);
    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, 0);
    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 1);
    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 0);
    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATF, 1);
    env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DATM, 1);

    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, FPE, 0);
    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, SXE, 0);
    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, ASXE, 0);
    env->CSR_EUEN = FIELD_DP64(env->CSR_EUEN, CSR_EUEN, BTE, 0);

    env->CSR_MISC = 0;

    env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, VS, 0);
    env->CSR_ECFG = FIELD_DP64(env->CSR_ECFG, CSR_ECFG, LIE, 0);

    env->CSR_ESTAT = env->CSR_ESTAT & (~MAKE_64BIT_MASK(0, 2));
    env->CSR_RVACFG = FIELD_DP64(env->CSR_RVACFG, CSR_RVACFG, RBITS, 0);
    env->CSR_TCFG = FIELD_DP64(env->CSR_TCFG, CSR_TCFG, EN, 0);
    env->CSR_LLBCTL = FIELD_DP64(env->CSR_LLBCTL, CSR_LLBCTL, KLO, 0);
    env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
    env->CSR_MERRCTL = FIELD_DP64(env->CSR_MERRCTL, CSR_MERRCTL, ISMERR, 0);

    env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, TLB_TYPE, 2);
    env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, MTLB_ENTRY, 63);
    env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_WAYS, 7);
    env->CSR_PRCFG3 = FIELD_DP64(env->CSR_PRCFG3, CSR_PRCFG3, STLB_SETS, 8);

    for (n = 0; n < 4; n++) {
        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV0, 0);
        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV1, 0);
        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV2, 0);
        env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
    }

#ifndef CONFIG_USER_ONLY
    env->pc = 0x1c000000;
#endif

    restore_fp_status(env);
    cs->exception_index = -1;
}
Commit message: Avoid overflowing allocation size in calloc()
CVE: CVE-2012-2675
CWE: CWE-189
Vulnerability description: Multiple integer overflows in the (1) CallMalloc (malloc) and (2) nedpcalloc (calloc) functions in nedmalloc (nedmalloc.c) before 1.10 beta2 make it easier for context-dependent attackers to perform memory-related attacks such as buffer overflows via a large size value, which causes less memory to be allocated than expected.

Project: nedmalloc

NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC
{
	unsigned flags=NEDMALLOC_FORCERESERVE(p, 0, no*size);
	return nedpmalloc2(p, size*no, 0, M2_ZERO_MEMORY|flags);
}
Commit message: 13242 parse_user_name in PAM is sloppy
Reviewed by: Alex Wilson <alex@cooperi.net>
Approved by: Gordon Ross <gordon.w.ross@gmail.com>
CVE: CVE-2020-27678
CWE: CWE-120
Vulnerability description: An issue was discovered in illumos before 2020-10-22, as used in OmniOS before r151030by, r151032ay, and r151034y and SmartOS before 20201022. There is a buffer overflow in parse_user_name in lib/libpam/pam_framework.c.

Project: illumos-gate

parse_user_name(char *user_input, char **ret_username)
{
	register char *ptr;
	register int index = 0;
	char username[PAM_MAX_RESP_SIZE];

	/* Set the default value for *ret_username */
	*ret_username = NULL;

	/*
	 * Set the initial value for username - this is a buffer holds
	 * the user name.
	 */
	bzero((void *)username, PAM_MAX_RESP_SIZE);

	/*
	 * The user_input is guaranteed to be terminated by a null character.
	 */
	ptr = user_input;

	/* Skip all the leading whitespaces if there are any. */
	while ((*ptr == ' ') || (*ptr == '\t'))
		ptr++;

	if (*ptr == '\0') {
		/*
		 * We should never get here since the user_input we got
		 * in pam_get_user() is not all whitespaces nor just "\0".
		 */
		return (PAM_BUF_ERR);
	}

	/*
	 * username will be the first string we get from user_input
	 * - we skip leading whitespaces and ignore trailing whitespaces
	 */
	while (*ptr != '\0') {
		if ((*ptr == ' ') || (*ptr == '\t'))
			break;
		else {
			username[index] = *ptr;
			index++;
			ptr++;
		}
	}

	/* ret_username will be freed in pam_get_user(). */
	if ((*ret_username = malloc(index + 1)) == NULL)
		return (PAM_BUF_ERR);
	(void) strcpy(*ret_username, username);
	return (PAM_SUCCESS);
}
Commit message: Add appheader tests; fix buffer overflow in main_get_appheader
CVE: CVE-2014-9765
CWE: CWE-119
Vulnerability description: Buffer overflow in the main_get_appheader function in xdelta3-main.h in xdelta3 before 3.0.9 allows remote attackers to execute arbitrary code via a crafted input file.

Project: xdelta-devel

main_get_appheader (xd3_stream *stream, main_file *ifile,
		    main_file *output, main_file *sfile)
{
  uint8_t *apphead;
  usize_t appheadsz;
  int ret;

  /* The user may disable the application header.  Once the appheader
   * is set, this disables setting it again. */
  if (! option_use_appheader) { return; }

  ret = xd3_get_appheader (stream, & apphead, & appheadsz);

  /* Ignore failure, it only means we haven't received a header yet. */
  if (ret != 0) { return; }

  if (appheadsz > 0)
    {
      char *start = (char*)apphead;
      char *slash;
      int   place = 0;
      char *parsed[4];

      memset (parsed, 0, sizeof (parsed));

      while ((slash = strchr (start, '/')) != NULL)
	{
	  *slash = 0;
	  parsed[place++] = start;
	  start = slash + 1;
	}

      parsed[place++] = start;

      /* First take the output parameters. */
      if (place == 2 || place == 4)
	{
	  main_get_appheader_params (output, parsed, 1, "output", ifile);
	}

      /* Then take the source parameters. */
      if (place == 4)
	{
	  main_get_appheader_params (sfile, parsed+2, 0, "source", ifile);
	}
    }

  option_use_appheader = 0;
  return;
}
Commit message: Use "length", which has been limited in size
CVE: CVE-2015-9542
CWE: CWE-787
Vulnerability description: add_password in pam_radius_auth.c in pam_radius 1.4.0 does not correctly check the length of the input password, and is vulnerable to a stack-based buffer overflow during memcpy(). An attacker could send a crafted password to an application (loading the pam_radius library) and crash it. Arbitrary code execution might be possible, depending on the application, C library, compiler, and other factors.

Project: pam_radius

static void add_password(AUTH_HDR *request, unsigned char type, CONST char *password, char *secret)
{
	MD5_CTX md5_secret, my_md5;
	unsigned char misc[AUTH_VECTOR_LEN];
	int i;
	int length = strlen(password);
	unsigned char hashed[256 + AUTH_PASS_LEN];	/* can't be longer than this */
	unsigned char *vector;
	attribute_t *attr;

	if (length > MAXPASS) {				/* shorten the password for now */
		length = MAXPASS;
	}

	if (length == 0) {
		length = AUTH_PASS_LEN;			/* 0 maps to 16 */
	} if ((length & (AUTH_PASS_LEN - 1)) != 0) {
		length += (AUTH_PASS_LEN - 1);		/* round it up */
		length &= ~(AUTH_PASS_LEN - 1);		/* chop it off */
	}						/* 16*N maps to itself */

	memset(hashed, 0, length);
	memcpy(hashed, password, strlen(password));

	attr = find_attribute(request, PW_PASSWORD);

	if (type == PW_PASSWORD) {
		vector = request->vector;
	} else {
		vector = attr->data;			/* attr CANNOT be NULL here. */
	}

	/* ************************************************************ */
	/* encrypt the password */
	/* password : e[0] = p[0] ^ MD5(secret + vector) */
	MD5Init(&md5_secret);
	MD5Update(&md5_secret, (unsigned char *) secret, strlen(secret));
	my_md5 = md5_secret;				/* so we won't re-do the hash later */
	MD5Update(&my_md5, vector, AUTH_VECTOR_LEN);
	MD5Final(misc, &my_md5);			/* set the final vector */
	xor(hashed, misc, AUTH_PASS_LEN);

	/* For each step through, e[i] = p[i] ^ MD5(secret + e[i-1]) */
	for (i = 1; i < (length >> 4); i++) {
		my_md5 = md5_secret;			/* grab old value of the hash */
		MD5Update(&my_md5, &hashed[(i-1) * AUTH_PASS_LEN], AUTH_PASS_LEN);
		MD5Final(misc, &my_md5);			/* set the final vector */
		xor(&hashed[i * AUTH_PASS_LEN], misc, AUTH_PASS_LEN);
	}

	if (type == PW_OLD_PASSWORD) {
		attr = find_attribute(request, PW_OLD_PASSWORD);
	}

	if (!attr) {
		add_attribute(request, type, hashed, length);
	} else {
		memcpy(attr->data, hashed, length); /* overwrite the packet */
	}
}
Commit message: Fixed: Buffer overrun vulnerability in URL decoding. Thanks to Zack Flack for report.
CVE: CVE-2019-11455
CWE: CWE-125
Vulnerability description: A buffer over-read in Util_urlDecode in util.c in Tildeslash Monit before 5.25.3 allows a remote authenticated attacker to retrieve the contents of adjacent memory via manipulation of GET or POST parameters. The attacker can also cause a denial of service (application outage).

Project: monit

static char x2c(char *hex) {
        register char digit;
        digit = ((hex[0] >= 'A') ? ((hex[0] & 0xdf) - 'A')+10 : (hex[0] - '0'));
        digit *= 16;
        digit += (hex[1] >= 'A' ? ((hex[1] & 0xdf) - 'A')+10 : (hex[1] - '0'));
        return(digit);
}
Commit message: All: Merge some file writing extension checks
CVE: CVE-2017-6903
CWE: CWE-269
Vulnerability description: In ioquake3 before 2017-03-14, the auto-downloading feature has insufficient content restrictions. This also affects Quake III Arena, OpenArena, OpenJK, iortcw, and other id Tech 3 (aka Quake 3 engine) forks. A malicious auto-downloaded file can trigger loading of crafted auto-downloaded files as native code DLLs. A malicious auto-downloaded file can contain configuration defaults that override the user's. Executable bytecode in a malicious auto-downloaded file can set configuration variables to values that will result in unwanted native code DLLs being loaded, resulting in sandbox escape.

Project: iortcw

void Con_Dump_f( void ) {
	int l, x, i;
	short   *line;
	fileHandle_t f;
	int		bufferlen;
	char	*buffer;
	char	filename[MAX_QPATH];

	if ( Cmd_Argc() != 2 ) {
		Com_Printf( "usage: condump <filename>\n" );
		return;
	}

	Q_strncpyz( filename, Cmd_Argv( 1 ), sizeof( filename ) );
	COM_DefaultExtension( filename, sizeof( filename ), ".txt" );

	f = FS_FOpenFileWrite( filename );
	if ( !f ) {
		Com_Printf ("ERROR: couldn't open %s.\n", filename);
		return;
	}

	Com_Printf ("Dumped console text to %s.\n", filename );

	// skip empty lines
	for ( l = con.current - con.totallines + 1 ; l <= con.current ; l++ )
	{
		line = con.text + ( l % con.totallines ) * con.linewidth;
		for ( x = 0 ; x < con.linewidth ; x++ )
			if ( ( line[x] & 0xff ) != ' ' ) {
				break;
			}
		if ( x != con.linewidth ) {
			break;
		}
	}

#ifdef _WIN32
	bufferlen = con.linewidth + 3 * sizeof ( char );
#else
	bufferlen = con.linewidth + 2 * sizeof ( char );
#endif

	buffer = Hunk_AllocateTempMemory( bufferlen );

	// write the remaining lines
	buffer[bufferlen-1] = 0;
	for ( ; l <= con.current ; l++ )
	{
		line = con.text + ( l % con.totallines ) * con.linewidth;
		for ( i = 0; i < con.linewidth; i++ )
			buffer[i] = line[i] & 0xff;
		for ( x = con.linewidth - 1 ; x >= 0 ; x-- )
		{
			if ( buffer[x] == ' ' ) {
				buffer[x] = 0;
			} else {
				break;
			}
		}
#ifdef _WIN32
		Q_strcat(buffer, bufferlen, "\r\n");
#else
		Q_strcat(buffer, bufferlen, "\n");
#endif
		FS_Write( buffer, strlen( buffer ), f );
	}

	Hunk_FreeTempMemory( buffer );
	FS_FCloseFile( f );
}
Commit message: Avoid listening on all interfaces by default
CVE: CVE-2018-1281
CWE: CWE-200
Vulnerability description: The clustered setup of Apache MXNet allows users to specify which IP address and port the scheduler will listen on via the DMLC_PS_ROOT_URI and DMLC_PS_ROOT_PORT env variables. In versions older than 1.0.0, however, the MXNet framework will listen on 0.0.0.0 rather than user specified DMLC_PS_ROOT_URI once a scheduler node is initialized. This exposes the instance running MXNet to any attackers reachable via the interface they didn't expect to be listening on. For example: If a user wants to run a clustered setup locally, they may specify to run on 127.0.0.1. But since MXNet will listen on 0.0.0.0, it makes the port accessible on all network interfaces.

Project: ps-lite

  int Bind(const Node& node, int max_retry) override {
    receiver_ = zmq_socket(context_, ZMQ_ROUTER);
    CHECK(receiver_ != NULL)
        << "create receiver socket failed: " << zmq_strerror(errno);
    int local = GetEnv("DMLC_LOCAL", 0);
    std::string addr = local ? "ipc:///tmp/" : "tcp://*:";
    int port = node.port;
    unsigned seed = static_cast<unsigned>(time(NULL)+port);
    for (int i = 0; i < max_retry+1; ++i) {
      auto address = addr + std::to_string(port);
      if (zmq_bind(receiver_, address.c_str()) == 0) break;
      if (i == max_retry) {
        port = -1;
      } else {
        port = 10000 + rand_r(&seed) % 40000;
      }
    }
    return port;
  }
Commit message: Fix out-of-bounds array access when passing a <4 byte input file to wavm or wavm-compile
CVE: CVE-2018-17292
CWE: CWE-125
Vulnerability description: An issue was discovered in WAVM before 2018-09-16. The loadModule function in Include/Inline/CLI.h lacks checking of the file length before a file magic comparison, allowing attackers to cause a Denial of Service (application crash caused by out-of-bounds read) by crafting a file that has fewer than 4 bytes.

Project: WAVM

inline bool loadModule(const char* filename, IR::Module& outModule)
{
	// Read the specified file into an array.
	std::vector<U8> fileBytes;
	if(!loadFile(filename, fileBytes)) { return false; }

	// If the file starts with the WASM binary magic number, load it as a binary irModule.
	if(*(U32*)fileBytes.data() == 0x6d736100)
	{ return loadBinaryModule(fileBytes.data(), fileBytes.size(), outModule); }
	else
	{
		// Make sure the WAST file is null terminated.
		fileBytes.push_back(0);

		// Load it as a text irModule.
		std::vector<WAST::Error> parseErrors;
		if(!WAST::parseModule(
			   (const char*)fileBytes.data(), fileBytes.size(), outModule, parseErrors))
		{
			Log::printf(Log::error, "Error parsing WebAssembly text file:\n");
			reportParseErrors(filename, parseErrors);
			return false;
		}

		return true;
	}
}
Commit message: abuild-sudo: don't allow --keys-dir

Not allowing --allow-untrusted is obviously a good idea, but it can be
trivially bypassed if --keys-dir is allowed:

$ abuild-apk add foo-1-r0.apk
ERROR: foo-1-r0.apk: UNTRUSTED signature
$ abuild-apk --allow-untrusted add foo-1-r0.apk
abuild-apk: --allow-untrusted: not allowed option
$ cp -rp /etc/apk/keys /tmp/keys
$ cp untrusted.pub /tmp/keys
$ abuild-apk --keys-dir /tmp/keys add foo-1-r0.apk
(1/1) Installing foo (1-r0)
OK: 4319 MiB in 806 packages

If both --allow-untrusted and --keys-dir are not allowed, then it should
no longer be possible for an unprivileged member of the abuild group to
add an untrusted package.

$ abuild-apk --keys-dir /tmp/keys add foo-1-r0.apk
abuild-apk: --keys-dir: not allowed option
CVE: CVE-2019-12875
CWE: CWE-264
Vulnerability description: Alpine Linux abuild through 3.4.0 allows an unprivileged member of the abuild group to add an untrusted package via a --keys-dir option that causes acceptance of an untrusted signing key.

Project: abuild

int main(int argc, const char *argv[])
{
	struct group *grent;
	const char *cmd;
	const char *path;
	int i;
	struct passwd *pw;

	grent = getgrnam(ABUILD_GROUP);
	if (grent == NULL)
		errx(1, "%s: Group not found", ABUILD_GROUP);

	char *name = NULL;
	pw = getpwuid(getuid());
	if (pw)
		name = pw->pw_name;

	if (!is_in_group(grent->gr_gid)) {
		errx(1, "User %s is not a member of group %s\n",
			name ? name : "(unknown)", ABUILD_GROUP);
	}

	if (name == NULL)
		warnx("Could not find username for uid %d\n", getuid());
	setenv("USER", name ?: "", 1);

	cmd = strrchr(argv[0], '/');
	if (cmd)
		cmd++;
	else
		cmd = argv[0];
	cmd = strchr(cmd, '-');
	if (cmd == NULL)
		errx(1, "Calling command has no '-'");
	cmd++;

	path = get_command_path(cmd);
	if (path == NULL)
		errx(1, "%s: Not a valid subcommand", cmd);

	/* we dont allow --allow-untrusted option */
	for (i = 1; i < argc; i++)
		if (strcmp(argv[i], "--allow-untrusted") == 0)
			errx(1, "%s: not allowed option", "--allow-untrusted");

	argv[0] = path;
	/* set our uid to root so bbsuid --install works */
	setuid(0);
	/* set our gid to root so apk commit hooks run with the same gid as for "sudo apk add ..." */
	setgid(0);
	execv(path, (char * const*)argv);
	perror(path);
	return 1;
}