Currently, there are not checks if something gets bad during
memory allocation: it will simply use NULL pointers and
crash.

Add error path at the logic which allocates memory for the
MPEG-TS generator code, propagating the errors up to the
vidtv_bridge. Now, if something wents bad, start_streaming
will return an error that userspace can detect:

        ERROR    DMX_SET_PES_FILTER failed (PID = 0x2000): 12 Cannot allocate 
memory

and the driver doesn't crash.

Signed-off-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org>
---
 .../media/test-drivers/vidtv/vidtv_bridge.c   |  2 +
 .../media/test-drivers/vidtv/vidtv_channel.c  | 58 +++++++++++++++++--
 .../media/test-drivers/vidtv/vidtv_channel.h  |  4 +-
 drivers/media/test-drivers/vidtv/vidtv_mux.c  | 55 +++++++++++++-----
 drivers/media/test-drivers/vidtv/vidtv_psi.c  | 40 ++++++++++---
 .../media/test-drivers/vidtv/vidtv_s302m.c    | 14 ++++-
 6 files changed, 143 insertions(+), 30 deletions(-)

diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c 
b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
index fb533c2dd351..b76c1c1ff7c0 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
@@ -181,6 +181,8 @@ static int vidtv_start_streaming(struct vidtv_dvb *dvb)
 
        dvb->streaming = true;
        dvb->mux = vidtv_mux_init(dvb->fe[0], dev, mux_args);
+       if (!dvb->mux)
+               return -ENOMEM;
        vidtv_mux_start_thread(dvb->mux);
 
        dev_dbg_ratelimited(dev, "Started streaming\n");
diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.c 
b/drivers/media/test-drivers/vidtv/vidtv_channel.c
index 28a675a4f367..748697a783a9 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_channel.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_channel.c
@@ -56,43 +56,61 @@ struct vidtv_channel
        const u16 s302m_program_pid         = 0x101; /* packet id for PMT*/
        const u16 s302m_es_pid              = 0x111; /* packet id for the ES */
        const __be32 s302m_fid              = 
cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER);
-
        char *name = ENCODING_ISO8859_15 "Beethoven";
        char *provider = ENCODING_ISO8859_15 "LinuxTV.org";
 
-       struct vidtv_channel *s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
+       struct vidtv_channel *s302m;
        struct vidtv_s302m_encoder_init_args encoder_args = {};
 
+       s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
+       if (!s302m)
+               return NULL;
+
        s302m->name = kstrdup(name, GFP_KERNEL);
+       if (!s302m->name)
+               goto free_s302m;
 
        s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id);
+       if (!s302m->service)
+               goto free_name;
 
        s302m->service->descriptor = (struct vidtv_psi_desc *)
                                     vidtv_psi_service_desc_init(NULL,
                                                                 
DIGITAL_TELEVISION_SERVICE,
                                                                 name,
                                                                 provider);
+       if (!s302m->service->descriptor)
+               goto free_service;
 
        s302m->transport_stream_id = transport_stream_id;
 
        s302m->program = vidtv_psi_pat_program_init(NULL,
                                                    s302m_service_id,
                                                    s302m_program_pid);
+       if (!s302m->program)
+               goto free_service;
 
        s302m->program_num = s302m_program_num;
 
        s302m->streams = vidtv_psi_pmt_stream_init(NULL,
                                                   STREAM_PRIVATE_DATA,
                                                   s302m_es_pid);
+       if (!s302m->streams)
+               goto free_program;
 
        s302m->streams->descriptor = (struct vidtv_psi_desc *)
                                     vidtv_psi_registration_desc_init(NULL,
                                                                      s302m_fid,
                                                                      NULL,
                                                                      0);
+       if (!s302m->streams->descriptor)
+               goto free_streams;
+
        encoder_args.es_pid = s302m_es_pid;
 
        s302m->encoders = vidtv_s302m_encoder_init(encoder_args);
+       if (!s302m->encoders)
+               goto free_streams;
 
        if (head) {
                while (head->next)
@@ -102,6 +120,19 @@ struct vidtv_channel
        }
 
        return s302m;
+
+free_streams:
+       vidtv_psi_pmt_stream_destroy(s302m->streams);
+free_program:
+       vidtv_psi_pat_program_destroy(s302m->program);
+free_service:
+       vidtv_psi_sdt_service_destroy(s302m->service);
+free_name:
+       kfree(s302m->name);
+free_s302m:
+       kfree(s302m);
+
+       return NULL;
 }
 
 static struct vidtv_psi_table_sdt_service
@@ -132,6 +163,8 @@ static struct vidtv_psi_table_sdt_service
                        tail = vidtv_psi_sdt_service_init(tail, service_id);
 
                        desc = vidtv_psi_desc_clone(curr->descriptor);
