Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 51b2e8a3 authored by ChandanaKishori Chiluveru's avatar ChandanaKishori Chiluveru Committed by Tarun Gupta
Browse files

usb: gadget: Fix synchronization issue between f_audio_source



Race is happening when both audio_pcm_close() and audio_send()
executes in parallel.
When the PCM session is closed, the substream attribute of the
audio_dev structure is set to NULL in audio_pcm_close().
As there is no synchronization protection for the audio_dev subtream
attributes in audio_send(), it is causing NULL pointer dereference.
Hence fixing the issue by adding proper synchronization protection
for the audio_dev subtream attributes in audio_send().

CRs-Fixed: 613498
Change-Id: Id9ab0d4e347b8bb2f551f9033829e541bdcaf0e8
Signed-off-by: default avatarChandanaKishori Chiluveru <cchilu@codeaurora.org>
Signed-off-by: default avatarTarun Gupta <tarung@codeaurora.org>
parent 48a4b550
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -365,15 +365,22 @@ static void audio_send(struct audio_dev *audio)
	s64 msecs;
	s64 frames;
	ktime_t now;
	unsigned long flags;

	spin_lock_irqsave(&audio->lock, flags);
	/* audio->substream will be null if we have been closed */
	if (!audio->substream)
	if (!audio->substream) {
		spin_unlock_irqrestore(&audio->lock, flags);
		return;
	}
	/* audio->buffer_pos will be null if we have been stopped */
	if (!audio->buffer_pos)
	if (!audio->buffer_pos) {
		spin_unlock_irqrestore(&audio->lock, flags);
		return;
	}

	runtime = audio->substream->runtime;
	spin_unlock_irqrestore(&audio->lock, flags);

	/* compute number of frames to send */
	now = ktime_get();
@@ -397,8 +404,21 @@ static void audio_send(struct audio_dev *audio)

	while (frames > 0) {
		req = audio_req_get(audio);
		if (!req)
		spin_lock_irqsave(&audio->lock, flags);
		/* audio->substream will be null if we have been closed */
		if (!audio->substream) {
			spin_unlock_irqrestore(&audio->lock, flags);
			return;
		}
		/* audio->buffer_pos will be null if we have been stopped */
		if (!audio->buffer_pos) {
			spin_unlock_irqrestore(&audio->lock, flags);
			return;
		}
		if (!req) {
			spin_unlock_irqrestore(&audio->lock, flags);
			break;
		}

		length = frames_to_bytes(runtime, frames);
		if (length > IN_EP_MAX_PACKET_SIZE)
@@ -424,6 +444,7 @@ static void audio_send(struct audio_dev *audio)
		}

		req->length = length;
		spin_unlock_irqrestore(&audio->lock, flags);
		ret = usb_ep_queue(audio->in_ep, req, GFP_ATOMIC);
		if (ret < 0) {
			pr_err("usb_ep_queue failed ret: %d\n", ret);