+                       if (!desc)
+                               return NULL;
                        vidtv_psi_desc_assign(&tail->descriptor, desc);
 
                        if (!head)
@@ -246,17 +279,25 @@ vidtv_channel_pmt_match_sections(struct vidtv_channel 
*channels,
        }
 }
 
-void vidtv_channel_si_init(struct vidtv_mux *m)
+int vidtv_channel_si_init(struct vidtv_mux *m)
 {
        struct vidtv_psi_table_pat_program *programs = NULL;
        struct vidtv_psi_table_sdt_service *services = NULL;
 
        m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id);
+       if (!m->si.pat)
+               return -ENOMEM;
 
        m->si.sdt = vidtv_psi_sdt_table_init(m->transport_stream_id);
+       if (!m->si.sdt)
+               return -ENOMEM;
 
        programs = vidtv_channel_pat_prog_cat_into_new(m);
+       if (!programs)
+               return -ENOMEM;
        services = vidtv_channel_sdt_serv_cat_into_new(m);
+       if (!services)
+               return -ENOMEM;
 
        /* assemble all programs and assign to PAT */
        vidtv_psi_pat_program_assign(m->si.pat, programs);
@@ -265,10 +306,14 @@ void vidtv_channel_si_init(struct vidtv_mux *m)
        vidtv_psi_sdt_service_assign(m->si.sdt, services);
 
        m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, 
m->pcr_pid);
+       if (!m->si.pmt_secs)
+               return -ENOMEM;
 
        vidtv_channel_pmt_match_sections(m->channels,
                                         m->si.pmt_secs,
                                         m->si.pat->programs);
+
+       return 0;
 }
 
 void vidtv_channel_si_destroy(struct vidtv_mux *m)
@@ -285,10 +330,15 @@ void vidtv_channel_si_destroy(struct vidtv_mux *m)
        vidtv_psi_sdt_table_destroy(m->si.sdt);
 }
 
-void vidtv_channels_init(struct vidtv_mux *m)
+int vidtv_channels_init(struct vidtv_mux *m)
 {
        /* this is the place to add new 'channels' for vidtv */
        m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id);
+
+       if (!m->channels)
+               return -ENOMEM;
+
+       return 0;
 }
 
 void vidtv_channels_destroy(struct vidtv_mux *m)
diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.h 
b/drivers/media/test-drivers/vidtv/vidtv_channel.h
index 93a436a27824..d9a0f6fbfd92 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_channel.h
+++ b/drivers/media/test-drivers/vidtv/vidtv_channel.h
@@ -62,14 +62,14 @@ struct vidtv_channel {
  * vidtv_channel_si_init - Init the PSI tables from the channels in the mux
  * @m: The mux containing the channels.
  */
-void vidtv_channel_si_init(struct vidtv_mux *m);
+int vidtv_channel_si_init(struct vidtv_mux *m);
 void vidtv_channel_si_destroy(struct vidtv_mux *m);
 
 /**
  * vidtv_channels_init - Init hardcoded, fake 'channels'.
  * @m: The mux to store the channels into.
  */
-void vidtv_channels_init(struct vidtv_mux *m);
+int vidtv_channels_init(struct vidtv_mux *m);
 struct vidtv_channel
 *vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id);
 void vidtv_channels_destroy(struct vidtv_mux *m);
diff --git a/drivers/media/test-drivers/vidtv/vidtv_mux.c 
b/drivers/media/test-drivers/vidtv/vidtv_mux.c
index b7223f3a2c9d..9086edd45252 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_mux.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_mux.c
@@ -47,33 +47,38 @@ static struct vidtv_mux_pid_ctx
        struct vidtv_mux_pid_ctx *ctx;
 
        ctx = vidtv_mux_get_pid_ctx(m, pid);
-
        if (ctx)
-               goto end;
+               return ctx;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return NULL;
 
-       ctx      = kzalloc(sizeof(*ctx), GFP_KERNEL);
        ctx->pid = pid;
        ctx->cc  = 0;
        hash_add(m->pid_ctx, &ctx->h, pid);
 
-end:
        return ctx;
 }
 
-static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m)
+static int vidtv_mux_pid_ctx_init(struct vidtv_mux *m)
 {
        struct vidtv_psi_table_pat_program *p = m->si.pat->program;
        u16 pid;
 
        hash_init(m->pid_ctx);
        /* push the pcr pid ctx */
-       vidtv_mux_create_pid_ctx_once(m, m->pcr_pid);
-       /* push the null packet pid ctx */
-       vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID);
+       if (!vidtv_mux_create_pid_ctx_once(m, m->pcr_pid))
+               return -ENOMEM;
+       /* push the NULL packet pid ctx */
+       if (!vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID))
+               return -ENOMEM;
        /* push the PAT pid ctx */
-       vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID);
+       if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID))
+               return -ENOMEM;
        /* push the SDT pid ctx */
-       vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID);
+       if (!vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID))
+               return -ENOMEM;
 
        /* add a ctx for all PMT sections */
        while (p) {
@@ -81,6 +86,8 @@ static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m)
                vidtv_mux_create_pid_ctx_once(m, pid);
                p = p->next;
        }
+
+       return 0;
 }
 
 static void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m)
@@ -429,7 +436,11 @@ struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe,
                                 struct device *dev,
                                 struct vidtv_mux_init_args args)
 {
-       struct vidtv_mux *m = kzalloc(sizeof(*m), GFP_KERNEL);
+       struct vidtv_mux *m;
+
+       m = kzalloc(sizeof(*m), GFP_KERNEL);
+       if (!m)
+               return NULL;
 
        m->dev = dev;
        m->fe = fe;
@@ -441,6 +452,9 @@ struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe,
        m->on_new_packets_available_cb = args.on_new_packets_available_cb;
 
        m->mux_buf = vzalloc(args.mux_buf_sz);
+       if (!m->mux_buf)
+               goto free_mux;
+
        m->mux_buf_sz = args.mux_buf_sz;
 
        m->pcr_pid = args.pcr_pid;
@@ -451,16 +465,29 @@ struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe,
        if (args.channels)
                m->channels = args.channels;
        else
-               vidtv_channels_init(m);
+               if (vidtv_channels_init(m) < 0)
+                       goto free_mux_buf;
 
        /* will alloc data for pmt_sections after initializing pat */
-       vidtv_channel_si_init(m);
+       if (vidtv_channel_si_init(m) < 0)
+               goto free_channels;
 
        INIT_WORK(&m->mpeg_thread, vidtv_mux_tick);
 
-       vidtv_mux_pid_ctx_init(m);
+       if (vidtv_mux_pid_ctx_init(m) < 0)
+               goto free_channel_si;
 
        return m;
+
+free_channel_si:
+       vidtv_channel_si_destroy(m);
+free_channels:
+       vidtv_channels_destroy(m);
+free_mux_buf:
+       vfree(m->mux_buf);
+free_mux:
+       kfree(m);
+       return NULL;
 }
 
 void vidtv_mux_destroy(struct vidtv_mux *m)
diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c 
b/drivers/media/test-drivers/vidtv/vidtv_psi.c
index 0e58cbc79fb2..3151b300a91b 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_psi.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c
@@ -325,6 +325,8 @@ struct vidtv_psi_desc_service 
*vidtv_psi_service_desc_init(struct vidtv_psi_desc
        u32 provider_name_len = provider_name ? strlen(provider_name) : 0;
 
        desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+       if (!desc)
+               return NULL;
 
        desc->type = SERVICE_DESCRIPTOR;
 
@@ -364,6 +366,8 @@ struct vidtv_psi_desc_registration
        struct vidtv_psi_desc_registration *desc;
 
        desc = kzalloc(sizeof(*desc) + sizeof(format_id) + additional_info_len, 
GFP_KERNEL);
+       if (!desc)
+               return NULL;
 
        desc->type = REGISTRATION_DESCRIPTOR;
 
@@ -410,11 +414,12 @@ struct vidtv_psi_desc *vidtv_psi_desc_clone(struct 
vidtv_psi_desc *desc)
                default:
                        curr = kzalloc(sizeof(*desc) + desc->length, 
GFP_KERNEL);
                        memcpy(curr, desc, sizeof(*desc) + desc->length);
-               break;
-       }
+               }
 
-               if (curr)
-                       curr->next = NULL;
+               if (!curr)
+                       return NULL;
+
+               curr->next = NULL;
                if (!head)
                        head = curr;
                if (prev)
@@ -693,6 +698,8 @@ vidtv_psi_pat_program_init(struct 
vidtv_psi_table_pat_program *head,
        const u16 RESERVED = 0x07;
 
        program = kzalloc(sizeof(*program), GFP_KERNEL);
+       if (!program)
+               return NULL;
 
        program->service_id = cpu_to_be16(service_id);
 
@@ -754,11 +761,15 @@ vidtv_psi_pat_program_assign(struct vidtv_psi_table_pat 
*pat,
 
 struct vidtv_psi_table_pat *vidtv_psi_pat_table_init(u16 transport_stream_id)
 {
-       struct vidtv_psi_table_pat *pat = kzalloc(sizeof(*pat), GFP_KERNEL);
+       struct vidtv_psi_table_pat *pat;
        const u16 SYNTAX = 0x1;
        const u16 ZERO = 0x0;
        const u16 ONES = 0x03;
 
+       pat = kzalloc(sizeof(*pat), GFP_KERNEL);
+       if (!pat)
+               return NULL;
+
        pat->header.table_id = 0x0;
 
        pat->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ZERO << 14) | 
(ONES << 12));
@@ -858,6 +869,8 @@ vidtv_psi_pmt_stream_init(struct vidtv_psi_table_pmt_stream 
*head,
        u16 desc_loop_len;
 
        stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+       if (!stream)
+               return NULL;
 
        stream->type = stream_type;
 
@@ -932,7 +945,7 @@ u16 vidtv_psi_pmt_get_pid(struct vidtv_psi_table_pmt 
*section,
 struct vidtv_psi_table_pmt *vidtv_psi_pmt_table_init(u16 program_number,
                                                     u16 pcr_pid)
 {
-       struct vidtv_psi_table_pmt *pmt = kzalloc(sizeof(*pmt), GFP_KERNEL);
+       struct vidtv_psi_table_pmt *pmt;
        const u16 SYNTAX = 0x1;
        const u16 ZERO = 0x0;
        const u16 ONES = 0x03;
@@ -940,6 +953,10 @@ struct vidtv_psi_table_pmt *vidtv_psi_pmt_table_init(u16 
program_number,
        const u16 RESERVED2 = 0x0f;
        u16 desc_loop_len;
 
+       pmt = kzalloc(sizeof(*pmt), GFP_KERNEL);
+       if (!pmt)
+               return NULL;
+
        if (!pcr_pid)
                pcr_pid = 0x1fff;
 
@@ -1079,14 +1096,17 @@ void vidtv_psi_pmt_table_destroy(struct 
vidtv_psi_table_pmt *pmt)
 
 struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 transport_stream_id)
 {
-       struct vidtv_psi_table_sdt *sdt = kzalloc(sizeof(*sdt), GFP_KERNEL);
+       struct vidtv_psi_table_sdt *sdt;
        const u16 SYNTAX = 0x1;
        const u16 ONE = 0x1;
        const u16 ONES = 0x03;
        const u16 RESERVED = 0xff;
 
+       sdt  = kzalloc(sizeof(*sdt), GFP_KERNEL);
+       if (!sdt)
+               return NULL;
+
        sdt->header.table_id = 0x42;
-
        sdt->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ONE << 14) | (ONES 
<< 12));
 
        /*
@@ -1219,6 +1239,8 @@ struct vidtv_psi_table_sdt_service
        struct vidtv_psi_table_sdt_service *service;
 
        service = kzalloc(sizeof(*service), GFP_KERNEL);
+       if (!service)
+               return NULL;
 
        /*
         * ETSI 300 468: this is a 16bit field which serves as a label to
@@ -1292,6 +1314,8 @@ vidtv_psi_pmt_create_sec_for_each_pat_entry(struct 
vidtv_psi_table_pat *pat, u16
        pmt_secs = kcalloc(pat->programs,
                           sizeof(struct vidtv_psi_table_pmt *),
                           GFP_KERNEL);
+       if (!pmt_secs)
+               return NULL;
 
        while (program) {
                pmt_secs[i] = 
vidtv_psi_pmt_table_init(be16_to_cpu(program->service_id), pcr_pid);
diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.c 
b/drivers/media/test-drivers/vidtv/vidtv_s302m.c
index 95c5b7bfd491..6e5e72ce90d0 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_s302m.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.c
@@ -144,7 +144,11 @@ static const struct tone_duration beethoven_5th_symphony[] 
= {
 
 static struct vidtv_access_unit *vidtv_s302m_access_unit_init(struct 
vidtv_access_unit *head)
 {
-       struct vidtv_access_unit *au = kzalloc(sizeof(*au), GFP_KERNEL);
+       struct vidtv_access_unit *au;
+
+       au = kzalloc(sizeof(*au), GFP_KERNEL);
+       if (!au)
+               return NULL;
 
        if (head) {
                while (head->next)
@@ -439,9 +443,13 @@ static u32 vidtv_s302m_clear(struct vidtv_encoder *e)
 struct vidtv_encoder
 *vidtv_s302m_encoder_init(struct vidtv_s302m_encoder_init_args args)
 {
-       struct vidtv_encoder *e = kzalloc(sizeof(*e), GFP_KERNEL);
+       struct vidtv_encoder *e;
        u32 priv_sz = sizeof(struct vidtv_s302m_ctx);
 
+       e = kzalloc(sizeof(*e), GFP_KERNEL);
+       if (!e)
+               return NULL;
+
        e->id = S302M;
 
        if (args.name)
@@ -460,6 +468,8 @@ struct vidtv_encoder
 
        e->is_video_encoder = false;
        e->ctx = kzalloc(priv_sz, GFP_KERNEL);
+       if (!e->ctx)
+               return NULL;
 
        e->encode = vidtv_s302m_encode;
        e->clear = vidtv_s302m_clear;
-- 
2.26.2

Reply via email to